LoginSignup
89
71

More than 1 year has passed since last update.

HTTP/3 (RFC 9114) をざっくり翻訳してみた (前編)

Last updated at Posted at 2022-06-12

HTTP/3 が IETF RFC 9114 としてきちんと標準化されました.これを機会に流し読みしようとしていたところ,気づいたらなぜか翻訳していたので,ここに共有します.RFC の翻訳とかしたことないので,生暖かい目でお読みください.

この記事はざっくり翻訳なので,翻訳の内容が正しいかは私にはわかりません.正しい内容が知りたいときは,原文 を読みに行ってください.とはいえ間違っていたら編集リクエストは大歓迎です.

この記事は前編です.さすがにボリュームが大きすぎたので前後編に分けました.後編はいつか書くかもしれないし書かないかもしれません.

1. 概要 (Introduction)

今まで HTTP/1.1 は多種多様なトランスポート・セッション層とともに,HTTP/2 は主に TLS on TCP で使われてきた.HTTP/3 は同じセマンティクスを新しいトランスポート・プロトコル QUIC でサポートする.

1.1. 前バージョンの HTTP (Prior Versions of HTTP)

HTTP/1.1 はホワイトスペースで区切られたテキストフィールドで HTTP メッセージを表現していた.これは人間にとって読みやすいが,パースすることの複雑さや挙動 (behaviour) の違いを招いた.

また HTTP/1.1 は多重化 (multiplexing) 機能を持たず,複数の TCP コネクションを平行して用いることでこれを実現していた.一方で,TCP が複数コネクション間で輻輳制御を共有できないことからネットワーク効率に負の影響を与えた.

HTTP/2 はトランスポート層を変えることなく遅延を減らすためにバイナリフレーミングと多重化レイヤを導入した.しかしながら,HTTP/2 の多重化は TCP のロスを回復する仕組みへ反映されないために,パケットのロスがすべてのアクティブなトランザクションへ影響するなどした.

1.2. QUIC への委譲 (Delegation to QUIC)

QUIC トランスポート・プロトコルは HTTP/2 のフレーミングレイヤで提供されたようなストリームの多重化とストリームごとのフロー制御を取り入れた.ストリームレベルで信頼性を提供することや,接続全体で輻輳制御を行うことで,QUIC は TCP へのマッピングに比べ HTTP のパフォーマンスを向上させられるようになった.さらに QUIC はトランスポート層で TLS 1.3 をも取り入れ,TLS over TCP に引けを取らない機密性や完全性を持てるようになった.

この文書では,大部分が HTTP/2 の設計による,HTTP セマンティクスの QUIC へのマッピングである, HTTP/3 を定義する.HTTP/3 はデータの機密性・完全性を保護すること,ピア認証,信頼できる・順の・ストリームごとの転送を QUIC によるものとする.ストリームの生存期間 (lifetime) とフロー制御の問題を QUIC へ委譲し,HTTP/2 のそれに似たバイナリフレーミングをそれぞれのストリームで用いる.いくつかの HTTP/2 の機能は QUIC に含まれ,他の機能は QUIC の上で実装される.

QUIC は QUIC-TRANSPORT で説明されている.また HTTP/2 の詳細は HTTP/2 を参照のこと.

訳注: HTTP/2 の RFC は RFC 7540 であったが,HTTP/3 の標準化とあわせて RFC 9113 に上書きされている.

2. HTTP/3 プロトコルの概要 (HTTP/3 Protocol Overview)

HTTP/3 は HTTP/2 に似た内部フレーミングレイヤと HTTP セマンティクスの QUIC による転送を提供する.

クライアントはあるエンドポイントに HTTP/3 サーバがあることを知ると,QUIC コネクションを開く.QUIC はプロトコルのネゴシエーション,ストリームベースの多重化,そしてフロー制御を提供する.HTTP/3 エンドポイントの発見 (discovery) については 3.1 章で説明する.

各フレーム内において,HTTP/3 通信の基本単位はフレームである (7.2 章).それぞれのフレームタイプは別の目的を満たす.たとえば,HEADERS フレームと DATA フレームはそれぞれ HTTP リクエストとレスポンスを表す (4.1 章).接続全体に反映するフレームは専用の (dedicated) 制御用ストリームで送信される.

リクエストの多重化は,QUIC-TRANSPORT の 2 章で説明されている QUIC ストリームによって行われる.リクエスト・レスポンスの 1 ペアが QUIC の 1 ストリームを使う.これはネットワークの利用率と発生する遅延のトレードオフとなる.いくらかの HTTP/3 フレームは PUSH_PROMISE, MAX_PUSH_ID, CANCEL_PUSH のようなサーバプッシュを管理するために使われる.

HTTP/2 のように,リクエスト・レスポンスのフィールドは転送に際し圧縮される. HPACK (HPACK) が圧縮されたフィールドセクションが順に転送されることを前提にするため (これは QUIC によって保証されない),HTTP/3 は HPACK を QPACK (QPACK) によって置換する.QPACK は別の単方向ストリームをフィールドテーブルの状態を変更・追跡するために使い,エンコードされたフィールドセクションはテーブルの状態を変更せずに参照する.

2.1. 文書の構成 (Document Organization)

これらのセクションは HTTP/3 のライフサイクルに対する詳しい概論を提供する:

  • 「接続のセットアップと管理 (”Connection Setup and Management”)」 (3 章) では HTTP/3 エンドポイントがどのように発見され接続が確立されるかを説明する.
  • 「HTTP/3 での HTTP セマンティクス (”Expressing HTTP Semantics in HTTP/3”)」 (4 章) では HTTP セマンティクスがどのようにフレームで表されるかを説明する.
  • 「接続の終了 (”Connection Closure”)」 (5 章) では HTTP/3 接続がどのようにして正常または異常に終了されるかを説明する.

