[2] [DFN[[RUBYB[[[フレーム]]]@en[frame]]]]は、[[HTTP/2接続]]中の通信の最小単位です。[[フレーム]]は[[ヘッダー]]と可変長の[[オクテット列]]で構成されます。 [SRC[>>1]]

* 仕様書

[REFS[
- [1] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-2.2>
- [3] '''[CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-4>'''
- [29] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-5.5>
- [30] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-6>
-- [31] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-6.5.2>
- [13] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-7>
- [59] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-10.5>
- [43] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-11.2>
- [63] [CITE[Hypertext Transfer Protocol version 2 (HTTP/2) Parameters]] ([TIME[2015-05-20 07:51:31 +09:00]] 版) <https://www.iana.org/assignments/http2-parameters/http2-parameters.xml#frame-type>
]REFS]

* 構文

[4] [[フレーム]]は、9[[バイト]]の[[ヘッダー]]と、
可変長の[[payload]] で構成されます [SRC[>>3]]。

[5] [[フレーム]]の[[ヘッダー]]は、次の欄で構成されます [SRC[>>3]]。
[FIG(list members)[
:[RUBYB[[[長さ]]]@en[Length]]:
[[payload]] の長さを[[符号無し]]24ビット[[整数]] ([[ネットワークバイト順]] [SRC[>>1]])
で表現したものです。 [SRC[>>3]]
:[RUBYB[[[型]]]@en[Type]]:[[フレーム]]の種類を表す8ビットの値です。
[[フレーム]]の形式と意味が指定されます。 [SRC[>>3]]
:[RUBYB[[[フラグ群]]]@en[Flags]]:[[フレーム型]]依存の [[boolean]] [[フラグ]]用の
8ビットの欄です。 [SRC[>>3]]
:[[R]]:予約された1ビットの欄です。意味は定義されていません。値は 0 です。
[[受信者]]は無視することになっています。 [SRC[>>3]]
:[RUBYB[[[ストリーム識別子]]]@en[Stream Identifier]]:[[ストリーム識別子]]を[[符号無し]]31ビット[[整数]]
([[ネットワークバイト順]] [SRC[>>1]]) として表したものです。 [SRC[>>3]]
[[接続]]全体を表す [CODE[[[0x0]]]] を指定することもできますが、
[[フレーム型]]によっては認められていません。
:[[Frame Payload]]:[[フレーム型]]に依存したデータです [SRC[>>3]]。
長さは「長さ」欄で指定され、0のこともあります。
]FIG]

[FIG(packet)[
:width:32:

= 24 [[Length]]
= 8 [[Type]]
= 8 [[Flags]]
= 1 R
= 31 [[ストリーム識別子]]
= 24... [[Frame Payload]]
]FIG]

* フレーム型

[51] [[フレーム]]の[DFN[[RUBYB[型]@en[Type]]]]は、[[フレーム]]の種類を表す8ビットの値です
[SRC[>>3]]。

[52] [[フレーム]]の形式と意味は[[フレーム型]]によって指定されます。 [SRC[>>3]]

;; 各[[フレーム型]]の項を参照。

[46] 次の[[フレーム型]]があります。
[FIG(short list)[
- [CODE(HTTP)@en[[[DATA]]]] ([CODE[[[0x0]]]])
- [CODE(HTTP)@en[[[HEADERS]]]] ([CODE[[[0x1]]]])
- [CODE(HTTP)@en[[[PRIORITY]]]] ([CODE[[[0x2]]]])
- [CODE(HTTP)@en[[[RST_STREAM]]]] ([CODE[[[0x3]]]])
- [CODE(HTTP)@en[[[SETTINGS]]]] ([CODE[[[0x4]]]])
- [CODE(HTTP)@en[[[PUSH_PROMISE]]]] ([CODE[[[0x5]]]])
- [CODE(HTTP)@en[[[PING]]]] ([CODE[[[0x6]]]])
- [CODE(HTTP)@en[[[GOAWAY]]]] ([CODE[[[0x7]]]])
- [CODE(HTTP)@en[[[WINDOW_UPDATE]]]] ([CODE[[[0x8]]]])
- [CODE(HTTP)@en[[[CONTINUATION]]]] ([CODE[[[0x9]]]])
- [CODE(HTTP)@en[ALTSVC]] ([CODE[0xA][ALTSVC]])
]FIG]

