HTTP CONNECT 応答後にバッファ内のデータを保持する
応答ヘッダーの境界を見つけ、その後に到着するバイトを保持することで、止まってしまう HTTP CONNECT ハンドシェイクを避けます。
小さなプロキシラッパーは HTTPS では動作し、サーバー側から話し始めるプロトコルに再利用するとハングすることがあります。疑わしい行は、多くの場合、受信バッファーが \r\n\r\n で終わるのを待っている行です。
TCP はクライアントにストリームを渡します。1 回の受信呼び出しで、HTTP ステータス行の半分、完全な CONNECT 応答、あるいはその応答に続いてすぐにトンネルデータが返ることがあります。読み取りがヘッダーの終端で止まる保証はありません。
バッファー内で境界を見つける
HTTP/1.1 CONNECT のやり取りでは、ヘッダー終端記号がバッファー内のどこかに現れるまでバイトを蓄積します。最初に現れた位置で分割します。1 つ目の部分からステータス行とヘッダーを解析し、境界より後ろはすべて別に保持します。待機中はヘッダーサイズの上限とタイムアウトを適用し、空のソケット読み取りはループを続ける誘いではなく接続の終了として扱います。
最終的な成功 2xx 応答は、そのヘッダーの直後から接続をトンネルモードに切り替えます。それに続くバイトはすでにトンネルのバイトです。破棄せず、CONNECT 応答のボディを待つこともしないでください。また Content-Length フィールドを、新しいプロトコルの一部を消費してよい許可だと解釈してはいけません。情報提供応答がある場合は、その最終応答より前に処理する必要があります。
ラッパーは余りを引き継ぐ必要がある
基になるソケットだけを返すと、ハンドシェイクのパーサーがすでにそこから取り出したバイトが失われます。次の読み取り側には、保存された末尾を先に返し、その後にソケットからの読み取りを再開するバッファー付きストリームが必要です。サーバー側から話し始めるプロトコルでは、その最初の挨拶を失うと双方が無期限に待ち続ける可能性があります。
逆に、失敗した CONNECT 応答のバイトはトンネルの挨拶ではありません。407 は依然としてプロキシのやり取りに属し、認証の処理が必要です。その他の失敗ステータスには適切なエラー経路が必要です。
これは特に、HTTP プロキシ経由で FTP や SSH クライアントを適応させる場合に重要です。プロキシは要求された宛先ポートも許可する必要があり、FTP は追加のデータ接続を必要とすることがあります。正しいヘッダー解析はストリームの引き渡しを解決しますが、CONNECT の許可を与えたり FTP の第 2 チャネルを提供したりすることはできません。