実際のプロトコルとトランスポートによる作用についての詳細は,以下のセクションで説明される:

  • 「ストリームのマッピングと利用 (”Stream Mapping and Usage”)」 (6 章) では QUIC ストリームがどのように使われるかを説明する.
  • 「HTTP フレーミングレイヤ (”HTTP Framing Layer”)」 (7 章) ではストリームで使われるフレームを説明する.
  • 「エラーハンドリング (”Error Handling”)」 (8 章) ではストリームおよび接続全体のエラー条件がどのように表現され,扱われるかを説明する.

追加の情報は最後のセクションで提供される:

  • 「HTTP/3 の拡張 (”Extensions to HTTP/3”)」 (9 章) では将来の文書で新しい機能がどのように追加できるかを説明する.
  • HTTP/2 と HTTP/3 の詳細な比較は 付録 A にある.

2.2. 用語の定義 (Conventions and Terminology)

この文書において “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMEND”, “MAY”, “OPTIONAL” の語が用いられたときは BCP 14, RFC 2119, RFC 8174 で示されるように解釈する.

この文書は QUIC-TRANSPORT による可変長整数エンコーディングを用いる.

以下の語が使われる:

中断 (abort): 主にエラー条件による接続またはストリームの異常終了.

クライアント (client): HTTP/3 接続を初期化するエンドポイント.クライアントが HTTP リクエストを送信して HTTP レスポンスを受け取る.

接続 (connection): QUIC をトランスポート・プロトコルとして用いる,2 エンドポイント間のトランスポート層の接続.

接続エラー (connection error): HTTP/3 接続の全体に影響するエラー.

エンドポイント (endpoint): 接続におけるクライアントまたはサーバ.

フレーム (frame): フレームタイプによって構造化された,可変長のバイト列をヘッダと共に扱う,HTTP/3 ストリームでの通信の最小単位.
プロトコル要素のフレームはこの文書と QUIC-TRANSPORT の存在する.QUIC-TRANSPORT のフレームを参照するときは,フレームの名前に “QUIC の” をつける.たとえば, “QUIC の CONNECTION_CLOSE フレーム” のようになる.これ以外のフレームについては 7.2 章で定義される通りとなる.

HTTP/3 接続 (HTTP/3 connection): アプリケーション・プロトコルが HTTP/3 でネゴシエーションされた QUIC 接続.

ピア (peer): エンドポイント.特定のエンドポイントについて議論するとき,その主語となるものの他方 (remote) のエンドポイントを指す.

受信者 (receiver): フレームを受け取るエンドポイント.

送信者 (sender): フレームを送信するエンドポイント.

サーバ (server): HTTP/3 接続を受け入れるエンドポイント.サーバは HTTP リクエストを受け取って HTTP レスポンスを送信する.

ストリーム (stream): QUIC によって提供される双方向または単方向のバイトストリーム.HTTP/3 におけるすべてのストリームは “HTTP/3 ストリーム” であるといえるが,HTTP/3 では複数のフレームタイプが定義されている.

ストリームエラー (stream error): 個別のストリームにおけるアプリケーションレベルのエラー.

用語「コンテンツ (“content”)」は HTTP の 6.4 章で定義される.

最後に,「リソース (”resource”)」「メッセージ (”message”)」「ユーザエージェント (”user agent”)」「オリジンサーバ (”origin server”)」「ゲートウェイ (”gateway”)」「中継 (”intermediary”)」「プロキシ (”proxy”)」「トンネル (”tunnel”)」の語は HTTP の 3 章で定義される.

この文書におけるパケット図はフィールドの順番とサイズを図示するために QUIC-TRANSPORT の 1.3 章で定義される書式を利用している.

3. 接続のセットアップと管理 (Connection Setup and Management)

3.1. HTTP/3 エンドポイントの発見 (Discovering an HTTP/3 Endpoint)

HTTP は,ターゲット URI によって識別されたオリジンサーバ (またはその側) がレスポンスメッセージを構成したときに,ターゲットリソースの状態から最も適当と判断されたレスポンス (権威のあるレスポンス) を信頼する.HTTP URI から権威のあるサーバを導く方法は HTTP の 4.3 章で議論される.

“https” スキームを使うと,クライアントは,URI の authority コンポーネントによって識別されるホストが信頼に値するかを証明書の所有によって考慮する.TLS ハンドシェイクでサーバ証明書を受け取った上で.クライアントはその証明書が URI のオリジンサーバと一致するかを HTTP の 4.3.4 章で説明されるように検証しなければならない (MUST).URI のオリジンサーバに対して証明書が正しいと検証できなかった場合,そのオリジンに対してサーバが権威をもつと解釈してはいけない (MUST NOT).

クライアントは, ホスト識別子から IP アドレスに解決して指定されたポートへ QUIC 接続を確立し (先述の通りサーバ証明書の検証を行った上で),当該 URI をターゲットとした HTTP/3 リクエストメッセージをその接続上で送信することによって,“https” URI によるリソースへのアクセスを試みることもできる (MAY) .何らかの仕組みによって HTTP/3 が選択されない場合,TLS ハンドシェイク拡張における Application-Layer Protocol Negotiation (ALPN; RFC 7301) の “h3” トークンを使う.

接続上の問題 (例えば UDP のブロック) が QUIC 接続の確立を失敗させることがあり,クライアントはこの場合 TCP ベースの HTTP 接続を試すべきである (SHOULD) .

サーバは HTTP/3 を任意の UDP ポートで提供でき (MAY) ,代替のサービス広告は常に指定されたポートを含み,URI はスキームに紐付けられた既定のポートまたは指定されたポートを含む.

3.1.1 HTTP 代替サービス (HTTP Alternative Services)

HTTP オリジンは HTTP/3 エンドポイントと等価な代替が利用可能であることを Alt-Svc HTTP レスポンスヘッダや HTTP/2 の ALTSVC フレーム (ALTSVC) で広告することがを “h3” ALPN トークンを使うことによってできる.

