HTTP-сервер Node обрабатывает обычный прокси-запрос через свой callback запроса. CONNECT идёт другим путём: сервер выдаёт connect вместе с запросом, клиентским сокетом и буфером head.

Это событие — передача между разбором HTTP и туннелем. Обычного объекта ServerResponse, который можно было бы дальше использовать для туннельного трафика, нет.

АргументЧто он несёт
reqЗапрос CONNECT, включая его целевой авторитет и заголовки
clientSocketСоединение обратно к клиенту
headДанные туннеля, которые Node уже прочитал за пределами HTTP-заголовков, возможно пустые

Завершите решение HTTP до передачи байтов

Проверьте запрошенные хост и порт, примените политику доступа и аутентификации прокси и установите восходящее соединение. CONNECT определяет авторитет вида service.example:443; разбирайте эту форму с учётом авторитетов IPv6, а не делите вслепую по каждому двоеточию.

Когда туннель принят, отправьте успешный HTTP-ответ, а затем завершающую пустую строку. После этого передайте любые байты head вверх по потоку, прежде чем продолжать с последующими байтами из клиентского сокета. Подключение нового обработчика данных не может вернуть буфер, который уже был отдельно передан обработчику.

Официальный пример туннелирования в Node выполняет эту передачу с помощью serverSocket.write(head) перед соединением двух направлений потока. Его небольшой пример иллюстрирует переход; развёрнутому прокси также нужны ограниченные попытки подключения, контроль доступа и управление жизненным циклом.

После успеха байты принадлежат протоколу сервиса

Успешный ответ CONNECT превращает соединение в поток байтов. Если цель — сайт HTTPS, его обмен TLS происходит внутри этого потока. Само туннелирование не требует, чтобы прокси выдавал заменяющий сертификат сайта.

До принятия CONNECT ошибка HTTP может объяснить причину отказа. После принятия запись HTTP 500 в поток внедрила бы байты в туннельный протокол. Вместо этого завершайте или уничтожайте соответствующие соединения при последующих сбоях.

Соедините оба направления с помощью обработка потока с учётом обратного давления и решите, как события end, error и close завершают партнёра. Сохраняйте исходный буфер head как часть той же модели владения; это данные приложения, а не лишние HTTP-заголовки, которые можно выбросить.

Похожие статьи