在 HTTP CONNECT 响应之后保留缓冲区中的数据
通过找到响应头的边界并保留其之后到达的字节,避免 HTTP CONNECT 握手卡住。
一个小的代理包装器可能对 HTTPS 有效,但在用于服务器先说法的协议时会挂起。可疑的那一行往往是等待接收缓冲区以 \r\n\r\n 结束 的那一行。
TCP 给客户端一个字节流。一次接收调用可能返回半行 HTTP 状态行、一个完整的 CONNECT 响应,或者该响应后面紧跟隧道数据。并没有任何保证说一次读取会停在头部末尾。
在缓冲区内部找到边界
对于 HTTP/1.1 CONNECT 交换,持续累积字节,直到头部终止符出现在缓冲区中的任意位置。在它第一次出现的位置切分。从第一部分解析状态行和头部;把边界之后的所有内容单独保留。等待时施加头部大小上限和超时,并把空的套接字读取视为连接已关闭,而不是又一次循环的邀请。
最终成功的 2xx 响应会在这之后立刻把连接切换到隧道模式。它后面跟随的字节已经是隧道字节。不要丢弃它们,不要 等待 CONNECT 响应正文,也不要把 Content-Length 字段解读为可以消费新协议一部分的许可。如果存在信息性响应,需要在该最终响应之前处理。
包装器必须把剩余数据传递下去
只返回底层套接字会丢失握手解析器已经从中取出的字节。下一个读取方需要一个带缓冲的流:先交出保存下来的尾部,然后继续从套接字读取。对于服务器先发言的协议,丢失这段初始问候可能让双方无限期等待。
反过来,失败 CONNECT 响应的字节不是隧道问候。407 仍属于代理交换,需要处理认证;其他非成功状态需要相应的错误路径。
在通过 HTTP 代理适配 FTP 或 SSH 客户端时,这一点尤其重要。代理还必须允许所请求的目标端口,而 FTP 可能需要额外的数据连接。正确的头部解析解决了流的交接;它无法授予 CONNECT 权限,也无法提供 FTP 的第二个通道。