Получить содержимое из HTTP-запроса, даже если заголовок длины содержимого отсутствует - PullRequest
3 голосов
/ 03 марта 2011

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

Как извлечь этот контент без помощи заголовка contentlength?

Ответы [ 3 ]

4 голосов
/ 03 марта 2011

Я сохранил исходный ответ для полноты, но я только что искал в HTTP RFC (2616) раздел 4.3:

Присутствие тела сообщения в запросе сигнализируется включением поля заголовка Content-Length или Transfer-Encoding в заголовки сообщения запроса. Тело сообщения НЕ ДОЛЖНО быть включено в запрос, если спецификация метода запроса (раздел 5.1.1) не позволяет отправлять тело объекта в запросах. Сервер ДОЛЖЕН прочитать и переслать тело сообщения по любому запросу; если метод запроса не включает определенную семантику для тела объекта, то тело сообщения ДОЛЖНО игнорироваться при обработке запроса.

Так что, если у вас нет длины контента, у вас должно иметь кодировку передачи (а если у вас ее нет, вы должны ответить статусом 400, чтобы указать неверный запрос, или 411 ( "длина требуется")). В этот момент вы делаете то, что говорит вам Transfer-Encoding:)

Теперь, если вы имеете дело с API сервлета (или аналогичным HTTP API), он вполне может справиться со всем этим для вас - в этот момент вы сможете использовать методику ниже для чтения из поток до тех пор, пока он не выдаст больше данных, так как об этом позаботится API (т.е. это будет не просто поток сокетов).

Если бы вы могли дать нам больше информации о вашем контексте, это помогло бы.


Оригинальный ответ

Если длина содержимого отсутствует, это означает, что содержимое продолжается до конца данных (когда сокет закрывается).

Продолжайте чтение из входного потока (например, записывая его в ByteArrayOutputStream для его сохранения или, возможно, файла), пока InputStream.read не вернет -1. Например:

byte[] buffer = new byte[8192];
ByteArrayOutputStream output = new ByteArrayOutputStream();
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1)
{
    output.write(buffer, 0, bytesRead);
}
// Now use the data in "output"

РЕДАКТИРОВАТЬ: Как было указано в комментариях, клиент может использовать chunked кодировку. Обычно используемый вами HTTP API должен справиться с этим, но если вы работаете с необработанным сокетом, вам придется справиться с этим самостоятельно.

Интересным является вопрос о том, что запрос (и, следовательно, клиент не может закрыть соединение) - я думал , что клиент мог просто закрыть отправляющую часть, но я не не вижу, как это отображается на что-либо в TCP в данный момент. Мои знания в области низкоуровневых сетей не такие, какими они могут быть.

Если этот ответ окажется "определенно бесполезным", я его удалю ...

3 голосов
/ 03 марта 2011

Если бы это был ответ , то сообщение можно было бы прекратить, закрыв соединение.Но это не вариант здесь, потому что клиент все еще должен прочитать ответ.

Помимо Content-Length:, другие методы определения длины контента:

  • Transfer-Encoding: chunked
  • угадайка

Надеемся, что это первое, и в этом случае запрос должен выглядеть примерно так:

POST /some/path HTTP/1.1
Host: www.example.com
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1C
and this is the second one

3
con
8
sequence
0

(бессовестно украденный из статьи Википедии) и изменен для запроса)

  • каждый фрагмент имеет форму: шестнадцатеричная длина, CRLF, данные, CRLF
  • после того, как окончательный блок переноса данных приходитчанк нулевой длины без данных
  • после чанка нулевой длины добавляются необязательные дополнительные заголовки HTTP
  • после необязательных заголовков HTTP приходит еще один CRLF
0 голосов
/ 03 марта 2011
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...