reparto - Detectar el final del cuerpo de solicitud HTTP
el cuerpo del deseo telenovela completa descargar (6)
Agrego otra respuesta principalmente porque no tengo suficiente representante para comentar en mgiuca . Sé que la pregunta es un poco antigua, pero no se ha logrado una respuesta definitiva.
Como se mencionó, lo más importante a tener en cuenta es que su servidor interactúa con otros incontrolables , lo que significa que no puede saber lo que enviarán en absoluto , y debe estar preparado para administrar todo lo que ingrese a través de esa puerta. Teniendo esto en cuenta, apegarse a las normas y prácticas comunes es probablemente la mejor opción.
Si el cliente envía un encabezado "Content-Length", el servidor debe analizarlo y usarlo para determinar el final de la solicitud. Si no existía dicho encabezado pero estaba presente el encabezado "Transfer-Encoding: chunked", el servidor debe poder analizar una solicitud fragmentada ( enlace de la respuesta de mgiuca ). Finalmente, si ninguno está presente, "el final de la conexión" señala el final de la solicitud.
Lo que creo que se pasó por alto es el hecho de que el cliente puede finalizar la conexión y aún obtener una respuesta del servidor. Quiero decir, ¿qué significa "terminar la conexión"? Recuerde que HTTP es un protocolo de capa de aplicación que viaja (generalmente) a través de TCP. Explorar la funcionalidad de TCP (particularmente su protocolo de terminación de conexión ) revela información interesante:
- Para finalizar de forma activa una conexión, el cliente envía un paquete con la bandera FIN , parte de un saludo de cuatro vías. La conexión todavía se considera abierta porque el protocolo de terminación aún no ha finalizado.
- El servidor recibe este paquete e informa al cliente (paquete ACK ). El servidor ahora sabe que el cliente no transmitirá más datos.
- El cliente va a un estado FIN_WAIT2 , esperando un paquete con el indicador FIN del servidor para cerrar correctamente la conexión.
¡Pero ahí está! El cliente ha informado que quiere finalizar la conexión, y el servidor lo sabe, pero la conexión todavía está abierta por parte del cliente (no la cerró porque no recibió el paquete FIN ). El servidor ahora responde la solicitud y luego cierra la conexión correctamente. Es importante tener en cuenta que el cliente ACK cada paquete de servidor con una bandera RST adicional, diciéndole al servidor que todavía está esperando que FIN cierre la conexión.
Cuando el servidor finaliza (en nuestro pequeño ejemplo, después de enviar la Respuesta HTTP) cierra la conexión de su lado, enviando el paquete FIN . El cliente cierra su lado cuando lo recibe y notifica al servidor con un ACK .
En una nota adicional, no conozco el contexto en el que está programando, pero la mayoría de las veces terminará llamando a shutdown () en un socket. El cierre de POSIX (y Windows'' al menos) toma la interfaz de la conexión que desea cerrar como argumento de función. Estas especificaciones dejan en claro que puede cerrar la parte del remitente (que es exactamente lo que hará el cliente), deshabilitando el envío de datos mientras permite que el cliente reciba más datos.
Más detalles sobre las conexiones TCP van más allá del alcance de esta pregunta, pero recomendaría leer sobre ello para obtener una mejor comprensión de los protocolos de las capas superiores que lo utilizan.
Estoy jugando con la escritura de mi propio cliente y servidor HTTP y quiero que el cliente incluya un cuerpo opcional en la solicitud. En el lado del servidor, quiero leer todo el cuerpo antes de enviar la respuesta HTTP. Mi pregunta es en el servidor ¿cómo sé que he leído todo el cuerpo?
Aunque en este caso yo controlo tanto al cliente como al servidor, estoy buscando un enfoque "estándar". Sin embargo, dado que Content-Length es opcional, quiero un método que no lo requiera. Si el cliente cierra la conexión, es fácil leer todos los datos disponibles, sin embargo, el cliente necesita mantener la conexión abierta para esperar una respuesta, por lo que este método no funciona.
Todo lo que puedo pensar que me queda es tener conocimiento del formato del cuerpo y detectar un terminador (por ejemplo, </HTML>
). Idealmente, no quiero exigir ese conocimiento.
¿Hay un enfoque que estoy pasando por alto?
Creo que te estás deteniendo de usar la opción más obvia cuando dices "Content-Length is optional".
De las especificaciones HTTP en http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
Las aplicaciones DEBEN usar este campo para indicar la longitud de transferencia del cuerpo del mensaje, a menos que esto esté prohibido por las reglas de la sección 4.4.
Si conoce la longitud, y parece que lo hará, especifíquela en el encabezado Content-Length y termine con ella, ya que la especificación básicamente le ruega que lo haga (suponiendo que nada más infringe las reglas mencionadas en rfc ).
Esta:
http://greenbytes.de/tech/webdav/rfc7230.html#message.body.length
se supone que es la respuesta autorizada (y no, no se requiere conocimiento del formato de la carga útil)
Suponiendo que desea que su cliente trabaje con otros servidores y que el servidor trabaje con otros clientes, su servidor no puede esperar que lo traten bien.
Hay dos formas de saber cuándo el cuerpo ha terminado. Ninguno de los dos requiere conocimiento del tipo de contenido del cuerpo como usted sugiere (p. Ej., No se moleste en buscar </html>
- que vaya más allá del protocolo HTTP).
- Si el cliente envía un mensaje con
Transfer-Encoding: Chunked
, necesitará analizar la sintaxis de codificación de transferencia fragmentada algo complicada. Realmente no tiene muchas opciones en el asunto: si el cliente está enviando en este formato, debe recibirlo. Cuando el cliente usa este enfoque, puede detectar el final del cuerpo en un trozo con una longitud de 0. - Si el cliente en su lugar envía una
Content-Length
, debe usar eso.
Como sugiere, el tercer método para detectar el final, cuando se cierra la conexión, solo funciona para la respuesta, no para la solicitud (ya que entonces no hay forma de enviar una respuesta).
La manera más fácil: use HTTP 1.0 y requiera la longitud del contenido
Para compatibilidad con las aplicaciones HTTP / 1.0, las solicitudes HTTP / 1.1 que contienen un cuerpo del mensaje DEBEN incluir un campo de encabezado Content-Length válido a menos que se sepa que el servidor es compatible con HTTP / 1.1. Si una solicitud contiene un cuerpo de mensaje y no se proporciona una longitud de contenido, el servidor DEBE responder con 400 (solicitud incorrecta) si no puede determinar la longitud del mensaje, o con 411 (longitud requerida) si desea insistir en recibiendo una longitud de contenido válida.
If a request contains a message-body and a Content-Length is not given,
the server SHOULD respond with 400 (bad request) if it cannot determine
the length of the message, or with 411 (length required) if it wishes
to insist on receiving a valid Content-Length.
es decir, tiene derecho a insistir en Transfer-Encoding: chunked
o Content-Length
, para que no tenga que preocuparse por determinar la duración en cualquier otra situación