メインコンテンツまでスキップ

5. メッセージルーティング

HTTP リクエストメッセージのルーティングは、ターゲットリソース、クライアントのプロキシ構成、およびインバウンド接続の確立または再利用に基づいて、各クライアントによって決定されます。対応するレスポンスのルーティングは、同じ接続連鎖をクライアントへと逆にたどります。

5.1. ターゲットリソースの識別​

HTTP は、汎用コンピューターから家電製品に至るまで、幅広いアプリケーションで使用されています。場合によっては、通信オプションがクライアントの構成にハードコードされています。しかしながら、ほとんどの HTTP クライアントは、汎用の Web ブラウザーと同じリソース識別機構と構成技法に依存しています。

HTTP 通信は、何らかの目的のためにユーザーエージェントによって開始されます。その目的は、[RFC7231] で定義されるリクエストのセマンティクスと、それらのセマンティクスを適用すべきターゲットリソースの組み合わせです。URI 参照 (セクション 2.7) は、通常、"ターゲットリソース" の識別子として使用され、ユーザーエージェントは "ターゲット URI" を得るためにそれを絶対形式に解決します。ターゲット URI は、参照のフラグメント構成要素 (存在する場合) を除外します。フラグメント識別子はクライアント側の処理のために予約されているためです ([RFC3986] のセクション 3.5)。

5.2. インバウンド接続​

ターゲット URI が決定されると、クライアントは、望ましいセマンティクスを達成するためにネットワークリクエストが必要かどうか、また必要な場合はそのリクエストをどこに向けるかを決定する必要があります。

クライアントがキャッシュ [RFC7234] を持ち、そのリクエストをそれで満たせる場合、リクエストは通常まずそこに向けられます。

リクエストがキャッシュで満たされない場合、典型的なクライアントは、その構成を調べて、リクエストを満たすためにプロキシを使用すべきかどうかを判断します。プロキシ構成は実装依存ですが、多くの場合、URI プレフィックスの一致、選択的な authority の一致、またはその両方に基づいており、プロキシ自体は通常 "http" または "https" URI によって識別されます。プロキシが適用可能である場合、クライアントは、そのプロキシへの接続を確立 (または再利用) することによってインバウンド接続を行います。

プロキシが適用可能でない場合、典型的なクライアントは、通常はターゲット URI のスキームに固有のハンドラールーチンを呼び出して、ターゲットリソースの authority に直接接続します。それがどのように達成されるかは、ターゲット URI スキームに依存し、その関連する仕様によって定義されます。これは、本仕様が "http" (セクション 2.7.1) および "https" (セクション 2.7.2) スキームの解決のためのオリジンサーバーアクセスを定義するのと同様です。

接続管理に関する HTTP 要件は、セクション 6 で定義されています。

5.3. リクエストターゲット​

インバウンド接続が取得されると、クライアントは、ターゲット URI から導出された request-target を含む HTTP リクエストメッセージ (セクション 3) を送信します。request-target には 4 つの異なる形式があり、要求されているメソッドと、リクエストがプロキシへのものであるかどうかの両方に依存します。

request-target = origin-form
/ absolute-form
/ authority-form
/ asterisk-form

5.3.1. origin-form​

request-target の最も一般的な形式は origin-form です。

origin-form    = absolute-path [ "?" query ]

CONNECT またはサーバー全体の OPTIONS リクエスト (以下で詳述) を除き、オリジンサーバーに直接リクエストを行う場合、クライアントは、ターゲット URI の絶対パスとクエリ構成要素のみを request-target として送信しなければなりません (MUST)。ターゲット URI のパス構成要素が空である場合、クライアントは origin-form の request-target 内のパスとして "/" を送信しなければなりません (MUST)。また、セクション 5.4 で定義されているように、Host ヘッダーフィールドも送信されます。

たとえば、次のように識別されるリソースの表現を取得したいクライアントは:

http://www.example.org/where?q=now

オリジンサーバーから直接、ホスト "www.example.org" のポート 80 への TCP 接続を開き (または再利用し)、次の行を送信します:

GET /where?q=now HTTP/1.1
Host: www.example.org

その後にリクエストメッセージの残りが続きます。

5.3.2. absolute-form​

CONNECT またはサーバー全体の OPTIONS リクエスト (以下で詳述) を除き、プロキシにリクエストを行う場合、クライアントは、ターゲット URI を absolute-form で request-target として送信しなければなりません (MUST)。

absolute-form  = absolute-URI

