HTTPプロキシ経由のHTTPSリクエストでは、CONNECTを受け付ける応答と、その後トンネル内のWebサイトからの応答を受け取ることがあります。最初のルート設定についてはGuzzleのリクエスト単位のプロキシオプションを参照してください。最初の応答のヘッダーが最終的な応答オブジェクトに存在する必要はありません。

自分で選んだHTTPエンドポイントで再現するには、HTTPプロキシ一覧から候補を選び、HTTPSトンネルを受け付けることを確認します。Guzzle 7.10のcURLハンドラーの経路では、各ヘッダーコールバックを個別のブロックとして保持します:

$blocks = [];
$client = new \GuzzleHttp\Client([
    'handler' => \GuzzleHttp\HandlerStack::create(
        new \GuzzleHttp\Handler\CurlHandler()
    ),
]);

$response = $client->get('https://www.example.com/', [
    'proxy' => 'http://proxy.example:8080',
    'curl' => [CURLOPT_SUPPRESS_CONNECT_HEADERS => false],
    'on_headers' => function (
        \Psr\Http\Message\ResponseInterface $part
    ) use (&$blocks) {
        $blocks[] = [
            'status' => $part->getStatusCode(),
            'reason' => $part->getReasonPhrase(),
            'headers' => $part->getHeaders(),
        ];
    },
]);

cURL拡張はCURLOPT_SUPPRESS_CONNECT_HEADERSを公開している必要があります。これはlibcurl 7.54.0で導入されたオプションです。falseに設定すると、CONNECTヘッダーがcURLのヘッダーコールバックに届きます。Guzzle 7.10のハンドラーは、完了したヘッダーブロックごとに応答を構築し、その境界でon_headersを呼び出します。

ブロックは順序どおりに保ちます。認証チャレンジ、リダイレクト、情報応答は追加のブロックを生むことがあります。すべての値を1つの配列に平坦化したり、ステータスが200という理由だけで応答を分類したりしないでください。

返される応答は完了したリクエストの応答を表し、blocksはコールバックが収集した観測を保持します。トンネルやTLSの設定に失敗した場合、呼び出し側アプリケーションでスローされた転送例外を処理してください。最終的なWebサイトの応答が存在しないこともあります。

この動作は示したcURLハンドラーに固有です。カスタムハンドラーやストリームハンドラーが同じプロキシハンドシェイクのコールバックを公開する義務はありません。取得したプロキシヘッダーは診断データとして扱い、アカウントに関わる値を不必要に保持しないでください。

関連記事