Как надежно прочитать все данные, когда отсутствуют значения content_length и Transfer-Encoding: chunked? (Boost Asio)

Вопросы и ответы

В моем коде используется заголовок 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

  1. Убедитесь, что ваш проект настроен для использования Boost.Asio и необходимый TCP/IP стек или библиотека для работы с HTTP/2.

  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, вы можете надежно получать все данные. Убедитесь, что вы правильно анализируете фреймы и обрабатываете возможные ошибки соединения.

Оцените материал
Добавить комментарий

Капча загружается...