2010-06-03 30 views
25

Estoy escribiendo un servidor HTTP simplista que aceptará solicitudes PUT principalmente de cURL como cliente y estoy teniendo un problema con el manejo del encabezado Expect: 100-continue.¿Cómo manejar el mensaje HTTP "100 continue"?

Según tengo entendido, el servidor se supone que leer el encabezado, enviar de vuelta una respuesta HTTP/1.1 100 Continue en la conexión, lea la corriente hasta el valor de Content-Length y después devuelven el código de respuesta real (Por lo general HTTP/1.1 200 OK pero cualquier otro una respuesta HTTP válida debería hacer).

Bueno, eso es exactamente lo que hace mi servidor. El problema es que, aparentemente, si envío una respuesta 100 Continue, cURL no informa ningún código de error HTTP posterior y asume que la carga fue un éxito. Por ejemplo, si se rechaza la carga debido a la naturaleza del contenido (hay una verificación de datos básicos), quiero que el cliente llamante detecte el problema y actúe en consecuencia.

¿Me falta algo obvio?

edición: aquí es un ejemplo de salida de Rizos y una cabecera secundaria que contiene un error:

> 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

¿No se necesita línea en blanco después de 'HTTP/1.1 100 Continue'? – YOU

+1

Hay uno. El hecho de que no se esté registrando parece ser un problema de visualización con cURL. – Stephane

+0

Solo para aclarar, envíe una respuesta HTTP completamente válida ('HTTP/1.1 100 Continue \ r \ n \ r \ n') no simplemente la cadena' "HTTP/1.1 100 Continue''. El cliente cURL esperará hasta que reciba esas dos secuencias , y si se da por vencido, emitirá (en modo detallado) el mensaje "Hecho esperando 100-continuar". – bishop

Respuesta

9

Si está utilizando libcurl a escribir el programa del lado del cliente, asegúrese de configurar la opción CURLOPT_FAILONERROR a 1. Por ejemplo, en C, que haría algo como:

curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1L); 

De acuerdo con la libcurl documentation, esta opción "cuenta la biblioteca a fallar en silencio si el código HTTP devuelto es igual o mayor que 400."

Además, la documentación deja en claro que "la acción predeterminada sería devolver la página normalmente, ignorando ese código".

Si está utilizando la herramienta de línea de comando Curl, simplemente agregando -f o en su comando curl provocará un comportamiento similar al descrito anteriormente. Esto también se describe en el curl man page.

Tenga en cuenta que estos dos métodos no son a prueba de fallos, como se indica claramente en los documentos:

"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

Estoy usando la herramienta de línea de comandos, pero el indicador -f no parece afectar el comportamiento de la herramienta. Desde entonces, me conformé con escribir mi propio cliente que maneja correctamente esta carga fallida. Gracias por la respuesta, aunque – Stephane

6

En realidad no debería ser real Remate de cabeza de 100 Continuar cabecera

Por lo tanto, hago normalmente como este en lado 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

Bueno, envié un encabezado real después de la respuesta del código 100. Parece que a cURL no le importa, sin embargo. – Stephane

3

Trate de añadir una línea vacía (CRLF) después de que el 100 continuar la línea (ver RFC 2616, Section 6),

+0

Parece que la línea que falta es un error. He comprobado el código y hay una línea vacía después de "100 continue" – Stephane

19

Sé que esto es viejo, pero aquí está mi comprensión de "100 continuar"

Se supone que su servidor valida la solicitud basada únicamente en el encabezado del cliente, es decir, si la solicitud no es válida, no envíe "100 Continue" sino error http real, por ejemplo, 403. Esto debería evitar que el cliente publique los datos que entiendo que es el punto de ida y vuelta al servidor (es decir, cliente que espera "100 Continue") en primer lugar.

Si está validando los datos reales publicados, entonces debe aplicar el protocolo de nivel superior aquí, es decirenvíe su error envuelto en un contenido de respuesta HTTP válido. Sí, parece una limitación y no estoy asumiendo que sea una limitación de protocolo; es más probable que la confusión del cliente tenga que manejar la respuesta del servidor más de una vez.

+3

Gracias por la respuesta. Tienes razón: es una vieja pregunta, pero la obtienes bastante correcta. mi verdadero problema es que, bueno, "100" no es un código de error de éxito: el cliente siempre debe verificar el código de retorno que figura en la respuesta real. Aparentemente, eso no es lo que está haciendo cURL. – Stephane

+0

"Esto debería evitar que el cliente publique los datos", esta es probablemente la parte más incomprendida del RFC. La falta de 100-Continuar no impide que el cliente continúe; RFC establece explícitamente que el cliente puede continuar enviando el cuerpo de la solicitud. En realidad, la única forma válida de manejar una respuesta es enviando el cuerpo o desconectándolo. –

+0

Información adicional útil sobre este malentendido de los servidores curl/web si las personas están interesadas en la lista de correo curl: [Más sobre POST y PUT con 100-continue] (https://curl.haxx.se/mail/lib-2004- 08/0002.html) – paperclip

4

Abundando en respuesta eres tú, y todavía se usa PHP como un ejemplo:

Es posible que múltiples 100 Continue cabeceras se podían recibir. Yo uso el siguiente para trabajar lentamente a través de las cabeceras y quitar cada una de las respuestas 100 Continue si existen:

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

¡Me salvó, gracias! – Aidin

Cuestiones relacionadas