[45] [CODE[0xf0]]-[CODE[0xff]] は、[[実験用]]に予約されています [SRC[>>43]]。

[44] [[IANA登録簿]] [SRC[>>63]] があります [SRC[>>43]]。

[62] [[送信者]]は未知の[[フレーム型]]の[[フレーム]]を送ってはならないと思われますし、
送る必要もないはずです。

[7] [[受信者]]は、未知の[[フレーム型]]の[[フレーム]]を無視し、捨てなければ[['''なりません''']] [SRC[>>3, >>29]]。

;; [12] 無視とはいえ、[[フレーム]]としてのエラー (長さの問題など) 
の検証は行わなければならないと思われます。また、[[ヘッダーリスト]]を構成する[[フレーム]]間では、
未知の[[フレーム型]]の[[フレーム]]はエラーとなります。

;; [61] [[ストリーム]]の状態遷移の項も参照。

* payload の長さ

[53] [[フレーム]]の[DFN[[RUBYB[長さ]@en[Length]]]]欄は、
[[payload]] の長さを[[符号無し]]24ビット[[整数]] ([[ネットワークバイト順]] [SRC[>>1]])
で表現したものです [SRC[>>3]]。単位は[[バイト]]です。
[[フレーム]]の長さは、本欄に示された [[payload]] の長さの値
(と[[フレーム]]の[[ヘッダー]]の 9 [[バイト]]の[[和]]) により決まります。

[54] [[payload]] の長さは、 0 [[以上]]の値です。

[6] [[payload]] の長さは、[[設定]] [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]] 
の値よりも大きな値としては[['''なりません''']] [SRC[>>3]]。

;; [55] 実際には、[[フレーム型]]依存の制約があるかもしれません。
各[[フレーム型]]の項を参照してください。

[32] [[設定]] [DFN[[CODE[[[SETTINGS_MAX_FRAME_SIZE]]]]]] ([CODE[[[0x5]]]])
は、[[送信者]]が[[受信]]する意志のある最大の[[フレーム]]の [[payload]]
の長さを[[バイト]]単位で表します [SRC[>>31, >>3]]。 

[33] 本[[設定]]の初期値は 2[SUP[14]] です [SRC[>>31]]。

[15] 本設定の値は、 2[SUP[14]] [[以上]]、 2[SUP[24]]-1 [[以下]]でなければ[['''なりません''']] [SRC[>>3, >>31]]。
範囲外の値は、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としなければ[['''なりません''']] [SRC[>>31]]。

[16] すべての実装は、 2[SUP[14]] [[バイト]][[以下]]の [[payload]]
を扱うことができなければ[['''なりません''']] [SRC[>>3]]。

;; [17] [[payload]] の長さには、[[フレーム]]の[[ヘッダー]]の長さ 9 は含まれていません。

;; [18] [CODE[[[PING]]]] のように、[[フレーム型]]依存の [[payload]]
の長さの制約が別にあるかもしれません。

[67] [[Chrome]] も [[Firefox]] も、値域外の値が指定された時を含め、
完全に無視しているように見えます。少なくても[[接続エラー]]にはなりません。 [TIME[2015-10-12T03:09:09.400Z]]

[19] [[エンドポイント]]は、次の場合に [CODE[[[FRAME_SIZE_ERROR]]]]
[[エラー符号]]を送信しなければ[['''なりません''']] [SRC[>>3]]。
[FIG(list)[
- [20] [[フレーム]]の長さが [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]] を超える場合
- [21] [[フレーム]]の長さが[[フレーム型]]依存の制限を超える場合
- [22] [[フレーム]]の長さが必須のフレームデータの長さより短い場合
]FIG]

