Зачекайте на порожній рядок після CONNECT
Прочитайте повну відповідь HTTP/1 CONNECT, перш ніж передати сокет TLS, навіть якщо рядок стану надійшов першим.
Клієнт бачить 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 не зберігає межі запису сервера.
Зробіть передачу явним станом парсера
- Зберіть і розберіть рядок стану. Використовуйте числовий код, а не точну англійську фразу причини.
- Продовжуйте, доки не надійде повний термінатор розділу заголовка. Успішний рядок стану не робить решту полів невидимими.
- За успішної відповіді CONNECT вважайте байт одразу після цього термінатора початком даних тунелю. За інших відповідей дотримуйтеся відповідної обробки відповіді HTTP та автентифікації.
- Передайте з'єднання та всі невикористані байти через буферизований інтерфейс вводу-виводу, який підтримує наступний протокол.
Останній крок важливий навіть за доброго пошуку роздільника. Буферизований читач міг спожити більше сокета, ніж запросив парсер. Запуск TLS на голому сокеті з відмовою від цього читача може залишити байти в приватному буфері читача.
Використовуйте строк на встановлення та обмеження розміру заголовка. EOF до термінатора — це неповна відповідь проксі, а не запрошення чекати вічно або все ж спробувати TLS.
Продумайте кілька меж
Уявіть читання, що закінчується після Proxy-Agent:. Парсеру все ще потрібні байти заголовка HTTP. Уявіть інше, що закінчується посередині останньої послідовності CRLF. Це все ще не повний розділ заголовка. А тепер уявіть повний успішний розділ заголовка, за яким у тому самому буфері йдуть байти тунелю: ці зайві байти мають пережити передачу.
407 — це інший результат. Він потребує обробки автентифікації; він не дозволяє TLS ClientHello у тунель, який ніколи не відкривався.
Надавайте перевагу підтримуваному конектору, якщо реалізація рукостискання не є завданням. Ця межа стосується саме показаного тут обміну HTTP/1. Проксі HTTP/2 несе CONNECT у потоці з іншим кадруванням.