例えば,同じホストネームの UDP ポート 50781 で HTTP/3 が有効であることを,オリジンは以下のヘッダフィールドによって示せる:

Alt-Svc: h3=":50781"

3.1.2. その他のスキーム (Other Schemes)

HTTP はトランスポート・プロトコルに依存しないため,”http” スキームでは, authority コンポーネントが示す任意のホストの指定されたポートにおける権威を,TCP 接続を受け付けられるかで判断する.HTTP/3 は TCP を使わないため,“http” URI で識別されるリソースの権威を持つサーバへ直接アクセスすることは,HTTP/3 ではできない.しかし,ALTSVC のようなプロトコル拡張を使うことで,権威を持つサーバは,HTTP/3 によって疎通でき権威を持つ他のサービスを示せる.

“https” ではないスキームでオリジンへのリクエストを作る前に,クライアントはサーバがそのスキームを扱うことを確実にしなければならない (MUST) .スキームが “http” のオリジンについては,これを満たすための試験的な方法が RFC 8164 によって説明されている.将来的に,多様なスキーマのための仕組みが定義されるかもしれない.

3.2. 接続の確立

HTTP/3 はトランスポートの根幹 (underlying transport) に QUIC バージョン 1 を用いる.将来の仕様によって, HTTP/3 による他の QUIC バージョンの利用を定義することができる (MAY) .

QUIC バージョン 1 は TLS 1.3 以降をハンドシェイク・プロトコルとして用いる.HTTP/3 クライアントは TLS ハンドシェイクに際してターゲットとなるホストを示す仕組みをサポートしなければならない (MUST) .サーバがドメイン名 (DNS-TERMS) によって識別される場合,クライアントは Server Name Indication (SNI; RFC 6066) TLS 拡張またはその代替となる仕組みを使ってターゲット・ホストを示す必要がある (MUST) .

QUIC 接続は QUIC-TRANSPORT で説明されるように確立される.接続の確立の間に,ALPN トークン “h3” を TLS ハンドシェイクで選択することで HTTP/3 サポートが示される.同ハンドシェイクで,他のアプリケーション層プロトコルのサポートを提示することもできる (MAY) .

コアの QUIC プロトコルによる接続レベルのオプションは初期の暗号化ハンドシェイクに付与され,HTTP/3 に特有の設定については SETTING フレームで送信される.QUIC 接続が確立されたのち,HTTP 制御ストリームの初期フレームとしてそれぞれのエンドポイントから SETTINGS フレームを送信しなければならない (MUST) .

3.3. 接続の再利用

HTTP/3 接続は複数のリクエストをまたいで永続的である.最善のパフォーマンスを得るために,クライアントはサーバが接続を閉じるか,サーバとの通信がもう不要であると判断されるまで接続を閉じないことが期待される (例えば,ユーザが特定の Web ページから離れるとき).

サーバのエンドポイントへの接続が存在するとき,複数の違う URI authority コンポーネントを持つリクエストに対してこの接続は再利用できる (MAY) .既存の接続を新しいオリジンに利用するためには,クライアントは新しいオリジンサーバに対して,サーバの提供する証明書を HTTP の 4.3.4 章で説明されるように検証しなければならない (MUST) .クライアントは証明書の検証に必要なサーバ証明書および追加の情報を残す必要があることを意味し,そうでないクライアントは追加のオリジンに対して接続を再利用できない.

何らかの理由で新しいオリジンに対して証明書が受け入れられないとき,その接続は再利用してはならず (MUST NOT) ,新しいオリジンに対する新しい接続を確立するべきである (SHOULD) .証明書が検証できない理由は,その接続に紐付いた他のオリジンに適用される可能性があり,クライアントはそれらのオリジンにおいてサーバ証明書を再検証するべきである (SHOULD) .例えば,証明書が失効したまたは無効化 (revoke) されたことによって証明書の検証が失敗した場合,この理由はその証明書が権威の確立に用いられた他のすべてのオリジンを無効化する (invalidate) ために使われる可能性がある.

クライアントは,URI から IP アドレスとポートが導かれたり,代替サービス (ALTSVC) や設定されたプロキシ,名前解決などによって,与えられた IP アドレスと UDP ポートに対して 2 つ以上の HTTP/3 接続を開くべきではない (SHOULD NOT) .クライアントは同じ IP アドレスおよび UDP ポートに対しては違うトランスポートや TLS 設定を使うことで複数の接続を開始できるが,同じ設定によって複数の接続を作成することは避けるべきである (SHOULD) .

サーバはできるだけ長く HTTP/3 接続を開いたままにすることを奨励されるが,必要であれば待機中 (idle) の接続を切断 (terminate) することも許される.どちらかのエンドポイントが HTTP/3 接続を閉じることを選択するとき,切断する側のエンドポイントは最初に GOAWAY フレーム (5.2 章) を送信するべきで (SHOULD) ,これにより両者のエンドポイントはその前に送信されたフレームが処理されて全く問題なく完了していることを確実に導いたり,必要で残ったタスクを終了させたり (terminate) できる.

特定のオリジンに対して HTTP/3 接続が再利用されることを願わないサーバは,HTTP の 7.4 章のように,そのリクエストのレスポンスで 421 (Misdirected Request) ステータスコードを送信することでリクエストに対する権威がないことを示せる.

4. HTTP/3 での HTTP セマンティクス (Expressing HTTP Semantics in HTTP/3)

4.1. HTTP メッセージフレーミング (HTTP Message Framing)

クライアントは 6.1 章のように,クライアントが初期化した双方向の QUIC ストリームであるリクエスト・ストリームで HTTP リクエストを送信する.クライアントは与えられたストリームで 1 リクエストのみを送信しなければならない (MUST) .サーバは以下の詳細のように,0 以上の暫定的な HTTP レスポンスと 1 つの最終 HTTP レスポンスを同じストリームで送信できる.臨時および最終の HTTP レスポンスについては HTTP のセクション 15 を参照のこと.

