Кратко

  • Upgrade и CONNECT предлагают изменить дальнейшую интерпретацию HTTP/1.1-соединения, но не фиксируют согласие сервера на новый протокол.
  • Если предложение отклонено, преждевременно отправленные данные всё ещё могут быть разобраны как HTTP/1.1.

Оптимистичный переход легко представить как техническую мелочь. Клиент закончил запрос, заранее знает желаемый протокол и пытается не ждать ещё один сетевой шаг. Поэтому он посылает первые байты нового потока до ответа. Это может уменьшать ожидание на диаграмме клиента. Но сервер в этот момент ещё вправе выбрать иной исход: проигнорировать Upgrade, запросить аутентификацию, перенаправить ресурс, отклонить CONNECT-адрес по политике или из-за недоступности.

RFC 9931 задаёт точку, после которой такое право уже реализовано. Для Upgrade это 101 Switching Protocols; для CONNECT — успешный 2xx. Завершённый запрос необходим, чтобы клиент вообще мог начать обновлённый протокол, однако этого недостаточно. До ответа клиент может честно зафиксировать: «я предложил переход». Он не может честно записать: «другая сторона уже перешла к новому парсеру».

Отказ не стирает соединение задним числом. Сервер способен продолжать разбирать последующие байты по правилам HTTP/1.1. Тогда последовательность, которую клиент считает началом нового протокола, для сервера становится следующей HTTP-заявкой. Риск рождается не из мистического свойства пакета, а из расхождения между ожидаемой и действующей грамматикой.

Это расхождение особенно значимо, когда доверенный для сервера клиент переносит данные, выбранные недоверенной третьей стороной. Браузер способен принести элементы, контролируемые другим origin; прокси-клиент — переслать TCP-payload локального приложения. Если payload ушёл до 2xx, а CONNECT был отклонён, прокси может получить этот материал всё ещё в HTTP/1.1-контексте. RFC 9931 называет request smuggling и использование различий парсера условными рисками такой конструкции. Она не свидетельствует об атаке на конкретную сеть и не объявляет каждую раннюю передачу компрометацией.

Изменение connect-udp делает ограничение наглядным. Оптимистично отправлять UDP-датаграммы можно только при HTTP/2 или более поздней версии; при HTTP/1.x это запрещено из-за риска request smuggling. Это не сертификат надёжности HTTP/2 и не доказательство доставки, права на назначение или прикладного результата. Норма лишь не позволяет превратить неразрешённую двусмысленность HTTP/1.x в скрытую цену оптимизации.

Для CONNECT от имени недоверенных TCP-клиентов прокси-клиент обязан ждать 2xx до пересылки payload либо послать Connection: close. Прокси-сервер после отказа CONNECT обязан закрыть базовое соединение до обработки дальнейших запросов. Эти требования удерживают в разных строках источник данных, решение о переходе, фактический парсер и последующее действие. Они не доказывают, что туннель существует, что субъект авторизован или что бизнес-операция состоялась.

Полезный операционный журнал поэтому не сокращает глаголы: клиент предложил; запрос завершён; ответ получен; переход принят или отклонён; payload удержан или переслан; соединение закрыто; последующий эффект наблюдён. Подход Heng Lu к первичности работающего кода укрепляет именно такую сдержанность. Трасса исполнения важна для своего слоя, но не получает права назначить политику другой стороны или выдать предположение за ненаблюдаемый результат.

Источники