CONNECT 뒤의 빈 줄을 기다리세요
상태 줄이 먼저 와도 소켓을 TLS에 넘기기 전에 HTTP/1 CONNECT 응답 전체를 읽으세요.
클라이언트는 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를 나릅니다.