web-dev-qa-db-fra.com

Comment gérer le message HTTP "100 continue"?

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 mal à gérer le Expect: 100-continue entête.

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

Eh bien, c'est exactement ce que fait mon serveur. Le problème est que, apparemment, si j'envoie un 100 Continue réponse, cURL ne signale aucun code d'erreur HTTP ultérieur 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 (il y a une vérification de base des données), je veux que le client appelant détecte le problème et agisse en conséquence.

Suis-je en train de manquer quelque chose d'évident?

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
<
30
Stephane

Si vous utilisez libcURL pour écrire votre programme côté client, assurez-vous de définir le CURLOPT_FAILONERROR option pour 1. Par exemple, en C, vous feriez quelque chose comme:

curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1L);

Selon la libcURL documentation , cette option "indique à la bibliothèque d'échouer silencieusement si le code HTTP retourné est égal ou supérieur à 400".

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

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

Notez que ces deux méthodes ne sont pas à sécurité intrinsèque, comme cela est clairement indiqué dans la documentation:

"Cette méthode n'est pas à sécurité intrinsèque et il y a des occasions où les codes de réponse non réussis se faufilent, en particulier lorsque l'authentification est impliquée (codes de réponse 401 et 407)."

12
bloosh

Je sais que c'est vieux, mais voici ma compréhension de "100 Continue"

Votre serveur est censé valider la demande en se basant uniquement sur l'en-tête du client, c'est-à-dire si la demande n'est pas valide, ne pas envoyer "100 Continuer" mais une véritable erreur http à la place, par ex. 403. Cela devrait empêcher le client de publier les données qui, à mon avis, constituent tout l'intérêt d'un aller-retour vers le serveur (c'est-à-dire le client en attente de "100 Continuer") en premier lieu.

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

23
bronekk

En fait, il devrait y avoir un véritable en-tête après 100 Continuer l'en-tête

Donc, j'aime normalement ça 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);
}
6
YOU

En élaborant la réponse de VOUS et en utilisant toujours PHP comme exemple:

Il est possible que plusieurs 100 Continue des en-têtes ont pu être reçus. J'utilise ce qui suit pour parcourir lentement les en-têtes et supprimer chacun des 100 Continue réponses 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];
?>
4
zamnuts

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

3
Julian Reschke