Прямой прокси читает строку запроса и заголовки, пересылает их, а затем ждёт в select тело POST. Клиент уже отправил его. Обе стороны выглядят так, будто ждут друг друга.

В BaseHTTPRequestHandler из Python чтение заголовков идёт через rfile — буферизованный входной поток. Этот поток может читать вперёд и удерживать байты, принадлежащие телу. Ожидание на нижележащем сокете спрашивает только, готов ли его файловый дескриптор; оно не спрашивает, содержит ли поток Python уже пригодные данные.

Следуйте за буфером, который прочитал заголовки

Читайте тело тоже через self.rfile. Не переключайтесь на self.connection.recv после разбора заголовков буферизованным потоком. Иначе код может обойти байты, уже удерживаемые этим потоком, и ждать данные, которые больше никогда не будут отправлены.

Передача самого rfile в select не заставляет select проверять его буфер Python. API готовности работает через файловый дескриптор объекта.

Для запроса с одним допустимым Content-Length и без Transfer-Encoding потребите ровно объявленное число байтов, обработав преждевременный конец ввода и свои ограничения по размеру и времени. Не читайте до EOF: клиент с постоянным соединением может оставить соединение открытым после завершения запроса.

Сделайте кадрирование явной частью прокси

Тела запросов в формате chunked требуют поддержки chunked-кадрирования. Их нельзя прочитать, ища отсутствующий Content-Length. Неоднозначные метаданные длины требуют определённого пути отказа, а не выбора заголовка, который кажется удобным.

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

Этот диагноз касается того, где удерживаются входящие байты. После того как прокси потребил правильное тело, ему всё ещё нужно переслать это тело с согласованным кадрированием HTTP. Стандартный обработчик http.server — полезное место для понимания механизма, но это не производственная реализация прямого прокси.

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