¿Cómo manejar el mensaje HTTP" 100 continue"?


Estoy escribiendo un servidor HTTP simplista que aceptará solicitudes PUT principalmente de cURL como cliente y estoy teniendo un pequeño problema con el manejo del encabezado Expect: 100-continue.

Según lo entiendo, se supone que el servidor debe leer el encabezado, devolver una respuesta HTTP/1.1 100 Continue en la conexión, leer la secuencia hasta el valor en Content-Length y luego devolver el código de respuesta real (Generalmente HTTP/1.1 200 OK pero cualquier otra respuesta HTTP válida debería hacerlo).

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

¿Me estoy perdiendo algo obvio ?

Editar: aquí hay una salida de muestra de cURL con un encabezado secundario 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
<
Author: Benjamin, 2010-06-03

5 answers

Si está utilizando libcURL para escribir su programa del lado del cliente, asegúrese de establecer la opción CURLOPT_FAILONERROR en 1. Por ejemplo, en C, harías algo como:

curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1L);

De acuerdo con la documentación de libcURL , esta opción "le dice a la biblioteca que falle silenciosamente si el código HTTP devuelto es igual o mayor que 400."

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

Si usted es usando la herramienta de línea de comandos curl, simplemente agregando -f o --fail en su comando curl causará un comportamiento similar al descrito anteriormente. Esto también se describe en la página man de curl .

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

" Este método no es a prueba de fallos y hay ocasiones en las que los códigos de respuesta no exitosos se deslizarán, especialmente cuando la autenticación está involucrada (códigos de respuesta 401 y 407)."

 9
Author: bloosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-31 15:09:34

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

Se supone que su servidor debe validar la solicitud basándose solo en el encabezado del cliente, es decir, si la solicitud no es válida, no envíe "100 Continue" sino un error http real, por ejemplo, 403. Esto debería evitar que el cliente publique los datos que entiendo que son el punto de ida y vuelta al servidor (es decir, el cliente esperando "100 Continuar") en primer lugar.

Si está validando actual datos publicados, luego debe aplicar un protocolo de nivel superior aquí, es decir, enviar su error envuelto en 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.

 20
Author: bronekk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-16 12:33:46

En realidad debe haber encabezado real después de 100 Continuar encabezado

Por lo tanto, normalmente me gusta esto en el 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);
}
 6
Author: YOU,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-03 09:37:09

Desarrollando SU respuesta, y aún usando PHP como ejemplo:

Es posible que se reciban múltiples encabezados 100 Continue. Utilizo lo siguiente para trabajar lentamente a través de los encabezados y eliminar 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];
?>
 4
Author: zamnuts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-26 08:03:53

Intente agregar una línea vacía (CRLF) después de la línea continua 100 (ver RFC 2616, Sección 6),

 3
Author: Julian Reschke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-03 10:04:21