[23] [[接続]]全体の状態を変えてしまい得る[[フレーム]]の長さのエラーは、
[[接続エラー]]となければ[['''なりません''']] [SRC[>>3]]。これには次のものが含まれます。 
[FIG(list)[
- [25] [[header block]] を含む[[フレーム]] ([CODE[[[HEADERS]]]], [CODE[[[PUSH_PROMISE]]]], [CODE[[[CONTINUATION]]]]) [SRC[>>3]]
- [26] [CODE[[[SETTINGS]]]] [SRC[>>3]]
- [[ストリーム識別子]]が [CODE[[[0]]]] の[[フレーム]] [SRC[>>3]]
]FIG]

[10] それ以外の場合は、[[ストリームエラー]]で良いものと思われます。

[39] [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]] を超える値だとしても、
[[接続エラー]]でなく[[ストリームエラー]]とする場合、
次の[[フレーム]]を正しく処理できるよう、
指定された長さ分通常通り読む (読み飛ばす) 必要があります。

[40] [[Firefox]] は [CODE[[[DATA]]]] フレームであっても
[CODE[[[SETTINGS_MAX_FRAME_SIZE]]]] を超える長さの時、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] とするようです。 
更に大量のデータを受信している場合には [CODE[[[GOAWAY]]]]
を送信せずすぐに接続を閉じるようです。
[TIME[2015-09-28T07:17:58.500Z]]

[42] [[Chrome]] は [CODE[[[DATA]]]] の [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]]
の検査をしないようです。 [TIME[2015-10-10T08:13:47.000Z]]

[64] [[Firefox]] も [[Chrome]] も、[CODE[[[HEADERS]]]]
の payload は 2[SUP[18]] までエラーとはしません。
2[SUP[18]]+1 以上のヘッダーを受信すると、 2[SUP[14]] まで受信を待ちます。
その後 [[Firefox]] は[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]、
[[Chrome]] は[[接続エラー]] [CODE[[[FRAME_SIZE_ERROR]]]]
とします。ただしその後更にデータを受信した場合は、
[CODE[[[GOAWAY]]]] を送信せずに直ちに接続を閉じるようです
(閾値は payload のサイズが [[Chrome]] で 2[SUP[14]]、
[[Firefox]] で 2[SUP[15]] 弱のようです)。 [TIME[2015-10-11T03:31:21.100Z]]

[11] [CODE[[[RST_STREAM]]]] [[フレーム]]や
[CODE[[[WINDOW_UPDATE]]]] [[フレーム]]の長さのエラーも、
[[接続エラー]]となります。

;; それぞれの項を参照。

[34] [DFN[[CODE[[[FRAME_SIZE_ERROR]]]]]] ([CODE[[[0x6]]]]) は、
非妥当なサイズの[[フレーム]]を受信したことを示します [SRC[>>13]]。

[49] 実際のデータの長さより長い [[payload]] の長さが指定された時にどうするべきかは不明です。

;; [50] [[フレーム]]を受信し終える前に[[接続]]が閉じられた場合や、
[CODE(HTTP)@en[[[HTTP2-Settings:]]]] [[ヘッダー]]の値が不完全な場合があり得ます。

* フラグ

[56] [[フレーム]]の[DFN[[RUBYB[フラグ群]@en[Flags]]]]は、
[[boolean]] [[フラグ]]用の8ビットの欄です。 [SRC[>>3]]

[57] 8つの[[ビット]]ごとに、[[フレーム型]]に依存 [SRC[>>3]] した意味が定義されているか、
未定義のままとされています。

[60] 次の[[フラグ]]があります。ただしすべての[[フレーム型]]で定義されているわけではありませんし、
第0ビットは[[フレーム型]]により異なる意味が割り当てられています。
[FIG(packet)[
:width:8

= 1 [CODE[[[END_STREAM]]]] / [CODE[[[ACK]]]]
= 1 0
= 1 [CODE[[[END_HEADERS]]]]
= 1 [CODE[[[PADDED]]]]
= 1 0
= 1 [CODE[[[PRIORITY]]]]
= 1 0
= 1 0
]FIG]

;; 各[[フレーム型]]の項を参照。

[8] [[送信者]]は、[[フレーム型]]により[[フラグ]]群の意味が定義されていない場合、
0 を設定しなければ[['''なりません''']] [SRC[>>3]]。