プッシュされたレスポンスは,6.2.2 章のように,サーバが初期化した単方向の QUIC ストリームで送信される.サーバは通常のレスポンスのように,0 以上の暫定的な HTTP レスポンスと 1 つの最終 HTTP レスポンスを同じストリームで送信できる.プッシュは 4.6 章で詳細を説明される.

与えられたストリームにおいて,複数のリクエストや最終レスポンスの後のレスポンスの受信については不正として扱われなければならない (MUST) .

HTTP メッセージ (リクエストまたはレスポンス) は以下から成る:

  1. メッセージ制御データを含んだヘッダセクションが単体の HEADERS フレームとして送られ.
  2. コンテンツがあれば, DATA フレーム群として送られ,
  3. トレーラセクションがあれば,単体の HEADER フレームとして送られる.

ヘッダ・トレーラセクションについては HTTP の 6.3 および 6.5 章で説明され,コンテンツについては HTTP の 6.4 章で説明される.

不正なフレーム列の受信は H3_FRAME_UNEXPECTED の接続エラーとして扱わなければならない (MUST) .特に,HEADERS フレームの前の DATA フレームや,トレーラ HEADERS フレームの後の HEADERS または DATA フレームについては不正と考えられる.他のフレームタイプ,特に不明なフレームタイプについては,9 章のように,自身のルールに基づいて許可されることもある.

サーバはレスポンスメッセージの前後やフレーム間に 1 つ以上の PUSH_PROMISE フレームを送信できる (MAY) .この PUSH_PROMISE フレームは 4.6 章で述べる詳細のようにレスポンスの一部分ではない.プッシュストリームにおいて PUSH_PROMISE フレームは許可されておらず, PUSH_PROMISE フレームを含むプッシュレスポンスは H3_FRAME_UNEXPECTED の接続エラーとして扱わなければならない (MUST) .

予約されたフレーム (7.2.8 章) を含む不明なタイプのフレーム (9 章) はリクエストストリームやプッシュストリームにおいてこの章で説明された他のフレームの前後およびフレーム間に送信することができる (MAY) .

HEADERS および PUSH_PROMISE フレームは QPACK 動的テーブルの参照を更新させることがある.この更新は,直接的にはメッセージ交換の一部分ではなく,メッセージより前に受信され処理される必要がある.詳細は 4.2 章を参照のこと.

転送コーディング (HTTP/1.1 の 7 章) は HTTP/3 では定義されず,Transfer-Encoding ヘッダフィールドを利用してはならない (MUST NOT) .

同じリクエストに対し 1 以上の暫定的なレスポンス (1xx; HTTP の 15.2 章) によって最終レスポンスが導かれる場合にのみ,レスポンスは複数のメッセージから成ることができる (MAY) .暫定的なレスポンスはコンテンツおよびトレーラセクションを持たない.

HTTP リクエスト・レスポンスの交換は,クライアントが初期化した双方向の QUIC ストリームを完全に消費する.リクエストを送信したのち,クライアントは送信に使うストリームを閉じなければならない (MUST) .CONNECT メソッド (4.4 章) を使う場合を除いて,クライアントはリクエストに対するレスポンスへ依存してストリームを閉じてはならない (MUST NOT) .最終レスポンスを送信したのち,サーバは送信に使うストリームを閉じなければならない (MUST) .ここで,QUIC ストリームは完全に閉じられる.

ストリームが閉じられるとき,最終 HTTP メッセージの終わりを示す.いくつかのメッセージは大きいまたは無限であるため,処理に必要な HTTP メッセージの部分を受け取ったらその処理を始めるべきである (SHOULD) .クライアントの初期化したストリームが,レスポンスを完了するのに十分な HTTP メッセージなしに切断された場合,サーバはそのレスポンス・ストリームを H3_REQUEST_INCOMPLETE エラーコードで中断するべきである (SHOULD) .

レスポンスが,リクエストのうちまだ送受信されていない部分に依存しないとき,サーバはクライアントがすべてのリクエストを送信することを待たずして完全なレスポンスを送信できる.サーバがリクエストの残りを受信する必要のないときは,リクエスト・ストリームからの読み取りを終了し,完全なレスポンスを送信して,ストリームの送信側をきれいに閉じることができる (MAY) .クライアントにリクエスト・ストリームの送信の停止を要求したいときには H3_NO_ERROR エラーコードを使うべきである.クライアントはその裁量によっていつでもレスポンスを破棄できるが,リクエストが意図せず切断されたときに得られたレスポンスに限って破棄してはならない (MUST NOT) .サーバが部分的または完全なレスポンスを送信したがリクエストの読み取りを中断しないとき,クライアントはリクエスト内容の送信を続けて,通常通りストリームを閉じるべきである (SHOULD) .

4.1.1. リクエストのキャンセルと拒否

リクエスト・ストリームが開かれたのち,リクエストはどちらかのエンドポイントによってキャンセルすることができる (MAY) .クライアントはそのレスポンスに興味がなくなった場合にリクエストをキャンセルできるし,サーバはレスポンスしないまたはできないときにキャンセルできる.可能であれば,サーバは処理を開始したリクエストをキャンセルするのではなく,適当なステータスコードを持った HTTP レスポンスを送信することが推奨される (RECOMMENDED) .

未だ開いているストリームがどちらかによって突然切断されたとき,実装はリクエストをキャンセルするべきである (SHOULD) .QUIC-TRANSPORT の 2.4 章のように,ある実装はストリームの送信側をリセットして送信側からの読み取りを中断する.

