Столкнулся с проблемой при написании HTTP снифера: Иногда приходят HTTP ответы ( нормальные с кодом 200 ), т.е. которые предполагают существование тела сообщения, причем они не содержат ни поле Content-Length, ни поле Transfer-Encoding и как определить длинну передаваемой информации - х.з. Вот, пример такого заголовка: HTTP/1.1 200 OK Date: Mon, 17 Sep 2007 13:54:51 GMT Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 OpenSSL/0.9.8d mod_gzip/1.3.26.1a mod_fastcgi/2.4.2 PHP/4.4.7 mod_perl/1.29 rus/PL30.22 Vary: Accept-Encoding Connection: close Content-Type: text/html <html> <head> ................................................................................... Или же если указано Connection: close - то всасываем все данные что нам передают до тех пор пока соединение существует, т.е. до обмена маркерами FIN ?
Ну так всё и определяют на самом деле. Всё кроме Host: в пакете, в реальной жизни поля опциональные и не обязательные. Если ты качаешь файл, то ты качаешь до тех пор пока соедидение не будет закрыто. Т.е. если recv вернул -1 , произошла ошибка передачи или разрыв соединения. Если recv вернул 0, то соединение было нормально закрыто (через FIN) и файл докачан. Если сервер на пол пути передумает отдавать тебе файл, то у в сокетах есть способ закрыть соединение с ошибкой на другой стороне. Короче жди нуля, а на длину не смотри...
Могу вас разочаровать - во первых - это не по стандарту и не до конца правильно, т.к. в пределах одной TCP сессии может быть передано сколь угодно много запросов и ответов. Вот, кстати еще пример заголовка, уже без указания Connection: close HTTP/1.0 200 OK Date: Mon Sep 17 17:54:53 2007 Cache-control: no-cache, max-age=0, must-revalidate, no-store Pragma: no-cache Expires: Thu, 01 Jan 1970 00:00:00 GMT P3P: policyref="/w3c/p3p.xml", CP="NON CUR ADM DEV PSA PSD OUR IND UNI NAV INT STA" Set-Cookie: uid=928277860; expires=Wednesday, 01-Jan-2020 00:00:00 GMT;path=/;domain=.adriver.ru Content-type: text/html <head></head> <body bgcolor="#FFFFFF" topmargin="0" leftmargin="0" marginwidth="0" marginheight="0" scroll="no"> ......................................................................................... Вобщем, фиг знает как это может понимать браузер ? по крайней мере я этого не понимаю. На счет поля Host - оно указывается только в запросах и то не всегда, так что оно тоже опциональное. бывают ответы вообще замечательные: HTTP/1.0 200 OK и все... Ну, конечно, на такие кладу болт, но те примеры которые я привел их как то обрабатывает браузер ?
Ну я не знаю как там по стандарту. Зато видел как пишут серверы и браузеры. Любая программа ориентируется на нормальное закрытие соединения. Программы которые не разрывают соединение, кажется пишут в ответном заголовке Connection: keep-alive. Но как я понимаю никто не мешает им попросту этого не делать. Это от софта зависит. Иногда в таких случаях концов считается двойная пустая строка. Можно сделать так чтобы сниффер реагировал на изменение направления потока. Если передаётся новый запрос, то передача ответа надо полагать запрещена..... Ну а забить болт - это самый правильный поступок. Ситуация когда HTTP работает без разрыва, крайне редка и если встречается где-то, то только не в браузерах....
О, кстати, вот это я еще не проверял, на счет двойной пустой ! Нет, такой номер не пройдет, т.к. это асинхронный протокол: например, HTTP может работать так: G1-G2-G3-G4- H1 - HD1 - HD2 - G5 - HD3 - H2 - H3 - H4 - H5, где G# - запрос ( например GET и его порядковый номер ) H# - ответ на запрос с номером # HD# - продолжение ответа на запрос с номером # как видно из диаграммы запрос G5 "как бы" разрывает поток данных ответа. Почему "как бы", потому что необходимо рассматривать отдельно входящий и исходящий потоки, тогда подобного разрыва мы уже не увидим. Вобщем, попробую детектить двойную пустую. Эх, этот бесконечный автомат состояний потребует небольшого изменения...
сервера бывают такие кривые, что просто удивительно, как броузеры с ними работают. Например, мне попался как то на глаза сервак, который строчки разделял через \n, а не \r\n. Они могут быть запросто чувствительными к регистру полей. Они могут забывать закрывать соединение. Короче, они могут делать все, что им угодно ))). Во поводу первого запроса, там формально все правильно - указано Connection: close и конец сообщения можно определить по концу соединения По поводу второго - обратите внимание еще на строку HTTP/1.0 - версия не 1.1. В 1.0 по моему нельзя было передавать пачками запросы и.т.п. В любом случае, вежливо завершение соединения сервером - самый надежный признак конца данных.
Наблюдал, учтено. тоже учел. действительно и как это все работает до сих пор ?... Бааальшое спасибо за информацию, будут еще мнения - высказывайтесь, всяко лучше чем одна голова
Нагнал я похоже про дополнительную пустую строку. Там в ответах заголовков может быть некое поле Transfer-Encoding: chunked. В таком случае указывать длину не надо. Данные передаются какими-то кусками хитрого формата и определить их размер и конец данных можно каким-то соотвествующим способом. А вот как это всё работает подробнее, я не понял пока что. Ща покурю RFC или дамбы, может пойму....
Всё крайне просто. Каждый блок начинается с текстовой записи шеснадцатеричной цифры, которая указывает размер данных блока. После чего идёт перевод строки и блок данных (после цифры кажется могут быть пробелы и всякая херня). После блока данных опять идёт перевод строки. И цифра с размером следующего блока. Последний блок имеет нулевой размер, и тоже как бы содержит перевод строки, до и после данных (т.е. '0' и две пустых строки).
В том месте где я сижу сейчас, никаких док под рукой нету. Поточнее нельзя сформулировать вопрос?))).
Клиент серверу: Код (Text): Connection: Keep-Alive; TE TE: identity, chunked, trailers Что есть trailers?
Это все ясно и уже реализовано, в самом первом посте еще упомянул, в RFC2616 описано. Вобщем, все как сказал Proteus. Trailers - это кусок HTTP заголовка который может присутствовать в сообщении у которого Transfer-Encoding: chunked Т.е. после блока с нулевой длинной "0" - могут присутствовать еще какие-либо поля заголовка, за исключением следующих полей: Transfer-Encoding, Content-Length, Trailer.