6. 接続管理
HTTP メッセージングは、基盤となるトランスポート層またはセッション層の接続プロトコルから独立しています。HTTP は、リクエストの順序通りの配信と、それに対応するレスポンスの順序通りの配信を伴う信頼性のあるトランスポートのみを前提としています。HTTP リクエストとレスポンスの構造の、基盤となるトランスポートプロトコルのデータユニットへのマッピングは、本仕様の範囲外です。
セクション 5.2 で説明されているように、HTTP の対話に使用される具体的な接続プロトコルは、クライアント構成とターゲット URI によって決定されます。たとえば、"http" URI スキーム (セクション 2.7.1) は、デフォルトの TCP ポート 80 を伴う、IP 上の TCP のデフォルト接続を示しますが、クライアントは他の接続、ポート、またはプロトコルを介してプロキシを使用するように構成されている場合があります。
HTTP 実装は、接続管理を行うことが期待されます。これには、現在の接続の状態の維持、新しい接続の確立または既存の接続の再利用、接続で受信したメッセージの処理、接続障害の検出、および各接続の閉鎖が含まれます。ほとんどのクライアントは、複数の接続を並行して維持し、サーバーエンドポイントごとに複数の接続を維持することもあります。ほとんどのサーバーは、数千の同時接続を維持しつつ、リクエストキューを制御して公平な使用を可能にし、サービス拒否攻撃を検出するように設計されています。
6.1. Connection
"Connection" ヘッダーフィールドにより、送信者は現在の接続に対して望ましい制御オプションを示すことができます。下流の受信者を混乱させないために、プロキシまたはゲートウェイは、メッセージを転送する前に、受信した任意の接続オプションを除去または置き換えなければなりません (MUST)。
Connection 以外のヘッダーフィールドが、現在の接続のための、または現在の接続に関する制御情報を提供するために使用される場合、送信者は、対応するフィールド名を Connection ヘッダーフィールド内に列挙しなければなりません (MUST)。プロキシまたはゲートウェイは、メッセージが転送される前に、受信した Connection ヘッダーフィールドを解析し、このフィールド内の各 connection-option について、connection-option と同じ名前を持つ任意のヘッダーフィールドをメッセージから除去し、その後 Connection ヘッダーフィールド自体を除去しなければなりません (MUST) (または、転送するメッセージについて、仲介者自身の接続オプションで置き換えなければなりません)。
したがって、Connection ヘッダーフィールドは、直近の受信者のみを対象とするヘッダーフィールド ("hop-by-hop") と、連鎖上のすべての受信者を対象とするフィールド ("end-to-end") とを区別する宣言的な方法を提供し、メッセージを自己記述的にし、将来の接続固有の拡張が、古い仲介者によって盲目的に転送される心配なく配備できるようにします。
Connection ヘッダーフィールドの値は、次の文法を持ちます:
Connection = 1#connection-option
connection-option = token
接続オプションは大文字と小文字を区別しません。
送信者は、ペイロードのすべての受信者を対象とするヘッダーフィールドに対応する接続オプションを送信してはなりません (MUST NOT)。たとえば、Cache-Control は接続オプションとして適切ではありません ([RFC7234] のセクション 5.2)。
接続オプションは、メッセージに存在するヘッダーフィールドに常に対応するわけではありません。接続オプションに関連付けられたパラメータがない場合、接続固有のヘッダーフィールドは不要かもしれないためです。対照的に、対応する接続オプションなしで受信された接続固有のヘッダーフィールドは、通常、そのフィールドが仲介者によって不適切に転送されたことを示しており、受信者によって無視されるべきです。
新しい接続オプションを定義するとき、仕様の作成者は、既存のヘッダーフィールド名を調査し、新しい接続オプションが、既に配備されているヘッダーフィールドと同じ名前を共有しないことを保証すべきです。新しい接続オプションを定義することは、本質的に、その潜在的なフィールド名を、接続オプションに関連する追加情報を運ぶために予約することになります。送信者がそのフィールド名を他の何かのために使用するのは賢明ではないためです。
"close" 接続オプションは、送信者が、この接続がレスポンスの完了後に閉じられることを通知するために定義されています。例えば、
Connection: close
は、リクエストまたはレスポンスのヘッダーフィールドのいずれかにおいて、送信者が現在のリクエスト/レスポンスの完了後に接続を閉じようとしていることを示します (セクション 6.6)。
持続的接続をサポートしないクライアントは、すべてのリクエストメッセージで "close" 接続オプションを送信しなければなりません (MUST)。
持続的接続をサポートしないサーバーは、1xx (Informational) ステータスコードを持たないすべてのレスポンスメッセージで "close" 接続オプションを送信しなければなりません (MUST)。
6.2. 接続の確立
接続がさまざまなトランスポート層またはセッション層のプロトコルを介してどのように確立されるかを記述することは、本仕様の範囲外です。各接続は、1 つのトランスポートリンクのみに適用されます。
6.3. 持続性
HTTP/1.1 は、デフォルトで "持続的接続" (persistent connections) の使用を採用し、単一の接続を介して複数のリクエストとレスポンスを運ぶことを可能にします。"close" 接続オプションは、現在のリクエスト/レスポンスの後に接続が持続しないことを通知するために使用されます。HTTP 実装は、持続的接続をサポートすべきです (SHOULD)。
受信者は、最も最近受信したメッセージのプロトコルバージョンと Connection ヘッダーフィールド (存在する場合) に基づいて、接続が持続的かどうかを判断します:
-
"close" 接続オプションが存在する場合、接続は現在のレスポンスの後に持続しません。そうでなければ、
-
受信したプロトコルが HTTP/1.1 (またはそれ以降) である場合、接続は現在のレスポンスの後に持続します。そうでなければ、
-
受信したプロトコルが HTTP/1.0 であり、"keep-alive" 接続オプションが存在し、受信者がプロキシでなく、受信者が HTTP/1.0 の "keep-alive" 機構を尊重したい場合、接続は現在のレスポンスの後に持続します。そうでなければ、
-
接続は現在のレスポンスの後に閉じられます。
クライアントは、"close" 接続オプションを送信または受信するか、"keep-alive" 接続オプションのない HTTP/1.0 レスポンスを受信するまで、持続的接続で追加のリクエストを送信してもかまいません (MAY)。
持続性を保つために、接続上のすべてのメッセージは、自己定義されたメッセージ長 (すなわち、接続の閉鎖によって定義されない長さ) を持つ必要があります (セクション 3.3 で説明)。サーバーは、リクエストメッセージ本文全体を読み込むか、レスポンスを送信した後に接続を閉じなければなりません (MUST)。そうしないと、持続的接続上の残りのデータが次のリクエストとして誤って解釈されるためです。同様に、クライアントは、同じ接続を後続のリクエストに再利用するつもりである場合、レスポンスメッセージ本文全体を読み込まなければなりません (MUST)。
プロキシサーバーは、HTTP/1.0 クライアントとの持続的接続を維持してはなりません (MUST NOT) (多くの HTTP/1.0 クライアントによって実装されている Keep-Alive ヘッダーフィールドの問題に関する情報と考察については、[RFC2068] のセクション 19.7.1 を参照してください)。
HTTP/1.0 クライアントとの後方互換性の詳細については、付録 A.1.2 を参照してください。
6.3.1. リクエストの再試行
接続は、意図の有無にかかわらず、いつでも閉じられる可能性があります。実装は、非同期の閉鎖イベントから復旧する必要性を想定すべきです。
インバウンド接続が時期尚早に閉じられた場合、クライアントは、中断された一連のリクエストのすべてがべき等なメソッド ([RFC7231] のセクション 4.2.2) を持つならば、新しい接続を開き、自動的に再送信してもかまいません (MAY)。プロキシは、べき等でないリクエストを自動的に再試行してはなりません (MUST NOT)。
ユーザーエージェントは、メソッドにかかわらずリクエストのセマンティクスが実際にべき等であることを知る何らかの手段、または元のリクエストが適用されなかったことを検出する何らかの手段を持たない限り、べき等でないメソッドを持つリクエストを自動的に再試行してはなりません (MUST NOT)。たとえば、(設計または構成によって) 所与のリソースへの POST リクエストが安全であることを知っているユーザーエージェントは、そのリクエストを自動的に繰り返すことができます。同様に、バージョン管理リポジトリを操作するために特別に設計されたユーザーエージェントは、失敗した接続の後でターゲットリソースのリビジョンを確認し、部分的に適用された変更を元に戻すか修正し、その後、失敗したリクエストを自動的に再試行することによって、部分的な障害状態から復旧できる場合があります。
クライアントは、失敗した自動再試行を自動的に再試行すべきではありません (SHOULD NOT)。
6.3.2. パイプライン化
持続的接続をサポートするクライアントは、そのリクエストを "パイプライン化" (pipeline) してもかまいません (MAY) (すなわち、各レスポンスを待たずに複数のリクエストを送信します)。サーバーは、パイプライン化された一連のリクエストがすべて安全なメソッド ([RFC7231] のセクション 4.2.1) を持つ場合、それらを並行して処理してもかまいません (MAY) が、対応するレスポンスをリクエストを受信したのと同じ順序で送信しなければなりません (MUST)。
リクエストをパイプライン化するクライアントは、すべての対応するレスポンスを受信する前に接続が閉じた場合、未応答のリクエストを再試行すべきです (SHOULD)。失敗した接続 (サーバーが最後の完全なレスポンスで明示的に閉じなかった接続) の後にパイプライン化されたリクエストを再試行するとき、クライアントは接続確立直後にパイプライン化してはなりません (MUST NOT)。先行するパイプライン内の最初の残りのリクエストが、エラーレスポンスを引き起こした可能性があり、それが、時期尚早に閉じられた接続で複数のリクエストが送信されると再び失われる可能性があるためです (セクション 6.6 で説明されている TCP リセット問題を参照してください)。
べき等なメソッド ([RFC7231] のセクション 4.2.2) は、接続障害の後に自動的に再試行できるため、パイプライン化にとって重要です。ユーザーエージェントは、パイプライン化された系列を含む部分的な障害状態を検出して復旧する手段を持たない限り、べき等でないメソッドの後に、そのメソッドの最終的なレスポンスステータスコードを受信するまで、リクエストをパイプライン化すべきではありません (SHOULD NOT)。
パイプライン化されたリクエストを受信した仲介者は、それらをインバウンドに転送するときにそれらのリクエストをパイプライン化してもかまいません (MAY)。どのリクエストを安全にパイプライン化できるかを判断するために、アウトバウンドのユーザーエージェントに依存できるためです。レスポンスを受信する前にインバウンド接続が失敗した場合、パイプライン化する仲介者は、リクエストがすべてべき等なメソッドを持つならば、まだレスポンスを受信していないリクエストの系列の再試行を試みてもかまいません (MAY)。そうでない場合、パイプライン化する仲介者は、受信した任意のレスポンスを転送してから、対応するアウトバウンド接続を閉じるべきであり (SHOULD)、そうすればアウトバウンドのユーザーエージェントが適宜復旧できます。
6.4. 並行性
クライアントは、所与のサーバーに対して維持する同時オープン接続の数を制限すべきです。
HTTP の以前の改訂では、上限として特定の接続数が与えられていましたが、これは多くのアプリケーションにとって非現実的であることが判明しました。その結果、本仕様は特定の最大接続数を義務付けず、代わりに、複数の接続を開くときにクライアントが控えめであることを奨励しています。
複数の接続は、通常、"ヘッドオブラインブロッキング" 問題 (サーバー側の処理に時間がかかり、かつ/または大きなペイロードを持つリクエストが、同じ接続上の後続のリクエストをブロックする問題) を回避するために使用されます。しかしながら、各接続はサーバーのリソースを消費します。さらに、複数の接続を使用すると、輻輳したネットワークで望ましくない副作用を引き起こす可能性があります。
サーバーは、単一のクライアントからの過剰な数のオープン接続など、濫用的であるかサービス拒否攻撃の特徴であると見なすトラフィックを拒否する場合があることに注意してください。
6.5. 障害とタイムアウト
サーバーは通常、それを超えると非アクティブな接続を維持しなくなる何らかのタイムアウト値を持ちます。プロキシサーバーは、クライアントが同じプロキシサーバーを通じてより多くの接続を行う可能性が高いため、これをより高い値にする場合があります。持続的接続の使用は、クライアントとサーバーのいずれに対しても、このタイムアウトの長さ (または存在) に要件を課しません。
タイムアウトさせたいと望むクライアントまたはサーバーは、接続上で円滑な閉鎖を発行すべきです (SHOULD)。実装は、受信した閉鎖シグナルについてオープン接続を常に監視し、それに適切に応答すべきです (SHOULD)。接続の両側の迅速な閉鎖により、割り当てられたシステムリソースを回収できるためです。
クライアント、サーバー、またはプロキシは、いつでもトランスポート接続を閉じてもかまいません (MAY)。たとえば、クライアントが新しいリクエストの送信を開始したのと同時に、サーバーが "アイドル" 接続を閉じることを決定した場合があります。サーバーの観点では、接続はアイドル状態のときに閉じられていますが、クライアントの観点では、リクエストが進行中です。
サーバーは、可能な場合、持続的接続を維持し (SHOULD)、クライアントが再試行することを期待して接続を終了するのではなく、基盤となるトランスポートのフロー制御機構に一時的な過負荷を解決させるべきです。後者の技法は、ネットワーク輻輳を悪化させる可能性があります。
メッセージ本文を送信するクライアントは、リクエストを送信している間、ネットワーク接続でエラーレスポンスを監視すべきです (SHOULD)。クライアントが、サーバーがメッセージ本文を受信することを望んでおらず接続を閉じようとしていることを示すレスポンスを見た場合、クライアントは直ちに本文の送信を中止し、接続の自身の側を閉じるべきです (SHOULD)。
6.6. 切断
Connection ヘッダーフィールド (セクション 6.1) は、"close" 接続オプションを提供し、送信者は、現在のリクエスト/レスポンスの組の後に接続を閉じたいときにそれを送信すべきです (SHOULD)。
"close" 接続オプションを送信するクライアントは、その接続で (それを含むリクエストの後に) それ以上のリクエストを送信してはならず (MUST NOT)、このリクエストに対応する最終レスポンスメッセージを読み込んだ後に接続を閉じなければなりません (MUST)。
"close" 接続オプションを受信したサーバーは、"close" を含んでいたリクエストへの最終レスポンスを送信した後に、接続の閉鎖 (下記参照) を開始しなければなりません (MUST)。サーバーは、その接続上の最終レスポンスで "close" 接続オプションを送信すべきです (SHOULD)。サーバーは、その接続で受信したそれ以上のリクエストを処理してはなりません (MUST NOT)。
"close" 接続オプションを送信するサーバーは、"close" を含むレスポンスを送信した後に、接続の閉鎖 (下記参照) を開始しなければなりません (MUST)。サーバーは、その接続で受信したそれ以上のリクエストを処理してはなりません (MUST NOT)。
"close" 接続オプションを受信したクライアントは、その接続でのリクエストの送信を中止し、"close" を含むレスポンスメッセージを読み込んだ後に接続を閉じなければなりません (MUST)。追加のパイプライン化されたリクエストがその接続で送信されていた場合、クライアントは、それらがサーバーによって処理されると想定すべきではありません (SHOULD NOT)。
サーバーが TCP 接続の即時閉鎖を実行する場合、クライアントが最後の HTTP レスポンスを読み込めないという重大なリスクがあります。サーバーが完全に閉じられた接続でクライアントから追加データ (例えば、サーバーのレスポンスを受信する前にクライアントが送信した別のリクエスト) を受信した場合、サーバーの TCP スタックはクライアントにリセットパケットを送信します。残念ながら、そのリセットパケットは、クライアントの HTTP パーサーがそれを読み込んで解釈する前に、クライアントの未確認の入力バッファを消去する可能性があります。
TCP リセット問題を回避するために、サーバーは通常、段階的に接続を閉じます。まず、サーバーは、読み書き接続の書き込み側のみを閉じることによって、ハーフクローズを実行します。次にサーバーは、クライアントから対応する閉鎖を受信するまで、またはサーバー自身の TCP スタックがサーバーの最後のレスポンスを含むパケットに対するクライアントの確認応答を受信したと合理的に確信するまで、接続からの読み込みを続けます。最後に、サーバーは接続を完全に閉じます。
リセット問題が TCP に固有のものであるのか、他のトランスポート接続プロトコルにも見られる可能性があるのかは不明です。
6.7. Upgrade
"Upgrade" ヘッダーフィールドは、同じ接続上で HTTP/1.1 から他の何らかのプロトコルへ移行するための単純な機構を提供することを意図しています。クライアントは、最終レスポンスを送信する前に、サーバーを 1 つ以上のそれらのプロトコルに切り替えるよう誘うために、優先度の降順で、リクエストの Upgrade ヘッダーフィールドにプロトコルのリストを送信してもかまいません (MAY)。サーバーは、その接続で現在のプロトコルを使用し続けたいと望む場合、受信した Upgrade ヘッダーフィールドを無視してもかまいません (MAY)。Upgrade は、プロトコル変更を強要するために使用することはできません。
Upgrade = 1#protocol
protocol = protocol-name ["/" protocol-version]
protocol-name = token
protocol-version = token
101 (Switching Protocols) レスポンスを送信するサーバーは、接続が切り替えられている新しいプロトコルを示すために Upgrade ヘッダーフィールドを送信しなければなりません (MUST)。複数のプロトコル層が切り替えられている場合、送信者はそれらのプロトコルを層の昇順で列挙しなければなりません (MUST)。サーバーは、対応するリクエストの Upgrade ヘッダーフィールドでクライアントによって示されなかったプロトコルに切り替えてはなりません (MUST NOT)。サーバーは、クライアントによって示された優先順位を無視し、リクエストの性質やサーバーの現在の負荷など他の要因に基づいて新しいプロトコルを選択してもかまいません (MAY)。
426 (Upgrade Required) レスポンスを送信するサーバーは、許容可能なプロトコルを優先度の降順で示すために Upgrade ヘッダーフィールドを送信しなければなりません (MUST)。
サーバーは、その他の任意のレスポンスで Upgrade ヘッダーフィールドを送信して、将来のリクエストにとって適切なときに、列挙されたプロトコルへのアップグレードのサポートを (優先度の降順で) 通知してもかまいません (MAY)。
以下は、クライアントによって送信される仮想的な例です:
GET /hello.txt HTTP/1.1
Host: www.example.com
Connection: upgrade
Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
プロトコル変更後のアプリケーション層通信の能力と性質は、選択された新しいプロトコルに完全に依存します。しかしながら、101 (Switching Protocols) レスポンスを送信した直後に、サーバーは、新しいプロトコル内でその等価物を受信したかのように元のリクエストに応答し続けることが期待されます (すなわち、サーバーは、プロトコルが変更された後も、満たすべき未処理のリクエストをまだ持っており、リクエストを繰り返すことを要求することなくそれを満たすことが期待されます)。
たとえば、Upgrade ヘッダーフィールドが GET リクエストで受信され、サーバーがプロトコルを切り替えることを決定した場合、サーバーはまず HTTP/1.1 で 101 (Switching Protocols) メッセージで応答し、その後直ちに、ターゲットリソースに対する GET へのレスポンスの新しいプロトコルでの等価物を続けます。これにより、追加のラウンドトリップのレイテンシコストなしに、接続を HTTP と同じセマンティクスを持つプロトコルにアップグレードできます。サーバーは、受信したメッセージのセマンティクスが新しいプロトコルで尊重され得ない限り、プロトコルを切り替えてはなりません (MUST NOT)。OPTIONS リクエストは任意のプロトコルで尊重できます。
以下は、上記の仮想的なリクエストへのレスポンスの例です:
HTTP/1.1 101 Switching Protocols
Connection: upgrade
Upgrade: HTTP/2.0
[... data stream switches to HTTP/2.0 with an appropriate response
(as defined by new protocol) to the "GET /hello.txt" request ...]
Upgrade が送信される場合、送信者は、列挙されたプロトコルを実装していない可能性のある仲介者によって Upgrade が誤って転送されるのを防ぐために、"upgrade" 接続オプションを含む Connection ヘッダーフィールド (セクション 6.1) も送信しなければなりません (MUST)。サーバーは、HTTP/1.0 リクエストで受信した Upgrade ヘッダーフィールドを無視しなければなりません (MUST)。
クライアントは、リクエストメッセージを完全に送信し終えるまで、接続上でアップグレードされたプロトコルを使用し始めることはできません (すなわち、クライアントはメッセージの途中で送信しているプロトコルを変更できません)。サーバーが Upgrade と、"100-continue" 期待値を持つ Expect ヘッダーフィールド ([RFC7231] のセクション 5.1.1) の両方を受信した場合、サーバーは 101 (Switching Protocols) レスポンスを送信する前に 100 (Continue) レスポンスを送信しなければなりません (MUST)。
Upgrade ヘッダーフィールドは、既存の接続の上でプロトコルを切り替える場合にのみ適用されます。基盤となる接続 (トランスポート) プロトコルを切り替えたり、既存の通信を別の接続に切り替えたりするために使用することはできません。それらの目的には、3xx (Redirection) レスポンス ([RFC7231] のセクション 6.4) を使用する方が適切です。
本仕様は、ハイパーテキスト転送プロトコル群が使用するプロトコル名 "HTTP" のみを、セクション 2.6 の HTTP バージョンルールおよび本仕様への将来の更新によって定義されるとおりに定義します。追加のトークンは、セクション 8.6 で定義された登録手順を使用して IANA に登録されるべきです。