サーバがアプリケーションの処理をされずにリクエストをキャンセルしたとき,このリクエストは “拒否された (rejected)” といえる.サーバはそのレスポンス・ストリームを H3_REQUEST_REJECTED エラーコードで中断するべきである (SHOULD) .このとき, “処理された” とはストリームからのデータがソフトウェアの上位層に渡されて何らかの操作がとられたことを意味する.クライアントはサーバによって拒否されたリクエストを何もしていないものと扱うことができ,後から再試行することを可能にする.

サーバは部分的にあるいは全部を処理したリクエストについて H3_REQUEST_REJECTED エラーコードを使ってはならない (MUST NOT) .サーバが部分的な処理を終えてレスポンスをやめるとき,そのレスポンス・ストリームを H3_REQUEST_CANCELLED で中断するべきである (SHOULD) .

クライアントはリクエストをキャンセルするために H3_REQUEST_CANCELLED エラーコードを使うべきである (SHOULD) .このエラーコードの受信に際し,サーバは何も処理をしていなければ H3_REQUEST_REJECTED エラーコードを使ってレスポンスを中断できる (MAY) .クライアントはサーバがこのエラーコードを使ってリクエスト・ストリームの終了を要求した場合を除いて,H3_REQUEST_REJECTED エラーコードを使ってはならない (MUST NOT) .

完全なレスポンスを受け取った後にストリームがキャンセルされた場合,クライアントはそのキャンセルを無視してレスポンスを使うことができる (MAY) .しかし,部分的なレスポンスを受け取った後にストリームがキャンセルされた場合は,そのレスポンスは使うべきではない (SHOULD NOT) .GET, PUT, DELETE のようなべき等な操作だけが安全に再試行でき,そうでないメソッドについてクライアントは,そのリクエストのセマンティクスがべき等だと知り得ないか,元のリクエストが適用されていないことを検出できない限りは自動的にリクエストを再試行するべきではない (SHOULD NOT) .詳細については HTTP の 9.2.2 章を参照のこと.

4.1.2. 不正なリクエストとレスポンス (Malformed Requests an Responses)

不正なリクエスト・レスポンスは,フレーム列が正しくなく,以下の原因で不正なときをいう:

  • 禁止されたフィールドや pseudo ヘッダフィールドの存在,
  • 必須 pseudo ヘッダフィールドの欠如,
  • pseudo ヘッダフィールドでの不正な値,
  • pseudo ヘッダフィールドの後のフィールド,
  • 不正な HTTP メッセージ列,
  • 大文字のフィールド名の含有,
  • フィールド名や値における不正な文字の含有.

リクエストまたはレスポンスがコンテンツを持つと定義され Content-Length ヘッダフィールド (HTTP 8.6 章) を含んでいて,Content-Length ヘッダフィールドの値と受信した DATA フレームの長さの和が等しくないとき,そのリクエスト・レスポンスは不正である.コンテンツを持つと定義されていないレスポンスは,Content-Length があっても,DATA フレームに何のコンテンツも含まない場合でも 0 でない Content-Length ヘッダフィールドを持つことができる.

HTTP リクエストおよびレスポンスを処理する中継 (例えば,トンネルとして動作しない中継) は不正なリクエストやレスポンスを転送してはならない (MUST NOT) .検知された不正なリクエストやレスポンスは H3_MESSAGE_ERROR のストリームエラーとして扱わなければならない (MUST) .

不正なリクエストについて,サーバはストリームを閉じたりリセットしたりせずにエラーを示す HTTP レスポンスを送信することができる (MAY) .クライアントは不正なレスポンスを受け入れてはならない (MUST NOT) .これは HTTP に対するいくつかの一般的な攻撃を防ぐため,意図的に厳しく,これを緩くすることは実装を脆弱性にさらすことにつながる.

4.2. HTTP フィールド (HTTP Fields)

HTTP メッセージは,HTTP の 6.3 章および 6.5 章のように,“HTTP フィールド” と呼ばれる Key-Value ペア群を使ってメタデータを運ぶ.登録された HTTP フィールドのリストについては, Hypertext Transfer Protocol (HTTP) Field Name Registry を参照のこと.HTTP/2 のように,HTTP/3 は Connection ヘッダフィールド,pseudo ヘッダフィールド,フィールド名に利用される文字について追加の考慮をしている.

フィールド名は ASCII 文字のサブセットを含む文字列である.HTTP フィールドの名前および値における特性について詳しくは HTTP の 5.1 章で議論される.フィールド名に含まれる文字はエンコードする前に小文字へ変換されなければならない (MUST) .大文字をフィールド名に含むリクエストおよびレスポンスは不正として扱われなければならない (MUST) .

HTTP/3 は接続特有のフィールドを示すために Connection ヘッダフィールドを利用せず,このプロトコルでは,接続特有のメタデータは別の意図で送られる.エンドポイントは接続特有のフィールドを含む HTTP/3 フィールドセクションを生成してはならず (MUST NOT) ,接続特有のフィールドを含むメッセージは不正として扱わなければならない (MUST) .

TE ヘッダフィールドのみは例外で,,HTTP/3 リクエストヘッダとして存在でき (MAY) ,そのとき,”trailers” 以外の値を含んではならない (MUST NOT) .

HTTP/1.x メッセージを HTTP/3 へ変換する中継は,HTTP の 7.6.1 章で議論されるように,接続特有のヘッダフィールドを取り除かなければならない (MUST) .そうでない場合,そのメッセージは他の HTTP/3 エンドポイントによって不正として扱われる.

4.2.1. ヘッダの圧縮 (Field Compression)

QPACK は,head-of-line ブロッキングが圧縮によりどのくらい発生するかを制御する機能をエンコーダに提供する,HPACK のバリエーションを説明する.これによって,遅延と圧縮効率のバランスを取ることが可能になる.HTTP/3 では制御データを含むヘッダセクションとトレーラセクションの圧縮に QPACK を用いる.

