2010-06-03 4 views
25

Sto scrivendo un server HTTP semplicistico che accetterà richieste PUT principalmente da cURL come client e sto avendo un po 'di problemi con la gestione dell'intestazione Expect: 100-continue.Come gestire il messaggio HTTP "100 continue"?

Da quanto ho capito, si suppone al server di leggere l'intestazione, inviare una risposta HTTP/1.1 100 Continue sulla connessione, leggere il flusso fino al valore su Content-Length e quindi inviare di nuovo il codice di risposta reale (Di solito HTTP/1.1 200 OK ma qualsiasi altro la risposta HTTP valida dovrebbe fare).

Bene, questo è esattamente ciò che fa il mio server. Il problema è che, apparentemente, se invio una risposta 100 Continue, cURL non riesce a segnalare alcun successivo codice di errore HTTP e presume che il caricamento sia stato un successo. Ad esempio, se il caricamento viene rifiutato a causa della natura del contenuto (si verifica un controllo dei dati di base), voglio che il client chiamante rilevi il problema e agisca di conseguenza.

Mi manca qualcosa di ovvio?

edit: ecco un esempio di output da cURL con un colpo di testa secondaria contenente un errore:

> PUT /test1%2Epdf HTTP/1.1 
> Authorization: Basic xxxx 
> User-Agent: curl/7.20.0 (i386-pc-win32) libcurl/7.20.0 OpenSSL/0.9.8l zlib/1.2.3 
> Host: localhost 
> Accept: */* 
> Content-Length: 24 
> Expect: 100-continue 
> 
< HTTP/1.1 100 Continue 
< HTTP/1.1 415 Unsupported Media Type 
< Connection: close 
< Content-Type: text/xml 
< Content-Length: 289 
< 
+0

è che non è necessario riga vuota dopo 'HTTP/1.1 100 CONTINUE? – YOU

+1

Ce n'è uno. Il fatto che non venga registrato sembra essere un problema di visualizzazione con cURL. – Stephane

+0

Giusto per chiarire, inviare una risposta HTTP completamente valida ('HTTP/1.1 100 Continue \ r \ n \ r \ n') non semplicemente la stringa' "HTTP/1.1 100 Continua" '. Il client cURL attenderà fino a quando non riceverà queste due sequenze e se si arrenderà, produrrà (in modalità dettagliata) il messaggio "Fatto aspettare 100-continua". – bishop

risposta

9

se si utilizza libcurl per scrivere il programma sul lato client, assicurarsi di impostare l'opzione CURLOPT_FAILONERROR a 1. Ad esempio, in C, si potrebbe fare qualcosa di simile:

curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1L); 

Secondo il libcurl documentation, questa opzione "dice la libreria a fallire in silenzio se il codice HTTP restituito è uguale o superiore a 400."

Inoltre, la documentazione chiarisce che "l'azione predefinita sarebbe quella di restituire normalmente la pagina, ignorando quel codice".

Se si utilizza lo strumento da riga di comando di arricciatura, è sufficiente aggiungere -f o --fail al comando di arricciamento per provocare un comportamento simile a quello descritto in precedenza. Questo è anche descritto nel ricciolo man page.

Si noti che entrambi questi metodi non sono fail-safe, come è chiaramente indicato nella documentazione:

"This method is not fail-safe and there are occasions where non-successful response codes will slip through, especially when authentication is involved (response codes 401 and 407)."

+0

Sto usando lo strumento da riga di comando ma il flag -f non sembra influenzare il comportamento dello strumento. Da allora mi sono deciso per scrivere il mio cliente che gestisce correttamente questo caricamento fallito. Grazie per la risposta, anche se – Stephane

6

In realtà ci dovrebbe essere vero e proprio colpo di testa dopo 100 continua intestazione

Quindi, faccio di solito come questo su dalla parte del cliente.

$contents=curl_exec($ch); 

list($header, $contents) = explode("\r\n\r\n", $contents , 2); 
if(strpos($header," 100 Continue")!==false){ 
    list($header, $contents) = explode("\r\n\r\n", $contents , 2); 
} 
+0

Bene, invio una vera intestazione dopo la risposta al codice 100. Sembra che a CURL non importi, però. – Stephane

3

Prova ad aggiungere una riga vuota (CRLF) dopo il 100 Continuare la linea (vedi RFC 2616, Section 6),

+0

Sembra che la linea mancante sia un bug. Ho controllato il codice e c'è una riga vuota dopo il "100 continua" – Stephane

19

So che questo è vecchio, ma qui è la mia comprensione di "100 Continua"

Il server deve convalidare la richiesta in base all'intestazione da solo dal client, ovvero se la richiesta non è valida, non inviare "100 Continua", ma invece l'errore HTTP effettivo es. 403. Ciò dovrebbe impedire al cliente di pubblicare i dati che capisco sia l'intero punto di andata e ritorno al server (ad esempio, il client che aspetta "100 Continua") in primo luogo.

Se si stanno convalidando i dati effettivi registrati, è necessario applicare il protocollo di livello superiore qui, ad es.invia il tuo errore racchiuso in un contenuto di risposta HTTP valido. Sì, sembra una limitazione e non sto assumendo che sia la limitazione del protocollo; più probabile confusione del client che deve gestire la risposta del server più di una volta.

+3

Grazie per la risposta. Hai ragione: è una vecchia domanda, ma la trovi abbastanza corretta. il mio vero problema è che, beh, "100" non è un codice di errore di successo: il client dovrebbe sempre controllare il codice di ritorno contenuto nella risposta effettiva. Apparentemente, non è quello che sta facendo CURL. – Stephane

+0

"Questo dovrebbe impedire al client di pubblicare i dati" - questa è probabilmente la parte più fraintesa della RFC di sempre. La mancanza di 100-Continue non impedisce al client di continuare, RFC afferma esplicitamente che il client può continuare a inviare il corpo della richiesta. In realtà l'unico modo valido di gestire una risposta è l'invio del corpo o la disconnessione. –

+0

Ulteriori informazioni utili su questo fraintendimento da parte di curl/web server se le persone sono interessate alla mailing list del ricciolo: [Altro su POST e PUT con 100-continue] (https://curl.haxx.se/mail/lib-2004- 08/0002.html) – paperclip

4

Elaborando risposta di te, e ancora utilizzando PHP come un esempio:

E 'possibile che più 100 Continue intestazioni potrebbero essere ricevuti. Io uso il seguente a lavorare lentamente attraverso le intestazioni e rimuovere ciascuna delle 100 Continue risposte se esistenti:

<?php 
// a little setup first 
$ch = curl_init(); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); 
curl_setopt($ch,CURLOPT_HEADER,1); 
// etc... 
$str = curl_exec($ch); 

// the goods 
$delimiter = "\r\n\r\n"; // HTTP header delimiter 
// check if the 100 Continue header exists 
while (preg_match('#^HTTP/[0-9\\.]+\s+100\s+Continue#i',$str)) { 
    $tmp = explode($delimiter,$str,2); // grab the 100 Continue header 
    $str = $tmp[1]; // update the response, purging the most recent 100 Continue header 
} // repeat 

// now we just have the normal header and the body 
$parts = explode($delimiter,$str,2); 
$header = $parts[0]; 
$body = $parts[1]; 
?> 
+0

Mi ha salvato, grazie! – Aidin