2010-06-03 4 views
25

J'écris un serveur HTTP simpliste qui acceptera les requêtes PUT principalement de cURL en tant que client et j'ai un peu de problème avec la gestion de l'en-tête Expect: 100-continue.Comment gérer le message HTTP "100 continuer"?

Si je comprends bien, le serveur est censé lire l'en-tête, renvoyer une réponse HTTP/1.1 100 Continue sur la connexion, lire le flux jusqu'à la valeur sur Content-Length puis renvoyer le code de réponse réelle (généralement HTTP/1.1 200 OK mais tout autre réponse HTTP valide devrait faire).

Eh bien, c'est exactement ce que fait mon serveur. Le problème est que, apparemment, si j'envoie une réponse 100 Continue, cURL ne signale aucun code d'erreur HTTP suivant et suppose que le téléchargement a réussi. Par exemple, si le téléchargement est rejeté en raison de la nature du contenu (une vérification des données de base est en cours), je souhaite que le client appelant détecte le problème et agisse en conséquence.

Est-ce que quelque chose me manque?

edit: voici un exemple de sortie de cURL avec un en-tête secondaire contenant une erreur:

> 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

ne vous besoin ligne vide après 'HTTP/1.1 100 CONTINUE? – YOU

+1

Il y en a un. Le fait qu'il ne soit pas enregistré semble être un problème d'affichage avec cURL. – Stephane

+0

Juste pour clarifier, renvoyez une réponse HTTP complètement valide ('HTTP/1.1 100 Continue \ r \ n \ r \ n') et pas simplement la chaîne' "HTTP/1.1 100 Continue" '. Le client cURL attendra jusqu'à ce qu'il reçoive les deux séquences , et s'il abandonne, il affichera (en mode verbeux) le message "Fait attendre 100-continuer". – bishop

Répondre

9

Si vous utilisez libcURL pour écrire votre programme côté client, assurez-vous que vous définissez l'option CURLOPT_FAILONERROR à 1. Par exemple, en C, vous feriez quelque chose comme:

curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1L); 

Selon le libcURL documentation, cette option « indique la bibliothèque silencieusement les codes HTTP est égale ou supérieure à 400. »

En outre, la documentation indique clairement que "l'action par défaut serait de retourner la page normalement, en ignorant ce code."

Si vous utilisez l'outil de ligne de commande curl, ajouter simplement -f ou --fail dans votre commande curl provoquera un comportement similaire à celui décrit ci-dessus. Ceci est également décrit dans le curl man page.

Notez que ces deux méthodes ne sont pas des défaillances, comme cela est clairement indiqué dans la documentation:

"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

J'utilise l'outil de ligne de commande mais l'indicateur -f ne semble pas affecter le comportement de l'outil. Depuis, je me suis contenté d'écrire mon propre client qui gère correctement ces téléchargements échoués. Merci pour la réponse, bien que – Stephane

6

En fait, il devrait y avoir en-tête réel après 100 Continuer tête

Alors, je fais d'habitude comme celui-ci sur côté client.

$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

Eh bien, j'envoie un vrai en-tête après le code 100 réponse. Il semble que cURL ne s'en soucie pas, cependant. – Stephane

3

Essayez d'ajouter une ligne vide (CRLF) après la ligne 100 Continuer (voir RFC 2616, Section 6),

+0

Il semble que la ligne manquante soit un bug. J'ai vérifié le code et il y a une ligne vide après le "100 continue" – Stephane

19

Je sais que c'est vieux, mais voici ma compréhension de « 100 Continuer »

Votre serveur est supposé valider la requête en fonction de l'en-tête du client, c'est-à-dire si la requête est invalide, ne pas envoyer "100 Continue" mais erreur http réelle à la place par exemple 403. Cela devrait empêcher le client d'afficher les données qui, d'après ce que je comprends, constituent le point de départ total du serveur (c'est-à-dire le client qui attend «100 Continue») en premier lieu.

Si vous validez des données réelles publiées, vous devez appliquer un protocole de niveau supérieur ici, c'est-à-direenvoyez votre erreur enveloppée dans un contenu de réponse HTTP valide. Oui, cela semble être une limitation et je ne suppose pas que c'est une limitation de protocole; la confusion du client est plus susceptible de devoir gérer la réponse du serveur plus d'une fois.

+3

Merci pour la réponse. Vous avez raison: c'est une vieille question mais vous l'avez à peu près correcte. mon vrai problème est que, bien, "100" n'est pas un code d'erreur de succès: le client devrait toujours vérifier le code de retour contenu dans la réponse réelle. Apparemment, ce n'est pas ce que fait cURL. – Stephane

+0

"Cela devrait empêcher le client d'afficher les données" - c'est probablement la partie la plus mal comprise de la RFC. Le manque de 100-Continue n'empêche pas le client de continuer, RFC indique explicitement que le client peut continuer à envoyer le corps de la demande. En fait, la seule manière valable de gérer une réponse est d'envoyer le corps ou de se déconnecter. –

+0

Informations supplémentaires utiles sur ce malentendu par les serveurs curl/web si les gens sont intéressés par la liste de diffusion Curl: [Plus sur POST et PUT avec 100-continuer] (https://curl.haxx.se/mail/lib-2004- 08/0002.html) – paperclip

4

Élaborant sur la réponse de vous, et toujours en utilisant PHP comme exemple:

Il est possible que plusieurs têtes 100 Continue pourraient être reçues. J'utilise ce qui suit pour travailler lentement à travers les en-têtes et enlever chacune des réponses 100 Continue si elles existent:

<?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

Il m'a sauvé, merci! – Aidin

Questions connexes