より良い圧縮効率を得るために,Cookie ヘッダフィールド (COOKIES) については,圧縮前に 1 以上の Cookie ペアから成る複数のフィールド行へ分けることができる (MAY) .伸張されたフィールドが複数の Cookie フィールド行を含む場合,HTTP/1.1 接続や一般の HTTP サーバアプリケーションのような,HTTP/2 および HTTP/3 以外のコンテキストへ渡す前に “; “ (ASCIi 0x3b, 0x20) の 2 バイトを使って一つのバイト列へ結合しなければならない (MUST) .

4.2.2. ヘッダのサイズ制約 (Header Size Constraints)

HTTP/3 の実装は,個別の HTTP メッセージに対して,受け入れるメッセージヘッダの最大サイズを制限することができる (MAY) .その制限よりも大きなヘッダセクションを受け取った,そのリクエストを扱うサーバは,HTTP 431 (Request Header Fields Too Large) ステータスコード (RFC 6585) を送信できる.クライアントは処理できないレスポンスを破棄できる.フィールドリストのサイズは無圧縮時のサイズを基に,フィールドの値と名前に加えてそれぞれのフィールドに対して 32 バイトのオーバヘッドを加えて計算される.

実装がピアに対しこの制限を告知することを望む場合,SETTINGS_MAX_FIELD_SECTION_SIZE パラメータによってそれをバイト単位で伝えられる.このパラメータを受け取った実装は,それの示すサイズを超えた HTTP メッセージヘッダを送信するとピアが拒否すると思われるため,送信するべきではない (SHOULD NOT) .しかし,HTTP メッセージは HTTP の 3.7 章のように,オリジンサーバへ到達するまでに 1 以上の中継を経由できる.この制限はそのメッセージを処理するそれぞれの実装に適用されるため,制限を下回ったメッセージでも (訳注: 最終的にオリジンサーバで) 受け入れられることは保証されない.

4.3. HTTP 制御データ (HTTP Control Data)

HTTP/2 のように,HTTP/3 はフィールド名が : (ASCII 0x3a) で始まる pseudo ヘッダフィールド群を用いる.この pseudo ヘッダフィールドは HTTP の 6.2 章のように,メッセージ制御データを伝える.

Pseudo ヘッダフィールドは HTTP フィールドではない.エンドポイントはこの文書に定義されたものを以外の pseudo ヘッダフィールドを生成してはならない (MUST NOT) .しかしながら,9 章によって,拡張はこの制限を変更できる.

Pseudo ヘッダフィールドはそれが定義されたコンテキストでのみ有効である.リクエストに対して定義された pseudo ヘッダフィールドはレスポンスに現れてはならず (MUST NOT) ,レスポンスに対して定義された pseudo ヘッダフィールドはリクエストに現れてはならない (MUST NOT) .また pseudo ヘッダフィールドはトレーラセクションに現れてはならない (MUST NOT) .エンドポイントは未定義の,あるいは不正な pseudo ヘッダフィールドを含むリクエストおよびレスポンスを不正として扱わなければならない (MUST) .

すべての pseudo ヘッダフィールドは,ヘッダセクション内の,通常のヘッダフィールドの前に現れなければならない (MUST) .通常のヘッダフィールドの後に pseudo ヘッダフィールドが現れるすべてのリクエストおよびレスポンスは不正として扱わなければならない (MUST) .

4.3.1. リクエスト pseudo ヘッダフィールド (Request Pseudo-Header Fields)

以下の pseudo ヘッダフィールドがリクエストに対して定義される:

“:method”: HTTP メソッドを含む (HTTP の 9 章) .

“:scheme”: ターゲット URI のスキーム部分を含む (URI の 3.1 章) .
この :scheme pseudo ヘッダは “http” および “https” スキームを持つ URI に限られない.プロキシやゲートウェイは HTTP でないスキームにリクエストを変換でき,HTTP でないサービスと HTTP によって作用することができる.
”https” 以外のスキームの利用については 3.1.2 章を参照のこと.

“:authority”: ターゲット URI の authority 部分を含む (URI の 3.2 章) .この authority は “http” および “https” スキームにおいては,非推奨の userinfo サブコンポーネントを含んではならない (MUST NOT) .
HTTP/1.1 のリクエスト行が正確に再現できるよう,HTTP の 7.1 章のようにメソッド特有の形式でリクエスト・ターゲットを持つ HTTP/1.1 リクエストから変換するときには,この pseudo ヘッダフィールドを除かなければならない (MUST) .HTTP/3 リクエストを直接生成するクライアントは Host ヘッダの代わりに :authority pseudo ヘッダを使うべきである (SHOULD) .HTTP/3 リクエストを HTTP/1.1 に変換する中継は,Host フィールドが存在しないとき,:authority pseudo ヘッダフィールドの値をコピーして作らなければならない (MUST) .

“:path”: ターゲット URI のパスとクエリ部分を含む (”path-absolute” と,任意で ? 文字 (ASCII 0x3f) および “query”; URL の 3.3 および 3.4 章を参照のこと) .
この pseudo ヘッダフィールドは “http” および “https” スキームの URI に対しては空であってはならなず (MUST NOT) ,path コンポーネントを含まない ”http” および “https” の URI に対しては / (ASCII 0x2f) の値を含めなければならない (MUST) .path コンポーネントを含まない OPTIONS リクエストに対しては HTTP 7.1 章のように,* (ASCII 0x2a) を :path pseudo ヘッダフィールドに含める.

4.4 章による CONNECT リクエスト以外のすべての HTTP/3 リクエストは,:method, :scheme, :path pseudo ヘッダフィールドの値をそれぞれ 1 つ含めなければならない (MUST) .

