The client sees 200 Connection Established, starts TLS, and immediately reports nonsense where a TLS record should be. Look for an unfinished HTTP response before blaming the destination's cipher settings.

For an HTTP/1 CONNECT exchange, the status line is only the beginning of the response. Header fields can follow it. The empty line ending the header section marks the switch to the tunnel after a successful CONNECT response.

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

Those bytes can arrive in one read, several reads, or a read that also contains subsequent bytes. TCP does not preserve the server's write boundaries.

Make the handoff an explicit parser state

  1. Collect and parse the status line. Use the numeric status rather than an exact English reason phrase.
  2. Continue until the complete header-section terminator has arrived. A successful status line does not make the remaining fields disappear.
  3. For a successful CONNECT response, identify the byte immediately after that terminator as the beginning of tunnel data. For other responses, follow the appropriate HTTP response and authentication handling.
  4. Transfer the connection and any unconsumed bytes through the next protocol's supported buffered-I/O interface.

The last step matters even with a good delimiter search. A buffered reader can have consumed more of the socket than the parser requested. Starting TLS on the bare socket while abandoning that reader may strand bytes in the reader's private buffer.

Use a setup deadline and a header-size limit. EOF before the terminator is an incomplete proxy response, not an invitation to wait forever or try TLS anyway.

Reason through several boundaries

Imagine a read ending after Proxy-Agent:. The parser still needs more HTTP header bytes. Imagine another ending halfway through the final CRLF sequence. That is still not a complete header section. Now imagine a complete successful header section followed by tunnel bytes in the same buffer: those extra bytes must survive the handoff.

A 407 is a different outcome. It needs authentication handling; it does not authorize a TLS ClientHello into a tunnel that was never opened.

Prefer a maintained connector unless implementing the handshake is the task. This boundary is specific to the HTTP/1 exchange shown here. An HTTP/2 proxy carries CONNECT on a stream with different framing.

Erthyglow kevrennek