Обнаружить конец тела запроса HTTP

Я играю с написанием собственного HTTP-клиента и сервера и хочу, чтобы клиент включил в запрос необязательный элемент. На стороне сервера я хочу прочитать все тело перед отправкой ответа HTTP. Мой вопрос на сервере, как я знаю, что я прочитал все тело?

Хотя в этом случае я управляю как клиентом, так и сервером, я ищу "стандартный" подход. Однако, поскольку Content-Length является необязательным, я хочу метод, который этого не требует. Если клиент закрывает соединение, легко прочитать все доступные данные, однако клиент должен поддерживать соединение открытым, чтобы ждать ответа, поэтому этот метод не работает.

Все, что я могу думать, что мне осталось, - это знание формата тела и обнаружение терминатора (например, </HTML>). В идеале я не хочу требовать этого знания.

Есть ли подход, который я пропускаю?

Ответ 1

Предполагая, что вы хотите, чтобы ваш клиент работал с другими серверами, а сервер работал с другими клиентами, ваш сервер не может ожидать, что вас будут рассматривать красиво.

Есть два способа сказать, когда тело закончилось. Ни один из них не требует знания типа содержимого тела, как вы предлагаете (например, не беспокойтесь о поиске </html>), который выходит далеко за пределы протокола HTTP).

  • Если клиент отправляет сообщение с Transfer-Encoding: Chunked, вам нужно будет проанализировать несколько сложный chunked синтаксис кодирования передачи. У вас нет большого выбора в этом вопросе - если клиент отправляет этот формат, вы должны его получить. Когда клиент использует этот подход, вы можете обнаружить конец тела куском с длиной 0.
  • Если клиент вместо этого отправляет Content-Length, вы должны использовать это.

Как вы полагаете, третий метод обнаружения конца - когда соединение закрывается - работает только для ответа, а не запроса (так как тогда нет способа отправить ответ).

Ответ 2

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.

то есть. вы имеете право настаивать на Transfer-Encoding: chunked или Content-Length, поэтому вам не нужно беспокоиться об определении длины в любой другой ситуации.

Ответ 3

Я добавляю еще один ответ в основном потому, что у меня недостаточно комментариев, чтобы прокомментировать mgiuca. Я знаю, что вопрос старый, но никакого определенного ответа не было.

Как уже упоминалось, главное, чтобы учесть, что ваш сервер взаимодействует с неконтролируемыми другими, то есть вы не можете знать, что они будут отправлять вообще, и должны быть готовы управлять тем, что приходит через эти ворота. Принимая это во внимание, придерживаясь стандартов и общих практик, вероятно, лучший выбор.

Если клиент отправляет заголовок "Content-Length", сервер должен проанализировать его и использовать для определения конца запроса. Если такого заголовка не было, но заголовок "Transfer-Encoding: chunked" присутствовал, тогда сервер должен иметь возможность анализировать запрошенный запрос (link от ответа mgiuca). Наконец, если ни один из них не присутствует, "конец соединения" сигнализирует о завершении запроса.

Я думаю, что вы упустили из виду тот факт, что клиент может завершить соединение и получить ответ от сервера. Я имею в виду, что означает "прекратить соединение"? Помните, что HTTP - это протокол уровня приложения, который перемещается (обычно) через TCP. Изучение функциональности TCP (в частности, протокол Закрытие POSIXWindows ', по крайней мере), какой интерфейс соединения, которое вы хотите закрыть как аргумент функции. В этих спецификациях четко указано, что вы можете просто закрыть часть отправителя (именно это будет делать клиент), отключив передачу данных, позволяя клиенту получать дополнительные данные.

Дополнительная информация о TCP Connections выходит за рамки этого вопроса, но я бы рекомендовал прочитать об этом, чтобы лучше понять протоколы более высоких уровней, которые его используют.

Ответ 4

rfc

Простой способ: использовать HTTP 1.0 и требовать длину содержимого

Для совместимости с приложениями HTTP/1.0 запросы HTTP/1.1, содержащие тело сообщения, ДОЛЖНЫ включать допустимое поле заголовка Content-Length, если только сервер не известен как HTTP/1.1. Если запрос содержит тело сообщения, а Content-Length не указывается, сервер ДОЛЖЕН ответить 400 (неверный запрос), если он не может определить длину сообщения или 411 (требуется длина), если он хочет настаивать на получая действительный Content-Length.

Ответ 5

Я думаю, что вы перестаете использовать самый очевидный выбор, когда говорите "Content-Length является необязательным".

Из спецификации HTTP в http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13

Приложения СЛЕДУЕТ использовать это поле для указать длину передачи тело сообщения, если это не запрещено правилами в разделе 4.4.

Если вы знаете длину, и она звучит так, как вы, укажите ее в заголовке Content-Length и сделайте с ней, так как спецификация в основном просит вас сделать это (предполагая, что ничего другого вы не нарушаете правил, упомянутых в http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4).