プロキシは、可能であれば有効なキャッシュからそのリクエストを満たすか、またはクライアントの代わりに、次のインバウンドプロキシサーバーか、request-target によって示されるオリジンサーバーに直接、同じリクエストを行うよう要求されます。そのようなメッセージの "転送" に関する要件は、セクション 5.7 で定義されています。

request-line の absolute-form の例は次のとおりです:

GET http://www.example.org/pub/WWW/TheProject.html HTTP/1.1

HTTP のいくつかの将来のバージョンですべてのリクエストを absolute-form に移行できるようにするため、HTTP/1.1 クライアントがプロキシへのリクエストでのみそれを送信するとしても、サーバーはリクエストで absolute-form を受け入れなければなりません (MUST)。

5.3.3. authority-form​

request-target の authority-form は、CONNECT リクエスト ([RFC7231] のセクション 4.3.6) にのみ使用されます。

authority-form = authority

1 つ以上のプロキシを通じてトンネルを確立するために CONNECT リクエストを行う場合、クライアントは、ターゲット URI の authority 構成要素 (任意の userinfo およびその "@" 区切り文字を除く) のみを request-target として送信しなければなりません (MUST)。例えば、

CONNECT www.example.com:80 HTTP/1.1

5.3.4. asterisk-form​

request-target の asterisk-form は、サーバー全体の OPTIONS リクエスト ([RFC7231] のセクション 4.3.7) にのみ使用されます。

asterisk-form  = "*"

クライアントが、そのサーバーの特定の名前付きリソースではなく、サーバー全体に対する OPTIONS を要求したい場合、クライアントは request-target として "*" (%x2A) のみを送信しなければなりません (MUST)。例えば、

OPTIONS * HTTP/1.1

プロキシが、URI が空のパスとクエリ構成要素を持たない absolute-form の request-target を持つ OPTIONS リクエストを受信した場合、リクエスト連鎖上の最後のプロキシは、そのリクエストを示されたオリジンサーバーに転送するときに、request-target として "*" を送信しなければなりません (MUST)。

たとえば、次のリクエストは

OPTIONS http://www.example.org:8001 HTTP/1.1

最終的なプロキシによって次のように転送されます

OPTIONS * HTTP/1.1
Host: www.example.org:8001

これは、ホスト "www.example.org" のポート 8001 に接続した後のものです。

5.4. Host​

リクエスト内の "Host" ヘッダーフィールドは、ターゲット URI からのホストとポートの情報を提供し、オリジンサーバーが、単一の IP アドレスで複数のホスト名に対するリクエストを処理しながらリソースを区別できるようにします。

Host = uri-host [ ":" port ] ; Section 2.7.1

クライアントは、すべての HTTP/1.1 リクエストメッセージで Host ヘッダーフィールドを送信しなければなりません (MUST)。ターゲット URI が authority 構成要素を含む場合、クライアントは、任意の userinfo 副構成要素とその "@" 区切り文字を除いて、その authority 構成要素と同一の Host のフィールド値を送信しなければなりません (MUST) (セクション 2.7.1)。ターゲット URI について authority 構成要素が欠けているか未定義である場合、クライアントは、空のフィールド値を持つ Host ヘッダーフィールドを送信しなければなりません (MUST)。

Host のフィールド値はリクエストを処理するために重要な情報であるため、ユーザーエージェントは、request-line の直後の最初のヘッダーフィールドとして Host を生成すべきです (SHOULD)。

たとえば、http://www.example.org/pub/WWW/ のオリジンサーバーへの GET リクエストは、次のように始まります:

GET /pub/WWW/ HTTP/1.1
Host: www.example.org

クライアントは、request-target が absolute-form であっても、HTTP/1.1 リクエストで Host ヘッダーフィールドを送信しなければなりません (MUST)。これにより、Host を実装していない可能性のある古い HTTP/1.0 プロキシを通じて Host 情報を転送できるためです。

プロキシが absolute-form の request-target を持つリクエストを受信した場合、プロキシは、受信した Host ヘッダーフィールド (存在する場合) を無視し、代わりに request-target のホスト情報で置き換えなければなりません (MUST)。そのようなリクエストを転送するプロキシは、受信した Host のフィールド値を転送するのではなく、受信した request-target に基づいて新しい Host フィールド値を生成しなければなりません (MUST)。