:scheme pseudo ヘッダフィールドが authority コンポーネントを必須とするスキーム (”http”, “https” を含む) を示す場合,そのリクエストは :authoity pseudo ヘッダフィールドまたは Host ヘッダフィールドのどちらかを含まなければならない (MUST) .これらのフィールドが存在するとき,その値は空であってはならない (MUST) .両方のフィールドが存在するとき,両方の値は同じでなければならない (MUST) .スキームが authority コンポーネントを必須とせず,リクエストターゲットが提供しないとき,そのリクエストは :authority pseudo ヘッダフィールドおよび Host ヘッダフィールドを含めてはならない (MUST NOT) .

必須の pseudo ヘッダフィールドがないか,それらの pseudo ヘッダフィールドに不正な値を含む HTTP リクエストは不正である.

HTTP/3 は,HTTP/1.1 のリクエスト行に含まれるバージョン識別子を運ぶ方法を提供しない.HTTP/3 リクエストは明示的に “3.0” のプロトコルバージョンを持つ.

4.3.2. レスポンス pseudo ヘッダフィールド (Response Pseudo-Header Fields)

レスポンスに対しては,HTTP の 15 章による HTTP ステータスコードを運ぶための,”:status” pseudo ヘッダフィールドのみが定義される.この pseudo ヘッダフィールドはすべてのレスポンスに含まれなければならず (MUST) ,そうでない場合そのレスポンスは不正である (4.1.2 章) .

HTTP/3 は,HTTP/1.1 のステータス行に含まれるバージョン識別子を運ぶ方法を提供しない.HTTP/3 レスポンスは明示的に “3.0” のプロトコルバージョンを持つ.

4.4. CONNECT メソッド (The CONNECT Method)

CONNECT メソッドは HTTP 9.3.6 章のように,受信者がリクエストターゲットによって示されるオリジンサーバに対してトンネルを確立することを要求する.これは主に HTTP プロキシが “https” リソースへ作用する目的でオリジンサーバへの TLS セッションを確立するために用いられる.

HTTP/1.x では,CONNECT は HTTP 接続の全体をリモートホストへのトンネルへ変換するために用いられた.HTTP/2 と HTTP/3 では,CONNECT メソッドは単一のストリーム内でトンネルを確立するために用いられる.

CONNECT リクエストは以下のように構築されなければならない (MUST):

  • :method pseudo ヘッダフィールドは “CONNECT” に設定される
  • :scheme と :path pseudo ヘッダフィールドは除く
  • :authority ヘッダフィールドは接続先のホストとポートを含む (HTTP 7.1 章によるリクエストターゲットの authority 形式と等価)

リクエストストリームはデータを転送するためにリクエスト終了後も開いたままとなる.CONNECT リクエストについてはこの制限の無視によって不正とならない.

CONNECT をサポートするプロキシは :authority pseudo ヘッダフィールドに示されたサーバへ TCP 接続 (RFC 0793) を確立する.この接続が正常に確立されたのち,プロキシは HTTP 15.3 章のように,2xx ステータスコードを含む HEADERS フレームをクライアントへ送信する.

ストリームにおけるすべての DATA フレームはこの TCP コネクションで送受信されるデータと対応する.クライアントによって送信された任意の DATA フレームのペイロードはプロキシによて TCP サーバへ送信され,TCP サーバから受信したデータはプロキシで DATA フレームにパッケージ化される.TCP セグメントのサイズと数は,HTTP DATA および QUIC STREAM フレームのサイズと数から予測できることを保証されない.

CONNECT メソッドの終了後,ストリームでは DATA フレームの送信のみが許可される.拡張による定義で許可された場合は拡張フレームを使うこともできる (MAY) .その他の既知のフレームタイプの受信は,H3_FRAME_UNEXPECTED の接続エラーとして扱われなければならない (MUST) .

TCP 接続はどちらのピアからも閉じられる.クライアントがリクエストストリームを終えると (プロキシの受信ストリームは “Data Recvd” 状態となり) ,プロキシは TCP サーバへの通信に FIN ビットを設定する.プロキシが FIN ビットがセットされたパケットを受け取ると,クライアントへの送信ストリームを閉じる.単方向に対してだけ閉じられた TCP 接続は不正であるが,サーバによってよく不十分に扱われるため,クライアントは CONNECT のターゲットからデータを受信することを予期する間,送信ストリームを閉じるべきではない (SHOULD NOT) .

TCP 接続エラーはストリームを突然切断することで伝えられる.プロキシは RST ビットがセットされた TCP セグメントを含むすべての TCP 接続エラーを H3_CONNECT_ERROR のストリームエラーとして扱う.

一方,プロキシがストリームまたは QUIC 接続においてエラーを検知した場合,TCP 接続を閉じなければならない (MUST) .クライアントがストリームをリセットしたり,ストリームからの読み取りを中断したりしたことをプロキシが検知した場合,TCP 接続を閉じなければならない (MUST) .クライアントによってストリームがリセットされたり,読み取りが中断されたりしたとき,プロキシは両方向のストリームをキャンセルするために別の方向に対しても同じ操作をしなければならない.これらのすべての場合で,根幹の TCP 実装が許す場合,プロキシは RST ビットをセットした TCP セグメントを送信するべきである (SHOULD) .

CONNECT は任意のサーバへトンネルを作成できるため,HTTP 9.3.6 章に詳細があるように,CONNECT をサポートするプロキシは既知のポートや安全なリクエストターゲットのリストへ利用を制限するべきである (SHOULD) .

4.5. HTTP アップグレード (HTTP Upgrade)

HTTP/3 は HTTP アップグレード (HTTP 7.8 章) の仕組みや 101 (Switching Protocols) 補助ステータスコード (HTTP 15.2.2 章) をサポートしない.

4.6. サーバプッシュ (Server Push)

サーバプッシュは,クライアントがリクエストを作るよりも先に,サーバがリクエスト・レスポンスの交換をクライアントへプッシュすることを許す作用モードである.これは遅延の利得とネットワーク利用とのトレードオフとなる.HTTP/3 サーバプッシュは HTTP/2 8.2 章で説明されるそれに似ているが,別の仕組みを使う.

