В моем коде используется заголовок content_length, который, кажется, работает нормально для HTTP/1.1, но это не подходит для HTTP/2, где этот заголовок не является обязательным.
https://www.rfc-editor.org/rfc/rfc9113.html упоминает END_STREAM
, но я не могу его прочитать (или tcp фреймы) с помощью boost::asio's async_read_some
.
Как вы бы прочитали http/2 запрос в boost::asio без доступа к таким заголовкам?
Я думал о том, чтобы читать до EOF error
, но не знаю, хороша ли это практика.
Я изучал message_flags
и OOB данные, но безуспешно. :<
Ответ
Для надежного чтения всех данных в HTTP/2, когда заголовки Content-Length и Transfer-Encoding: chunked отсутствуют, необходимо учитывать особенности HTTP/2 и работу с Boost.Asio. Вот пошаговая инструкция, как это сделать:
Шаг 1: Понимание HTTP/2
В HTTP/2 нет обязательного заголовка Content-Length, так как протокол поддерживает множественные потоки и может передавать данные в нескольких фреймах. Вместо этого вы должны использовать особые аспекты протокола, такие как фреймы и флаг END_STREAM.
Шаг 2: Настройка Boost.Asio
-
Убедитесь, что ваш проект настроен для использования Boost.Asio и необходимый TCP/IP стек или библиотека для работы с HTTP/2.
- Создайте асинхронное соединение с сервером. Например:
boost::asio::io_context io_context;
boost::asio::ip::tcp::resolver resolver(io_context);
boost::asio::ip::tcp::socket socket(io_context);
auto endpoints = resolver.resolve("example.com", "443");
boost::asio::connect(socket, endpoints);
Шаг 3: Чтение данных без заголовков Content-Length и Transfer-Encoding
Для обработки ответа от HTTP/2 необходимо создать механизм для чтения фреймов. Вам нужно будет обрабатывать др. фреймы, такие как DATA, и фиксировать, когда встречается флаг END_STREAM. Вот пример, как это можно реализовать:
void read_data(boost::asio::ip::tcp::socket& socket) {
std::vector<char> buffer(4096); // буфер для чтения данных
while (true) {
boost::system::error_code error;
size_t bytes_transferred = socket.read_some(boost::asio::buffer(buffer), error);
if (error) {
if (error == boost::asio::error::eof) {
// Соединение закрыто корректно – мы достигли конца потока.
break;
} else {
// Обработка других ошибок
throw boost::system::system_error(error);
}
}
// Обработка прочитанных данных
process_frame(buffer.data(), bytes_transferred);
}
}
void process_frame(const char* data, size_t length) {
// Здесь вы должны анализировать фреймы HTTP/2:
// 1. Определите тип фрейма (DATA, HEADERS и т.д.)
// 2. Обработайте его согласно спецификациям HTTP/2.
// 3. Проверьте, был ли установлен флаг END_STREAM для завершения чтения.
}
Шаг 4: Обработка фреймов
Когда вы будете читать и анализировать фреймы, проверьте, является ли тип фрейма DATA
и установлен ли флаг END_STREAM
. Этот флаг указывает на то, что больше данных не будет, и вы можете завершить чтение.
Шаг 5: Завершение работы
После завершения чтения всех данных не забудьте закрыть сокет и освободить ресурсы:
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
socket.close();
Заключение
Чтение данных в HTTP/2 без заголовков Content-Length и Transfer-Encoding может быть сложным, но с помощью Boost.Asio и правильной обработки фреймов, включая проверку флага END_STREAM, вы можете надежно получать все данные. Убедитесь, что вы правильно анализируете фреймы и обрабатываете возможные ошибки соединения.