Host ヘッダーフィールドはアプリケーション層のルーティング機構として機能するため、共有キャッシュを汚染したり、リクエストを意図しないサーバーにリダイレクトしたりしようとするマルウェアの頻繁な標的となります。傍受プロキシは、傍受した接続がそのホストの有効な IP アドレスを対象としていることを最初に検証することなく、リクエストを内部サーバーにリダイレクトするために、または共有キャッシュのキャッシュキーとして Host のフィールド値に依存している場合、特に脆弱です。

サーバーは、Host ヘッダーフィールドを欠くいかなる HTTP/1.1 リクエストメッセージに対しても、また複数の Host ヘッダーフィールドまたは無効なフィールド値を持つ Host ヘッダーフィールドを含むいかなるリクエストメッセージに対しても、400 (Bad Request) ステータスコードで応答しなければなりません (MUST)。

5.5. 有効リクエスト URI​

request-target はしばしばユーザーエージェントのターゲット URI の一部のみを含むため、サーバーは、リクエストを適切に処理するために、意図されたターゲットを "有効リクエスト URI" として再構成します。この再構成には、サーバーのローカル構成と、request-target、Host ヘッダーフィールド、および接続コンテキストで伝達された情報の両方が関与します。

ユーザーエージェントにとって、有効リクエスト URI はターゲット URI です。

request-target が absolute-form である場合、有効リクエスト URI は request-target と同じです。そうでない場合、有効リクエスト URI は次のように構成されます:

サーバーの構成 (またはアウトバウンドゲートウェイ) が固定の URI スキームを提供する場合、そのスキームが有効リクエスト URI に使用されます。そうでない場合、リクエストが TLS で保護された TCP 接続で受信されたなら有効リクエスト URI のスキームは "https" であり、そうでなければスキームは "http" です。

サーバーの構成 (またはアウトバウンドゲートウェイ) が固定の URI authority 構成要素を提供する場合、その authority が有効リクエスト URI に使用されます。そうでない場合、request-target が authority-form であれば、有効リクエスト URI の authority 構成要素は request-target と同じです。そうでない場合、空でないフィールド値を持つ Host ヘッダーフィールドが提供されていれば、authority 構成要素は Host のフィールド値と同じです。それ以外の場合、authority 構成要素にはサーバー用に構成されたデフォルト名が割り当てられ、接続の着信 TCP ポート番号が有効リクエスト URI のスキームのデフォルトポートと異なる場合、コロン (":") と着信ポート番号 (10 進形式) が authority 構成要素に追加されます。

request-target が authority-form または asterisk-form である場合、有効リクエスト URI の結合されたパスとクエリの構成要素は空です。そうでない場合、結合されたパスとクエリの構成要素は request-target と同じです。

上記のように決定された有効リクエスト URI の構成要素は、scheme、"://"、authority、および結合されたパスとクエリの構成要素を連結することによって absolute-URI 形式に結合できます。

例 1: 安全でない TCP 接続で受信した次のメッセージは

GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.example.org:8080

次の有効リクエスト URI を持ちます

http://www.example.org:8080/pub/WWW/TheProject.html

例 2: TLS で保護された TCP 接続で受信した次のメッセージは

OPTIONS * HTTP/1.1
Host: www.example.org

次の有効リクエスト URI を持ちます

https://www.example.org

Host ヘッダーフィールドを欠く HTTP/1.0 リクエストの受信者は、有効リクエスト URI の authority 構成要素を推測するために、ヒューリスティック (例えば、特定のホストに固有の何かを求めて URI パスを調べる) を使用する必要がある場合があります。

有効リクエスト URI が構成されると、オリジンサーバーは、そのリクエストが受信された接続を介してその URI にサービスを提供するかどうかを決定する必要があります。たとえば、リクエストが意図的にまたは偶発的に誤った方向に送られ、受信した request-target または Host ヘッダーフィールド内の情報が、接続が行われたホストまたはポートと異なる場合があります。接続が信頼されたゲートウェイからのものである場合、その不一致は想定内である可能性があります。そうでない場合、それはセキュリティフィルターを回避したり、サーバーを騙して非公開コンテンツを配信させたり、キャッシュを汚染したりしようとする試みを示す可能性があります。メッセージルーティングに関するセキュリティ上の考慮事項については、セクション 9 を参照してください。

5.6. レスポンスのリクエストへの関連付け​

