[114] [DFN[server push]] は、[[クライアント]]から明示的な[[要求]]がなくても、
予め[[サーバー]]から[[応答]]を送信するものです。

[121] 
一番最初にフックとなる[[クライアント]]から[[サーバー]]への[[要求]]が必要とはいえ、
通常の [[HTTP]] とは異なり、
[[サーバー]]が主体的に[[クライアント]]に情報を送信できる仕組みとなっています。

* 仕様書

[REFS[
- [78] [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>
- [79] [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.1>
- [82] [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.2>
- [83] [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.1>
- [87] [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.3.5>
- [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-6.1>
- [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-6.5.2>
- [8] '''[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.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-7>
- [34] '''[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-8.2>'''
- [70] [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.4>
- [76] [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>
]REFS]

* 意味

[35] [[HTTP/2]] [[server push]] は、
[[応答]]とそれに対応する「[RUBYB[約束]@en[promised]]」[[要求]]を、
先に[[クライアント]]が開始した[[要求]]に関連付ける形で[[サーバー]]から予め送信
([[push]]) するものです [SRC[>>34]]。

[36] [[server push]] は、[[クライアント]]が元の[[要求]]に対する[[応答]]を完全に処理するために当該[[応答]]が必要になるであろうとわかっている場合に便利です
[SRC[>>34]]。

[55] [[server push]] は、意味的には[[クライアント]]の[[要求]]に[[サーバー]]が[[応答]]を返す通常の場合と同じですが、
[[要求]]を[[クライアント]]ではなく[[サーバー]]が ([[クライアント]]へと)
[CODE[[[PUSH_PROMISE]]]] [[フレーム]]により送信します [SRC[>>34]]。

[52] [[クライアント]]は、 [[push]] できません [SRC[>>34]]。

* 約束要求

[44] [[サーバー]]から[[クライアント]]へと送信する[[要求]]を、
[DFN[[RUBYB[[[約束要求]]]@en[promised request]]]]といいます。

[39] [[約束要求]]は、[[要求本体]]を含んでは[['''なりません''']] [SRC[>>34]]。

[56] [CODE[[[PUSH_PROMISE]]]] [[フレーム]] (と [CODE[[[CONTINUATION]]]]
[[フレーム]]) が、[[要求]]の [[header block]] を含みます。
[[要求]]の[[ヘッダー]]を[[妥当]]かつ完全に含まなければ[['''なりません''']]。 [SRC[>>34]]

[49] [[サーバー]]は、当該[[サーバー]]が権限を有する ([[authoritative]])
[CODE(HTTP)@en[[[:authority]]]] [[疑似ヘッダー]]値を含めなければ[['''なりません''']]
[SRC[>>34]]。

;; [[HTTP接続]]も参照。

[37] [[約束要求]]は、[[キャッシュ可能]]でなければ[['''なりません''']] [SRC[>>34]]。

[38] [[約束要求]]は、[[安全]]でなければ[['''なりません''']] [SRC[>>34]]。

[58] [[サーバー]]は、 [CODE(HTTP)@en[[[:method]]]] [[疑似ヘッダー]]に[[安全]]で[[キャッシュ可能]]な[[要求メソッド]]を指定しなければ[['''なりません''']] [SRC[>>34]]。

[61] [[サーバー]]は、約束された[[応答]]を参照する[[フレーム]]を送信する前に、
[CODE(HTTP)@en[[[PUSH_PROMISE]]]] [[フレーム]]を送信する[['''べきです''']]。
これにより[[クライアント]]が [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信する前に別途[[要求]]を発行することを防ぐことができます。 [SRC[>>34]]

[EG[
[62] 例えば [CODE(HTTP)@en[[[DATA]]]] [[フレーム]]に[[画像]]を埋め込むリンクが含まれているなら、
それよりも前に当該[[画像]]の [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信することにできます。 [SRC[>>34]]
]EG]

[71] 複数の[[著者]]の[[資源]]を提供する[[サーバー]]は、
他の[[著者]]の管轄下のはずの[[資源]]を[[プッシュ]]できてしまわないようにしなければ[['''なりません''']] [SRC[>>70]]。

;; [72] [[レンタルサーバー]]や[[クラウド]]サービスの[[逆串]]などで注意が必要です。

* プッシュ応答

[48] [[約束要求]]に続いて[[サーバー]]から[[クライアント]]へと送信する[[応答]]を、
[DFN[[RUBYB[プッシュ応答]@en[pushed response]]]]といいます。

[65] [[サーバー]]は [CODE[[[PUSH_PROMISE]]]] [[フレーム]]
(と [CODE[[[CONTINUATION]]]] [[フレーム]]) に続けて
(同じ[[ストリーム]]で) [[プッシュ応答]]を配送開始できます [SRC[>>34]]。

* 文脈

[119] 
[[Webページ]]は [[HTML文書]]から参照される [[CSS]] や [[JavaScript]]
などいろいろな[[ファイル]]の集合体として構成されますが、
その読み込みの最適化のため、
[[HTML文書]]の[[応答]]中に [[server push]]
を使って他の構成ファイルが送信されることがあります。

[120] [[Web Push Protocol]]
では、
[[プッシュメッセージ購読資源]]、
[[プッシュメッセージ購読集合資源]]、
[[受領証購読資源]]で
[[server push]]
が使われます。

* 処理

[60] [[クライアント]]は、[[約束要求]]に完全で妥当な[[ヘッダー]]の集合が含まれていなければ、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

[40] [[クライアント]]は、[[キャッシュ可能]]でない[[約束要求]]を受信したら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

[41] [[クライアント]]は、[[安全]]でない[[約束要求]]を受信したら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

[59] [[クライアント]]は、 [CODE(HTTP)@en[[[:method]]]] [[疑似ヘッダー]]に[[安全]]でない[[要求メソッド]]が指定されていれば、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

;; [43] [[クライアント]]が新しい[[要求メソッド]]が[[安全]]と知っていなければ、
エラーになります [SRC[>>34]]。

[42] [[クライアント]]は、[[要求本体]]の存在を示した[[約束要求]]を受信したら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

[50] [[クライアント]]は、[[サーバー]]が権限を有する ([[authoritative]])
か[[プロキシ]]であって対応する[[要求]]に関する[[プッシュ応答]]を提供するよう設定されていることを検証しなければ[['''なりません''']]。
それ以外の値の [CODE(HTTP)@en[[[:authority]]]] [[疑似ヘッダー]]が含まれていたら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

[EG[
[69] [[DNS-ID]] または[[共通名]]として [CODE[[[example.com]]]]
が指定された[[証明書]]を使っている[[サーバー]]の場合、
[CODE[https://www.example.org/doc]] の[[プッシュ応答]]を提供してはなりません。 [SRC[>>34]]
]EG]

;; [[HTTP接続]]も参照。

[45] [[プッシュ応答]]は、[[キャッシュ可能]]なら、
[[クライアント]]の [[HTTPキャッシュ]]に[[蓄積]]できます [SRC[>>34]]。

[46] [[プッシュ応答]]は、[[ストリーム]]が [[open]] 
である間、[[起源サーバー]]で成功裏に[[検証]]されたものとみなします [SRC[>>34]]。

[47] [[プッシュ応答]]は、[[キャッシュ可能]]でなければ、
[[HTTPキャッシュ]]に[[蓄積]]しては[['''なりません''']]。
別途[[応用]]に提供しても構いません。 [SRC[>>34]]

[51] [[中間器]]は、[[サーバー]]からの [[push]] を[[クライアント]]へと[[転送]]しないことにしても構いません。
また[[サーバー]]から送られてこなくても独自に[[クライアント]]に [[push]]
しても構いません。 [SRC[>>34]]

[66] [[クライアント]]は、 [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を受信し、
[[プッシュ応答]]を受け入れることにしたら、
その[[ストリーム]]が閉じられるまでの間、
その[[応答]]に対する[[要求]]を発行する[['''べきではありません''']] [SRC[>>34]]。

[67] [[クライアント]]は、何らかの理由で[[プッシュ応答]]を受信したくない時や、
[[サーバー]]が[[プッシュ応答]]を送信し始めるまでの時間がかかりすぎている時は、
[CODE[[[RST_STREAM]]]] [[フレーム]]に[[誤り符号]] [CODE[[[CANCEL]]]] や
[CODE[[[REFUSED_STREAM]]]] を指定し、当該[[ストリーム識別子]]を指定して送信できます [SRC[>>34]]。

[73] [[サーバー]]が [[authoritative]] でない[[応答]]を[[キャッシュ]]したり、
使ったりしては[['''なりません''']] [SRC[>>70]]。

;; [74] [[authoritative]] かどうかの判定については、 [[HTTP接続]]の再利用の項を参照。

[EG[
[75] 例えば [CODE[[[example.com]]]] の[[サーバー証明書]]を持つ [[TLS接続]]上で
[CODE[https://example.net/]] の[[応答]]が[[プッシュ]]されても、
使ってはなりません。
]EG]

[30] [[Firefox]] も [[Chrome]] も、異なる[[起源]]の[[約束要求]]を受信した時、
[[ストリームエラー]] [CODE[[[REFUSED_STREAM]]]] とするようです。
[TIME[2015-10-12T10:01:05.800Z]]

[106] [[Firefox]] も [[Chrome]] も、この検査を ([CODE[[[PUSH_PROMISE]]]]
の受信時でも [[fetch]] 時でもなく) 応答の受信時に行うようです。
[TIME[2015-10-12T14:33:56.00Z]]

[111] 同じ [CODE[[[:path]]]] の[[約束要求]]を受信したら、
[[Chrome]] は[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]]、
[[Firefox]] は[[ストリームエラー]] [CODE[[[INTERNAL_ERROR]]]]
とします。この検査は [CODE[[[PUSH_PROMISE]]]] 受信時点で行い、
[[約束ストリーム]]に対して送信します。 [TIME[2015-10-13T02:26:10.300Z]]

[77] [[クライアント]]は、 [[reserved (remote)]] 状態にある[[ストリーム]]の数を制限する[['''べきです''']]。
超過したら[[ストリームエラー]] [CODE[[[ENHANCE_YOUR_CALM]]]]
とできます。 [SRC[>>76]]

* [CODE(HTTP)@en[PUSH_PROMISE]] フレーム

** 意味

[9] [CODE[[[PUSH_PROMISE]]]] [[フレーム]] ([[フレーム型]] [CODE[[[0x5]]]]) は、
[[peer]] に対して[[ストリーム]]を開始することを予め通知するものです [SRC[>>8]]。

[23] [CODE[[[PUSH_PROMISE]]]] によって予約する順序は、その[[ストリーム]]を利用する順序と一致していなくても構いません [SRC[>>8]]。

** 構文

[57] [[ストリーム識別子]]は、[[要求]]が属する[[ストリーム]]を表します [SRC[>>34]]。
0x0 を指定することはできません。

[16] 次の[[フラグ]]があります。
[FIG(list members)[
:[17] [CODE[[[END_HEADERS]]]] ([CODE[[[0x4]]]] = 第2ビット):
設定されていれば、[[header block]] 全体が含まれており、 [CODE[[[CONTINUATION]]]]
[[フレーム]]が続かないことを表します [SRC[>>8]]。
[18] 設定されていなければ、同じ[[ストリーム]]で [CODE[[[CONTINUATION]]]]
[[フレーム]]が続かなければ[['''なりません''']] [SRC[>>8]]。
:[20] [CODE[[[PADDED]]]] ([CODE[[[0x8]]]] = 第3ビット):
設定されていれば、詰め長欄と詰めが存在することを示します [SRC[>>8]]。
]FIG]

[80] 他の[[フラグ]]は、0 でなければ[['''なりません''']]。
[[受信者]]は、無視しなければ[['''なりません''']]。 [SRC[>>79]]

[FIG(packet)[
:width:8

= 1 0
= 1 0
= 1 [CODE[[[END_HEADERS]]]]
= 1 [CODE[[[PADDED]]]]
= 1 0
= 1 0
= 1 0
= 1 0
]FIG]

[11] [[payload]] は、次の欄で構成されます。
[FIG(list members)[
:[12] [RUBYB[[[詰め長]]]@en[Pad Length]]:
[[フレーム]]の詰めの長さを[[バイト]]単位で指定する
8ビットの欄です [SRC[>>8]]。
[CODE[[[PADDED]]]] [[フラグ]]が設定されている場合のみ存在します [SRC[>>8]]。
値は0でも構いません。値が実際の[[詰め]]の長さを超えることは禁止されていませんが、
当然正しく処理できませんし、可能な長さを超えるなら[[接続エラー]]となります。
:[13] [[R]]:
予約されている1ビットです [SRC[>>8]]。
:[10] [DFN[[RUBYB[[[約束ストリームID]]]@en[Promised Stream ID]]]]:
[[送信者]]がで予約する[[ストリーム]]の[[符号無し]]31ビット[[ストリーム識別子]]を示します [SRC[>>8]] ([[ネットワークバイト順]] [SRC[>>78]])。
[[送信者]]が作成する次の[[ストリーム]]の識別子として妥当なものでなければ[['''なりません''']]
[SRC[>>8]]。 [[idle]] 状態でなければなりません [SRC[>>8]]。
これは[RUBYB[関連付けられた]@en[associated]][[ストリーム]]を表します [SRC[>>8]]。
選択方法は[[ストリーム識別子]]を参照。
:[14] [RUBYB[[[ヘッダーブロック素片]]]@en[[[Header Block Fragment]]]]:
[[要求ヘッダー]]を含んだ[[ヘッダーブロック素片]]です [SRC[>>8]]。
:[15] [RUBYB[[[詰め]]]@en[Padding]]:
[[メッセージ]]の長さを隠すための[[セキュリティー]]機能です。
[[送信者]]は、すべて 0 の[[オクテット]]にしなければ[['''なりません''']]。 [SRC[>>29]]
詰め長の長さより、詰めの最大長は、255バイトです。
]FIG]

[FIG(packet)[
:width:32

= 8 詰め長
= 1 R
= 31 ストリーム識別子
= 88... header block fragment
= 32... 詰め
]FIG]

** 文脈

[64] [CODE[[[PUSH_PROMISE]]]] [[フレーム]]は、
任意の[[クライアント]]が開始した[[ストリーム]]に対して、
[[サーバー]]が送信することができます [SRC[>>34]]。

[21] [[peer]] が開始した[[ストリーム]]で状態が [[open]] か [[half-closed (remote)]]
である場合にしか送信しては[['''なりません''']] [SRC[>>8, >>34]]。

[86] 送信すると、指定した約束ストリームIDの[[ストリーム]]の状態は、
[[idle]] から [[reserved (local)]] へと遷移します [SRC[>>83]]。

[3] [[設定]] [CODE[[[SETTINGS_ENABLE_PUSH]]]] が 0 に設定されていれば、 
[CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信しては[['''なりません''']] [SRC[>>1, >>8]]。

[63] [[クライアント]]は、 [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信しては[['''なりません''']]
[SRC[>>34]]。

** 処理

[81] [[受信者]]は、[[payload]] が短すぎるか、[[設定]] [CODE[[[SETTINGS_MAX_FRAME_SIZE]]]]
より長いなら、[[接続エラー]] [CODE[[[FRAME_SIZE_ERROR]]]] としなければ[['''なりません''']]
[SRC[>>82]]。

[4] [[設定]] [CODE[[[SETTINGS_ENABLE_PUSH]]]] を 0 に設定し、 
[[acknowledge]] された[[エンドポイント]]は、
[CODE[[[PUSH_PROMISE]]]] [[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>1, >>8]]。

[22] [[ストリーム識別子]]が [CODE[[[0x0]]]] なら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>8]]。

[108] 未使用の[[ストリーム識別子]]の [CODE[[[PUSH_STREAM]]]]
を受信すると、[[約束ストリーム識別子]]の[[ストリーム]]の側で
[[Firefox]] は[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]]、
[[Chrome]] は[[ストリームエラー]] [CODE[[[STREAM_CLOSED]]]]
とするようです。ただし[[約束ストリーム識別子]]が 0
なら、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] とするようです。
[TIME[2015-10-12T15:43:49.800Z]]

;; 仕様上は[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]。[[ストリーム]]の状態遷移参照。

[109] [[要求]]送信済みで [CODE[[[HEADERS]]]]
受信前の[[ストリーム]] ([CODE[[[PUSH_PROMISE]]]] で作成された[[ストリーム]]含む。)
の[[ストリーム識別子]]で [CODE[[[PUSH_PROMISE]]]]
を受信したら、 [[Firefox]] も [[Chrome]] もエラーとはしません。
[TIME[2015-10-12T15:56:40.700Z]]

[110] [CODE[[[END_STREAM]]]] 受信済みの[[ストリーム]]で [CODE[[[PUSH_PROMISE]]]]
を受信したら、 [[Firefox]] は[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]、
[[Chrome]] は[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] とします。[TIME[2015-10-13T02:07:42.400Z]]

[28] [[約束ストリーム識別子]]が [[idle]] 状態でないなら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>8]]。

[93] 明記されていませんが、[[送信者]]が開始できない[[ストリーム識別子]]や
0の場合も同様に扱うべきと思われます。[[Chrome]] や [[Firefox]]
はそのようにしています。 [TIME[2015-10-12T15:29:02.100Z]]

[26] [[受信者]]は、[[ストリーム]]の状態が [[open]] でも [[half-closed (local)]]
でもなければ、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']]
[SRC[>>8]]。

[27] ただし、[CODE[[[RST_STREAM]]]] を送信した後 (の [[closed]] 状態) には、
受信した [CODE[[[PUSH_PROMISE]]]] を処理しなければ[['''なりません''']] [SRC[>>8, >>83]]。

;; が十分な時間の経過後はエラーとしても構いません [SRC[>>83]]。
[[ストリーム]]の状態遷移の項を参照。

[32] [[受信者]]は、[[詰め]]に 0 以外があれば[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としても構いません。 [SRC[>>29]] 

[33] [[受信者]]は、詰め長が可能な長さより長ければ、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>29]]。

[24] [[受信者]]は、約束された[[ストリーム識別子]]を参照する
[CODE[[[RST_STREAM]]]] [[フレーム]]を返送することで、
約束[[ストリーム]]を拒絶することができます [SRC[>>8]]。

[84] [CODE(HTTP)@en[[[PUSH_PROMISE]]]] [[フレーム]]を受信すると、
その約束ストリームIDの[[ストリーム]]は、[[idle]] 状態から
[[reserved (remote)]] 状態へ遷移します。 [SRC[>>83]]

;; [85] 実際には約束ストリームIDで指定された[[ストリーム]]は存在していないはずですから、
作成して初期状態の [[idle]] 状態となり、直ちに [[reserved (remote)]]
状態に遷移します。

[88] [[約束ストリームID]]の[[ストリーム]]は、[[ストリーム識別子]]の[[ストリーム]]に
([[重み]]は既定値で) [[依存性]]を持つ状態となります [SRC[>>87]]。

;; [[依存性木]]を参照。

[25] [[ストリーム]]の状態遷移の項、[[ヘッダーリスト]]の項も参照。

[19] [CODE[[[END_HEADERS]]]] フラグが設定されていない場合、
次の[[フレーム]]が [CODE[[[CONTINUATION]]]] で無いか、
違う[[ストリーム]]なら、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としなければ[['''なりません''']] [SRC[>>8]]。

[53] [[サーバー]]は、[CODE(HTTP)@en[[[PUSH_PROMISE]]]] [[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。

[107] [CODE[[[PUSH_PROMISE]]]] の[[ヘッダー]]が[[奇形]]な場合、
[[Chrome]] はエラーの種別に応じて[[接続エラー]] [CODE[[[COMPRESSION_ERROR]]]]
または[[約束ストリーム]]の[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]]、
[[Firefox]] は[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] とするようです。
[TIME[2015-10-12T14:38:24.100Z]]

** 関連

[122] 
[[JavaScript]] の [CODE[Promise]]
とは無関係です。

* 設定

[2] [DFN[[CODE[[[SETTINGS_ENABLE_PUSH]]]]]] ([CODE[[[0x2]]]]) は、
[[server push]] を無効化するために使うことができます。 [SRC[>>1]]

[5] 値 1 は、 [[server push]] を認めることを表します。これは初期値です。 [SRC[>>1]]

[6] 値 0 は、 [[server push]] を認めないことを表します [SRC[>>34]]。

[7] [CODE[[[1]]]] と [CODE[[[0]]]] 以外の値は、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としなければ[['''なりません''']] [SRC[>>1]]。

[54] [[クライアント]]は、 [CODE(HTTP)[[[SETTINGS_ENABLE_PUSH]]]]
が [CODE[[[0]]]] 以外の値に設定されようとしたら、
拒絶して[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']]
[SRC[>>34]]。

;; [101] 1 が初期値なので、クライアントは最初エラーになるべき値が設定されていることになりますが、 [[RFC]] ではこの点に特に説明はありません。。。

[102] 実際には [[Chrome]] も [[Firefox]] も、値の検査をしていないようです。
[TIME[2015-10-12T03:20:51.100Z]]

[68] [[クライアント]]は、[[設定]] [CODE[[[SETTINGS_MAX_CONCURRENT_STREAMS]]]]
によって[[サーバー]]が[[並行]]してプッシュできる[[応答]]の数を制限できます。
0 を設定することで、[[server push]] のための[[ストリーム]]の作成を抑制できます。
ただし [CODE[[[PUSH_PROMISE]]]] [[フレーム]]の送信を禁止するものではありません。 [SRC[>>34]]

* fetch と server push

[92] [[Chrome]] や [[Firefox]] は、 [[fetch]] に当たり [CODE[[[PUSH_PROMISE]]]]
を受け取っていれば、新たに[[要求]]を送信せずにその[[応答]]を待つようです。
しかし [[fetch]] の呼び出し方法 (やタイミング?) によって別途[[要求]]を送信することもあります。
[TIME[2015-10-12T10:15:29.700Z]]

* 歴史

** 前史

[127] [CITE[Improving HTTP Latency]], [TIME[2024-10-10T06:01:40.000Z]], [TIME[2001-06-03T06:54:15.439Z]] <https://web.archive.org/web/20010603065233/http://archive.ncsa.uiuc.edu/SDG/IT94/Proceedings/DDay/mogul/HTTPLatency.html>


** HTTP/2

[89] [CITE@ja[IIS 10.0 と ASP.NET 4.6 で HTTP/2 のサーバープッシュが使えるようになっていたので試した - しばやん雑記]]
([TIME[2015-06-06 17:34:09 +09:00]] 版)
<http://blog.shibayan.jp/entry/20150506/1430846908>

[90] [CITE@en[HTTP/2 server push support · Issue #51 · whatwg/fetch]]
([TIME[2015-06-12 12:15:20 +09:00]] 版)
<https://github.com/whatwg/fetch/issues/51>

[91] [CITE[HTTP/2 Push + browser cache - Google ドキュメント]]
([TIME[2015-08-28 20:02:16 +09:00]] 版)
<https://docs.google.com/document/d/1v3rjj0DMDTocUtZSjOwdwt8D-yhCw6R5SVaax4MPgMc/edit?pli=1>

[94] [CITE[Issue 135485 - chromium - SPDY - Pushed stream - crash accessing https://jetty.intalio.com:10111/spdy - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-10-05 20:45:55 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=135485>

[95] [CITE[Issue 377538 - chromium - Robust support for HTTP/2 server-push - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-10-05 20:48:35 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=377538>

[96] [CITE[Issue 328167 - chromium - Server-push for proactive cache management - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-10-05 20:49:28 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=328167>

[97] [CITE@en[958712 – HTTP/2 push continuations not completely implemented]]
([TIME[2015-10-05 20:51:56 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=958712>

[98] [CITE@en[draft-thomson-webpush-http2-02 - Generic Event Delivery Using HTTP Push]]
([TIME[2015-07-19 16:43:54 +09:00]] 版)
<http://tools.ietf.org/html/draft-thomson-webpush-http2-02>

[99] [CITE@en[1072478 – loading never stops due to slow SPDY push]]
([TIME[2015-10-05 20:54:26 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1072478>

[100] [CITE@en[1167851 – HTTP/2 pushes and WINDOW_UPDATA frame]]
([TIME[2015-10-05 20:54:45 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1167851>

[103] [CITE@en[1127618 – PUSH_PROMISE is immediately rejected with a RST_STREAM]]
([TIME[2015-10-12 18:31:29 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1127618>

[104] [CITE[Issue 331663007: Implement PUSH_PROMISE handling in spdy_session - Code Review]]
([TIME[2015-10-12 18:32:45 +09:00]] 版)
<https://codereview.chromium.org/331663007>

[105] [CITE[Issue 331663007: Implement PUSH_PROMISE handling in spdy_session - Code Review]]
([TIME[2015-10-12 18:32:45 +09:00]] 版)
<https://codereview.chromium.org/331663007>

[112] [CITE@en[Preload]]
([TIME[2016-01-30 08:50:22 +09:00]] 版)
<https://w3c.github.io/preload/#server-push-http-2>

[FIG(quote)[
[FIGCAPTION[
[113] [CITE[Announcing Support for HTTP/2 Server Push]]
([TIME[2016-05-01 12:12:30 +09:00]] 版)
<https://blog.cloudflare.com/announcing-support-for-http-2-server-push-2/>
]FIGCAPTION]

> So, if you want to push assets for a given request, you simply add a specially formatted Link header to the response:
> Link: </asset/to/push.js>; rel=preload;

]FIG]


[115] [CITE@en[RFC 8030 - Generic Event Delivery Using HTTP Push]]
([TIME[2016-12-09 04:15:21 +09:00]])
<https://tools.ietf.org/html/rfc8030>

[FIG(quote)[
[FIGCAPTION[
[116] [CITE@en[mod_http2 - Apache HTTP Server Version 2.4]]
( ([TIME[2017-01-15 21:40:17 +09:00]]))
<https://httpd.apache.org/docs/2.4/mod/mod_http2.html#h2push>
]FIGCAPTION]

> Server pushes are detected by inspecting the Link headers of responses (see https://tools.ietf.org/html/rfc5988 for the specification). When a link thus specified has the rel=preload attribute, it is treated as a resource to be pushed.

]FIG]


[117] [CITE@en[google/node-h2-auto-push]]
([TIME[2018-01-17 16:21:14 +09:00]])
<https://github.com/google/node-h2-auto-push>

[118] [CITE@en[preload, destinations, and module scripts · Issue #486 · whatwg/fetch]]
([TIME[2018-03-20 15:19:29 +09:00]])
<https://github.com/whatwg/fetch/issues/486>

[123] [CITE@en[HTTP/2 | 2020 | The Web Almanac by HTTP Archive]]
([TIME[2021-04-24T09:24:01.000Z]])
<https://almanac.httparchive.org/en/2020/http2#goodbye-server-push>

[124] [CITE@en-US[Web Performance Calendar » HTTP/2 Push: The details]]
([TIME[2021-04-24T09:29:24.000Z]])
<https://calendar.perfplanet.com/2016/http2-push-the-details/>

[125] [CITE@ja[Intent to Remove: HTTP/2 and gQUIC server push]]
([TIME[2021-04-24T09:32:23.000Z]])
<https://groups.google.com/a/chromium.org/g/blink-dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ?pli=1>

[126] [CITE@en[b5428cd580034a30c7c76769241ebe565461fc53 - chromium/src - Git at Google]], [TIME[2022-08-23T10:51:04.000Z]] <https://chromium.googlesource.com/chromium/src/+/b5428cd580034a30c7c76769241ebe565461fc53>