[9] [[受信者]]は、[[フレーム型]]により[[フラグ]]群の意味が定義されていない場合、
無視しなければ[['''なりません''']] [SRC[>>3]]。

[65] [[Chrome]] は未定義の[[フラグ]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] とします。
[[Firefox]] は無視します。 [TIME[2015-10-11T09:24:05.700Z]]

* 文脈

[47] [[フレーム]]は、[[ストリーム]]上のバイト列として送受信されます。

[48] [CODE(HTTP)@en[[[SETTINGS]]]] [[フレーム]]は、 [[HTTP/1.1]]
[CODE(HTTP)@en[[[HTTP2-Settings:]]]] [[ヘッダー]]内に含まれることがあります。

* 処理

[27] [[フレーム]]の送受信は、[[ストリーム]]の状態を変化させます。
状態によっては、受信したらエラーとしなければならない[[フレーム型]]もあります。

;; [[HTTPストリーム]]を参照。

[28] [[フレーム]]の処理は、[[フレーム型]]によって異なります。

;; 各[[フレーム型]]の項も参照。

[58] 小さな[[フレーム]]や [[payload]] が空の[[フレーム]]は、
無駄な処理をさせるために濫用できます。
[[エンドポイント]]は利用状況を監視して制限する[['''べきです''']]。
[[接続エラー]] [CODE[[[ENHANCE_YOUR_CALM]]]] としても構いません。 [SRC[>>59]]

;; [35] ただし [CODE[[[DATA]]]] など空や小サイズでも正当な場合も多々あります。

[66] [[Chrome]] も [[Firefox]] も、[[フレーム]]の途中まで受信した時に残りを受信するまでの特別なタイムアウトは用意していないように見えます。
[[Firefox]] は定期的に [CODE[[[PING]]]] を送信するので、それに応答がないことにより接続が閉じられます。
[TIME[2015-10-11T12:00:44.600Z]]

* 実装

[36] [[Chrome]] も [[Firefox]] も、
[CODE[[[FRAME_SIZE_ERROR]]]] ではなく [CODE[[[PROTOCOL_ERROR]]]]
を使っているようです。 [TIME[2015-09-28T07:03:22.200Z]]

[37] [[Chrome]] はフレームのヘッダー部分を読んだ時点でエラーを検査しているように見えます。
[[Firefox]] は payload まですべて読んでから検査しているように見えます。
[TIME[2015-09-28T07:04:19.400Z]]

[38] [[Chrome]] は [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]] を超えていないかの検査をしていないように見えます。 [TIME[2015-09-28T07:10:39.100Z]]

[41] [[フレーム]]のヘッダーの途中や payload として指定された長さに満たずに[[接続]]が閉じられた場合、
[[Firefox]] は (正常終了なら) [CODE[[[GOAWAY]]]] ([CODE[[[NO_ERROR]]]]) を送信し、
[[Chrome]] はそのまま、[[接続]]を閉じるようです。
どちらも[[要求]]は[[ネットワークエラー]]になります。
[TIME[2015-09-28T09:44:16.300Z]]

[68] [[Firefox]] は[[接続序文]]で [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]]
に 2[SUP[14]] を設定しますが、これは初期値と同じです。[TIME[2015-10-20T08:18:08.200Z]]

[69] [CITE@en[The ORIGIN HTTP/2 Frame]]
([TIME[2016-12-24 19:55:06 +09:00]])
<http://httpwg.org/http-extensions/origin-frame.html>

[70] [CITE@en[draft-hoffman-dns-in-existing-http2-00 - Running DNS in Existing HTTP/2 Connections]]
([TIME[2017-04-11 17:24:40 +09:00]])
<https://tools.ietf.org/html/draft-hoffman-dns-in-existing-http2-00>

[71] [CITE[無職転生Ⅱ ~異世界行ったら本気だす~ 13話上映会 - 2024/4/11(木) 0:00開始 - ニコニコ生放送]]
([TIME[2024-04-15 13:58:22 +09:00]])
<https://live.nicovideo.jp/watch/lv344746642>