HTTP は、特定のリクエストメッセージをそれに対応する 1 つ以上のレスポンスメッセージに関連付けるためのリクエスト識別子を含みません。したがって、レスポンスの到着順序が、同じ接続上でリクエストが行われた順序に正確に対応することに依存します。1 つのリクエストに対して複数のレスポンスメッセージが生じるのは、1 つ以上の情報レスポンス (1xx、[RFC7231] のセクション 6.2 を参照してください) が同じリクエストへの最終レスポンスに先行する場合のみです。

接続上に複数の未処理のリクエストを持つクライアントは、未処理のリクエストのリストを送信順に維持しなければならず (MUST)、その接続で受信した各レスポンスメッセージを、まだ最終 (非 1xx) レスポンスを受信していない最も順序の高いリクエストに関連付けなければなりません (MUST)。

5.7. メッセージ転送​

セクション 2.3 で説明されているように、仲介者は HTTP リクエストとレスポンスの処理においてさまざまな役割を果たすことができます。一部の仲介者は、パフォーマンスや可用性を向上させるために使用されます。他のものは、アクセス制御またはコンテンツのフィルタリングに使用されます。HTTP ストリームはパイプアンドフィルターアーキテクチャに類似した特性を持つため、仲介者がストリームのどちらの方向を強化 (または妨害) できるかについて固有の制限はありません。

トンネルとして動作しない仲介者は、セクション 6.1 で規定されている Connection ヘッダーフィールドを実装しなければならず (MUST)、着信接続のみを対象とするフィールドを転送から除外しなければなりません (MUST)。

仲介者は、無限のリクエストループから保護されていない限り、メッセージを自身に転送してはなりません (MUST NOT)。一般に、仲介者は、自身のサーバー名 (任意のエイリアス、ローカルな変種、またはリテラル IP アドレスを含む) を認識し、そのようなリクエストに直接応答すべきです。

5.7.1. Via​

"Via" ヘッダーフィールドは、(リクエストでは) ユーザーエージェントとサーバーの間、または (レスポンスでは) オリジンサーバーとクライアントの間の中間プロトコルと受信者の存在を示します。これは、電子メールの "Received" ヘッダーフィールド ([RFC5322] のセクション 3.6.7) に類似しています。Via は、メッセージ転送の追跡、リクエストループの回避、およびリクエスト/レスポンス連鎖に沿った送信者のプロトコル能力の識別に使用できます。

Via = 1#( received-protocol RWS received-by [ RWS comment ] )

received-protocol = [ protocol-name "/" ] protocol-version
; see Section 6.7
received-by = ( uri-host [ ":" port ] ) / pseudonym
pseudonym = token

複数の Via フィールド値は、メッセージを転送した各プロキシまたはゲートウェイを表します。各仲介者は、メッセージがどのように受信されたかに関する自身の情報を追加し、その結果、最終結果は転送した受信者の順序に従って並びます。

プロキシは、以下で説明するように、転送する各メッセージに適切な Via ヘッダーフィールドを送信しなければなりません (MUST)。HTTP 間ゲートウェイは、各インバウンドリクエストメッセージに適切な Via ヘッダーフィールドを送信しなければならず (MUST)、転送するレスポンスメッセージに Via ヘッダーフィールドを送信してもかまいません (MAY)。

各仲介者について、received-protocol は、メッセージの上流の送信者が使用したプロトコルとプロトコルバージョンを示します。したがって、Via のフィールド値は、リクエスト/レスポンス連鎖の通知されたプロトコル能力を記録し、それらが下流の受信者に見えるようにします。これは、セクション 2.6 で説明されているように、応答または後のリクエストで使用しても安全な後方互換でない機能を判断するのに役立ちます。簡潔にするため、受信したプロトコルが HTTP である場合、protocol-name は省略されます。

フィールド値の received-by の部分は、通常、その後にメッセージを転送した受信者サーバーまたはクライアントのホストと任意のポート番号です。しかしながら、実際のホストが機密情報と見なされる場合、送信者はそれを仮名で置き換えてもかまいません (MAY)。ポートが提供されていない場合、受信者は、それを received-protocol のデフォルト TCP ポート (存在する場合) で受信されたことを意味すると解釈してもかまいません (MAY)。

送信者は、User-Agent および Server ヘッダーフィールドに類似して、各受信者のソフトウェアを識別するために Via ヘッダーフィールドにコメントを生成してもかまいません (MAY)。ただし、Via フィールド内のすべてのコメントは任意であり、受信者はメッセージを転送する前にそれらを除去してもかまいません (MAY)。

