Клієнт бачить 200 Connection Established, запускає TLS і одразу повідомляє безглуздя там, де має бути запис TLS. Шукайте незавершену відповідь HTTP, перш ніж звинувачувати налаштування шифрів призначення.

У обміні HTTP/1 CONNECT рядок стану — лише початок відповіді. Після нього можуть іти поля заголовка. Порожній рядок, що завершує розділ заголовка, позначає перехід у тунель після успішної відповіді CONNECT.

HTTP/1.1 200 Connection Established\r\n
Proxy-Agent: example\r\n
\r\n

Ці байти можуть надійти за одне читання, за кілька читань або за читання, що містить і наступні байти. TCP не зберігає межі запису сервера.

Зробіть передачу явним станом парсера

  1. Зберіть і розберіть рядок стану. Використовуйте числовий код, а не точну англійську фразу причини.
  2. Продовжуйте, доки не надійде повний термінатор розділу заголовка. Успішний рядок стану не робить решту полів невидимими.
  3. За успішної відповіді CONNECT вважайте байт одразу після цього термінатора початком даних тунелю. За інших відповідей дотримуйтеся відповідної обробки відповіді HTTP та автентифікації.
  4. Передайте з'єднання та всі невикористані байти через буферизований інтерфейс вводу-виводу, який підтримує наступний протокол.

Останній крок важливий навіть за доброго пошуку роздільника. Буферизований читач міг спожити більше сокета, ніж запросив парсер. Запуск TLS на голому сокеті з відмовою від цього читача може залишити байти в приватному буфері читача.

Використовуйте строк на встановлення та обмеження розміру заголовка. EOF до термінатора — це неповна відповідь проксі, а не запрошення чекати вічно або все ж спробувати TLS.

Продумайте кілька меж

Уявіть читання, що закінчується після Proxy-Agent:. Парсеру все ще потрібні байти заголовка HTTP. Уявіть інше, що закінчується посередині останньої послідовності CRLF. Це все ще не повний розділ заголовка. А тепер уявіть повний успішний розділ заголовка, за яким у тому самому буфері йдуть байти тунелю: ці зайві байти мають пережити передачу.

407 — це інший результат. Він потребує обробки автентифікації; він не дозволяє TLS ClientHello у тунель, який ніколи не відкривався.

Надавайте перевагу підтримуваному конектору, якщо реалізація рукостискання не є завданням. Ця межа стосується саме показаного тут обміну HTTP/1. Проксі HTTP/2 несе CONNECT у потоці з іншим кадруванням.

Схожі статті