Небольшая прокси-обёртка может работать для HTTPS, а затем зависать при повторном использовании для протокола, сервер которого говорит первым. Подозрительная строка — обычно та, что ждёт, пока буфер приёма закончится последовательностью \r\n\r\n.

TCP даёт клиенту поток. Один вызов приёма может вернуть половину строки состояния HTTP, полный ответ CONNECT или этот ответ сразу с данными туннеля. Нет никакой гарантии, что чтение остановится на конце заголовков.

Найдите границу внутри буфера

Для обмена HTTP/1.1 CONNECT накапливайте байты, пока терминатор заголовков не появится в любом месте буфера. Разделите по первому его вхождению. Разберите строку состояния и заголовки из первой части; всё после границы храните отдельно. Применяйте ограничение размера заголовков и тайм-аут во время ожидания, а пустое чтение из сокета считайте закрытым соединением, а не новым приглашением к циклу.

Последний успешный ответ 2xx переводит соединение в режим туннеля сразу после этих заголовков. Следующие за ним байты — уже байты туннеля. Не отбрасывайте их, не ждите тела ответа CONNECT и не трактуйте поле Content-Length как разрешение потребить часть нового протокола. Информационные ответы, если они есть, нужно обработать до этого финального ответа.

Обёртка должна передавать свои остатки

Возврат только нижележащего сокета теряет байты, которые парсер рукопожатия уже извлёк из него. Следующему читателю нужен буферизованный поток, который сначала отдаёт сохранённый хвост, а затем возобновляет чтение из сокета. Для протокола, где сервер говорит первым, потеря этого начального приветствия может оставить обе стороны в бесконечном ожидании.

И наоборот, байты неудачного ответа CONNECT не являются приветствием туннеля. 407 по-прежнему относится к обмену с прокси и требует обработки аутентификации; другой неуспешный статус требует подходящего пути ошибки.

Это особенно важно при адаптации клиента FTP или SSH через HTTP-прокси. Прокси также должен разрешать запрошенный порт назначения, а FTP может требовать дополнительных соединений данных. Правильный разбор заголовков решает передачу потока; он не может выдать разрешение CONNECT или обеспечить второй канал FTP.

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