Читаем заголовок HTTP-запроса (или ответа - не важно). Заголовок оканчивается двумя новыми строками. Соответственно - указываем делимитер: boost::asio::async_read_until ( socket, streambuf, "\r\n\r\n", boost::bind(&session::on_header, shared_from_this(), io::placeholders::error) ); *_read_until умеет читать только в streambuf. Соответственно, чтобы потом вынуть данные, на этот streambuf надевается std::istream, и данные вычитываются. Проблема состоит в том, что судя по дебагу *_read_until читает данные блоками (в моем случае - по 512 байт), и ищет делимитер в блоках. То есть после делимитера он скорее всего прочитает еще часть данных. Однако стрим считает, что данных в потоке - ровно до делимитера, не более (то есть в стримбуфе соответствующим образом выставленны границы), хотя в дебаге видно, что данных прочитано больше (то есть размером с блок). После прочтения заголовка нужно читать тело, однако, если просто продолжить читать из того же сокета, то тело будет обрезано вначале, как раз на те байты, которые были прочитаны в блок *_read_until после делимитера (думаю, это очевидно). Вопрос: как по-человечески разрулить эту ситуацию? Пролождать работать со стримбуфом до конца соединения - не хочется. Хачить стримбуф, выдирать указатели и т.д. - тоже не тру. Нужно какое-то православное решение для вычитывания заголовка через *_read_until с последующим вычитыванием тела через *_receive.
Так, вернемся к нашим баранам. Кое-что прояснилось. Фри-функции asio работают со стримбуфами, мембер-функции сокета работают с asio::buffer (обобщение над массивами и контенерами). Если начать читать фри-функцией, то потом продолжить мембер-функцией не получается. Ок, будем все читать и писать фри-функциями. Возникает следующий вопрос, уже не по азио, а по стримам С++: Есть streambuf, в нем данные (частично прочитанный HTTP-запрос). На него надевается std::istream и читается пара строк (урл, хедеры, ...). Теперь мне нужно как-то заресетить стрим, или стримбуф. То есть чтобы если я снова начал читать из этого стрима, то чтение началось сначала. Как это сделать?
В общем так. У asio::streambuf можно спросить data(), которая в свою очередь может быть проитерирована через asio::buffers_begin / buffers_end - вот и вся любовь.
Booster В примерах делается именно так. К тому же, ::data() это функция boost::asio::basic_streambuf, а не STL-ного предка. По-видимому введена в streambuf именно с целью доступа к данным.
Если так, то это плохо. Торчать наружу потоковый накопитель(буфер), не должен. Если не хватает функциональности istream, то его можно доработать, как например сделано с ifstream. А streambuf это низкоуровневая вещь.
Нельзя сказать, что доступ пользователя к стримбуфу - это всегда плохо. Если бы это было сугубо библиотечный класс, то он был бы наверно в чьей-либо private-секции, или не имел бы публичного интерфейса. А раз он имеет публичные методы, то наверно это потому, что пользователю все же иногда может потребоваться их вызывать.