それぞれのサーバプッシュにはサーバがユニークなプッシュ ID を設ける.プッシュ ID は HTTP/3 接続の生存期間を通した様々なコンテキストの中でプッシュを参照するために使われる.

プッシュ ID 空間は 0 から始まり MAX_PUSH_ID フレームで設定される最大値で終わる.特に,クライアントが MAX_PUSH_ID フレームを送信するまで,サーバはプッシュできない.クライアントはサーバが設けることのできるプッシュの数を制御するため MAX_PUSH_ID フレームを送信する.サーバはプッシュ ID を 0 から順に利用するべきである (SHOULD) .MAX_PUSH_ID フレームを送信していない間の受信や,最大のプッシュ ID より大きい ID を参照したプッシュストリームの受信を,クライアントは H3_ID_ERROR の接続エラーとして扱われなければならない (MUST) .

プッシュ ID は 1 つ以上の PUSH_PROMISE フレームで制御データとリクエストメッセージのヘッダフィールドを運ぶために使われる.これらのフレームはプッシュを生成したリクエストストリームで送信される.これにより,サーバプッシュをクライアントのリクエストと紐付けることができる.複数のリクエストストリームが同じプッシュ ID で設けられるとき,伸張されたリクエストフィールドセクションは同じフィールドを同じ順で含まなければならず (MUST) ,それぞれのフィールドの名前および値は一致しなければならない (MUST) .

💡 訳注: サーバプッシュによってレスポンスが行われるまでの単位が promise ですが,適当な日本語が思いつかなかったのでそのまま記述しています.

プッシュ ID は,プッシュストリームがその promise を完全に満たすときに含まれる.プッシュストリームは,それが満たすプッシュ ID を示し,4.1 章で説明されるようにリクエストへのレスポンスが含まれる.

そして,7.2.3 章のように,プッシュ ID を CANCEL_PUSH フレームで使うことができる.クライアントは promise によるリソースを受け取ることを望まないときにこのフレームで示せる.サーバはこのフレームで以前の promise を満たさないことを示せる.

すべてのリクエストがプッシュできるわけではない.サーバは以下の特性を持つリクエストをプッシュできる (MAY) .

  • キャッシュ可能 (HTTP 9.2.3 章)
  • 安全 (HTTP 9.2.1 章)
  • リクエストにコンテンツおよびトレーラセクションを含まない

サーバは,:authority pseudo ヘッダフィールドにそのサーバが権威を持つよう値を含めなければならない (MUST) .プッシュされたリクエストによって示されるオリジンをクライアントがその接続でまだ検証していないとき,3.3 章のようにその接続でそのオリジンにリクエストを送るときと同じ検証処理を行わなければならない (MUST) .検証が失敗した場合,クライアントはオリジンに対してそのサーバが権威を持つとしてはならない (MUST NOT) .

キャッシュできないリクエスト,安全ではないとわかるリクエスト,コンテンツの存在を示しているリクエスト,サーバが権威を持つと思われないリクエストを PUSH_PROMISE で受信したとき,クライアントは CANCEL_PUSH フレームを送信するべきである (SHOULD) .これらに対応するいずれのレスポンスも利用したりキャッシュしたりしてはならない (MUST NOT) .

それぞれのプッシュされたレスポンスは 1 つ以上のクライアントリクエストに紐付く.プッシュは PUSH_PROMISE フレームを受信したリクエストストリームに紐付く.PUSH_PROMISE フレームにおいて,複数のリクエストストリームで同じプッシュ ID を用いることで,同じプッシュを追加のクライアントリクエストへ紐付けることができる.この紐付けはプロトコルの操作には影響しないが,ユーザエージェントはこれによってプッシュされたリソースをどのように利用するか決めることができる (MAY) .

レスポンス内のいくつかの部分に対して,PUSH_PROMISE フレームの順番は重要である.サーバはその promise によるレスポンスの HEADERS および DATA フレームよりも先に PUSH_PROMISE フレームを送信すべきである (SHOULD) .これによりサーバによりプッシュされる予定のリソースをクライアントからリクエストする可能性を下げられる.

順序の変更の影響で (訳注: データが到着する順が保証できないので),プッシュストリームのデータは対応する PUSH_PROMISE フレームより先に到着する可能性がある.まだ知らないプッシュ ID の新しいプッシュストリームをクライアントが受信したとき,紐付いたクライアントリクエストとプッシュされたリクエストヘッダの両方は不明である.クライアントは一致する PUSH_PROMISE を予期してストリームデータをバッファできる.クライアントはストリームのフロー制御 (QUIC-TRANSPORT 4.1 章) を使ってプッシュストリームにサーバが送信するデータの量を制限できる.クライアントは対応する PUSH_PROMISE フレームが適当な時間内に処理されなかったとき,プッシュストリームからの読み取りを中断してすでに読み取ったデータを破棄するべきである (SHOULD) .

プッシュストリームのデータは,クライアントがプッシュをキャンセルした後にも到達しうる.このケースでは, クライアントは H3_REQUEST_CANCELLED エラーコードによってストリームの読み取りを中断できる.これはサーバに追加のデータを送信しないことを求め,今後のデータは破棄されることを示せる.

プッシュされたレスポンスはキャッシュ可能であり (HTTP-CACHING の 3 章) ,クライアントが HTTP キャッシュを実装すれば保管できる.プッシュされたレスポンスは,それを受信したときにおいて,オリジンサーバで正常に検証されたものとされる (例えば, “no-cache” キャッシュレスポンス命令があるとき; HTTP-CACHING 5.2.2.4 章) .

キャッシュできない,プッシュされたレスポンスは,いずれの HTTP キャッシュにおいても保管してはならない (MUST NOT) .これらはアプリケーションにおいて個別に利用可能とできる (MAY) .

5. 接続の終了 (Connection Closure)

image.png

89
71
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
89
71