プロキシ経由で受け取った応答は相対 Location を返すことがあります:

Location: ../new/

現代の HTTP ではここに URI 参照を許します。応答を生成した URL に対して解決してください。その URL が https://docs.example/catalog/old/ だった場合、上記の参照は https://docs.example/catalog/new/ を指します。プロキシのホスト名は基準ではありません。

通常の Python urllib リクエストでは、プロキシのエンドポイント周りで文字列を連結するのではなく、そのリダイレクトハンドラを使用します:

opener = build_opener(ProxyHandler({
    "https": "http://proxy.example:8080",
}))
with opener.open("https://docs.example/catalog/old/",
                 timeout=15) as response:
    final_url = response.geturl()

プロキシ認証のないこの公開ドキュメントのリクエストでは、ルートが許可されていれば、HTTP プロキシ一覧の HTTP 候補がサンプルのエンドポイントを置き換えられます。クラスは urllib.request に由来します。通常のハンドラはサポートされるリダイレクトをその制限内で追跡します。final_url が示すのは最終的なリソース URL であり、そこへ到達するために使った仲介者ではありません。

まず解決し、次に経路を選ぶ

リダイレクトは宛先のホストやスキームを変えることがあります。そのため宛先ベースのプロキシポリシーは、その新しい URL も評価する必要があります。最初のホストで機能した経路が次のホストの経路とは限りません。

リダイレクト処理を自分で実装する場合は、ドットセグメントを扱う URI 参照解決を使用してください。実際のステータスコードのメソッド規則を保ち、リダイレクト上限を設けます。Location をホスト名に連結することは、その解決アルゴリズムの代わりにはなりません。

リダイレクトが失敗した場合は、要求した URL、応答ステータス、Location の値、解決済みの次の URL を保持してください。これらの 4 つの値は通常、失敗が URL の構築側か、その後に試みた接続側かを示します。

関連記事