たとえば、リクエストメッセージが、HTTP/1.0 のユーザーエージェントから、"fred" というコード名の内部プロキシに送信され、それが HTTP/1.1 を使用してリクエストを p.example.net の公開プロキシに転送し、それがリクエストを www.example.com のオリジンサーバーに転送することによって完了する場合があります。そのとき www.example.com が受信するリクエストは、次の Via ヘッダーフィールドを持つことになります:

Via: 1.0 fred, 1.1 p.example.net

ネットワークファイアウォールを通じたポータルとして使用される仲介者は、明示的に有効化されていない限り、ファイアウォール領域内のホストの名前とポートを転送すべきではありません (SHOULD NOT)。有効化されていない場合、そのような仲介者は、ファイアウォールの背後にある任意のホストの received-by ホストを、そのホストの適切な仮名で置き換えるべきです (SHOULD)。

仲介者は、Via ヘッダーフィールドのエントリの順序付けられた部分列を、それらのエントリが同一の received-protocol 値を持つ場合、単一のそのようなエントリに結合してもかまいません (MAY)。例えば、

Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy

は、次のように折りたたむことができます

Via: 1.0 ricky, 1.1 mertz, 1.0 lucy

送信者は、すべてが同じ組織の管理下にあり、ホストが既に仮名で置き換えられていない限り、複数のエントリを結合すべきではありません (SHOULD NOT)。送信者は、異なる received-protocol 値を持つエントリを結合してはなりません (MUST NOT)。

5.7.2. 変換​

一部の仲介者は、メッセージとそのペイロードを変換する機能を含みます。たとえばプロキシは、キャッシュ空間を節約したり、低速なリンク上のトラフィック量を削減したりするために、画像形式間の変換を行う場合があります。しかしながら、これらの変換が、医用画像や科学データ解析など、重要なアプリケーションを対象とするペイロードに適用されると、特に受信したペイロードが元のものと同一であることを保証するために整合性チェックやデジタル署名が使用されている場合、運用上の問題が生じる可能性があります。

HTTP 間プロキシは、意味的に有意な方法でメッセージを変更するように (すなわち、通常の HTTP 処理によって要求されるものを超え、元の送信者にとって重要であるか、下流の受信者にとって潜在的に重要であるような方法でメッセージを変更する修正) 設計または構成されている場合、"変換プロキシ" (transforming proxy) と呼ばれます。たとえば、変換プロキシは、共有注釈サーバー (ローカルの注釈データベースへの参照を含めるようにレスポンスを修正する)、マルウェアフィルター、形式トランスコーダー、またはプライバシーフィルターとして動作する場合があります。そのような変換は、そのプロキシを選択したクライアント (またはクライアント組織) によって望まれていると推定されます。

プロキシが、完全修飾ドメイン名でないホスト名を持つ request-target を受信した場合、リクエストを転送するときに、受信したホスト名に自身のドメインを追加してもかまいません (MAY)。プロキシは、request-target が完全修飾ドメイン名を含む場合、ホスト名を変更してはなりません (MUST NOT)。

プロキシは、空のパスを "/" または "*" で置き換えるために上記で述べた場合を除き、受信した request-target の "absolute-path" および "query" の部分を、次のインバウンドサーバーに転送するときに変更してはなりません (MUST NOT)。

プロキシは、転送コーディング (セクション 4) の適用または除去によってメッセージ本文を変更してもかまいません (MAY)。

プロキシは、no-transform キャッシュ制御ディレクティブ ([RFC7234] のセクション 5.2) を含むメッセージのペイロード ([RFC7231] のセクション 3.3) を変換してはなりません (MUST NOT)。

プロキシは、no-transform キャッシュ制御ディレクティブを含まないメッセージのペイロードを変換してもかまいません (MAY)。ペイロードを変換するプロキシは、warn-code 214 ("Transformation Applied") の Warning ヘッダーフィールドがメッセージにまだ存在しない場合、それを追加しなければなりません (MUST) ([RFC7234] のセクション 5.5 を参照してください)。200 (OK) レスポンスのペイロードを変換するプロキシは、レスポンスのステータスコードを 203 (Non-Authoritative Information) に変更することによって、変換が適用されたことを下流の受信者にさらに通知できます ([RFC7231] のセクション 6.3.4)。

プロキシは、通信連鎖の端点、リソースの状態、または (ペイロード以外の) 選択された表現に関する情報を提供するヘッダーフィールドを、そのフィールドの定義がそのような修正を明示的に許可しているか、その修正がプライバシーまたはセキュリティのために必要と見なされる場合を除き、変更すべきではありません (SHOULD NOT)。