この文書は「SPDY Protocol - Draft 3」の日本語訳です。

原文の最新版 は、この日本語訳が参照した版から更新されている可能性があります。
この日本語訳は参考情報であり、正式な文書ではないことに注意してください。また、翻訳において生じた誤りが含まれる可能性があるため、必ず原文もあわせて参照することを推奨します。

公開日:
2013-02-11
更新日:
2013-08-21
翻訳者:
Moto Ishizawa <>
翻訳協力:
Shigeki Ohtsu

1. 概要

HTTP 実装のボトルネックの1つに、並列処理のために複数コネクションを必要とすることがあります。これは、接続確立のために追加で発生するラウンドトリップや、スロースタートによる遅延、そして1つのサーバーに対して複数の接続をおこなうことを避けるためのクライアントによるコネクションの割り当て、といったいくつかの問題を引き起こします。HTTP パイプラインはこれらのいくつかを改善しますが、部分的な多重化を生み出すにすぎません。加えて、パイプラインは様々な影響により既存のブラウザには展開できないことが分かっています。

SPDY は単一の TCP 接続 (または任意の信頼性の高いトランスポートストリーム) を越えて、同時に複数のストリームを多重化するフレーミング層を追加します。

フレーミング層は、Web アプリケーション開発者のために、今日の HTTP 上で動作するようなアプリケーションが少しの変更または変更なしに SPDY 上で動作することができるよう、HTTP のようなリクエスト・レスポンスストリームに最適化されます。

SPDY セッションはHTTP上で4つの改善を提供します:

SPDY は HTTP の既存のセマンティクスの維持を試みます。クッキーや ETags、Vary ヘッダー、Content-Encoding ネゴシエーションやその他の全ての機能が HTTP と同様に動作します。SPDY はネットワークへのデータの出力方法のみを置き換えるものです。

1.1 ドキュメントの構成

この SPDY の仕様は、独立した固定長フレームに TCP 接続の多重化をおこなうフレーミング層 (2章) と、フレーミング層で HTTP リクエスト/レスポンスのペアを扱うための仕組みを定義する HTTP 層 (3章) の2つのパートに分割されています。フレーミング層の概念のいくつかは HTTP 層から分離されています。汎用的なフレーミング層を作ることは目標ではなく、フレーミング層は HTTP プロトコルとサーバープッシュが必要とすることにあわせて作られます。

1.2 定義

2. SPDY フレーミング層

2.1 セッション (接続)

SPDY フレーミング層 (または "セッション") は TCP のような信頼性のあるトランスポート層の上で動作します。クライアントが TCP 接続を開始する側になります。また、SPDY 接続は持続的接続です。

最適なパフォーマンスのために、この層では接続を参照している全ての Web ページからユーザーが離れて移動するか、サーバー側から接続が閉じられるまでは、クライアントは接続を維持することを期待します。サーバーはできるだけ長い間、接続を維持することが推奨されますが、必要に応じてアイドル中の接続を終了することもできます。いずれかのエンドポイントがトランスポート層の接続を終了する場合は、終了する前にリクエストが完了しているかどうかエンドポイントが正確に判断できるように、 GOAWAY (2.6.6節) フレームを最初に送信しなければなりません (MUST)。

2.2 フレーミング

1度接続が確立すると、クライアントとサーバーはフレーム化されたメッセージをやり取りします。フレームには、コントロールフレーム (2.2.1節) と、データフレーム (2.2.2節) の2種類があります。フレームは常に8バイトの長さの共通フレームを持ちます。

最初のビットは、フレームがコントロールフレームかデータフレームかのどちらかを示すコントロールビットです。コントロールフレームはバージョン番号、フレームタイプ、フラグ、そして長さを含みます。データフレームはストリーム ID、フラグ、そして共通ヘッダーの後に送信されたペイロードの長さを含みます。このシンプルなヘッダーは簡単にフレームを入出力できるようにデザインされました。

長さやバージョン番号、タイプなどの全ての整数値はネットワークバイトオーダーで表現されます。SPDY は動的なサイズのフレームにおける型の調整は強制しません。

2.2.1 コントロールフレーム

+----------------------------------+
|C| Version(15bits) | Type(16bits) |
+----------------------------------+
| Flags (8)  |  Length (24 bits)   |
+----------------------------------+
|               Data               |
+----------------------------------+

Control Bit: 'C' ビットはコントロールメッセージかどうかを示す1ビットです。コントロールフレームのこの値は常に1になります。

Version: SPDY プロトコルのバージョン番号です。このドキュメントでは SPDY バージョン3を表します。

Type: コントロールフレームの種類です。コントロールフレームの完全なリストはコントロールフレーム (2.6節) をご覧ください。

Flags: このフレームに関連するフラグです。コントロールフレームとデータフレームではフラグは異なります。

Length: Length フィールド以降のバイトの長さを表す符号なし24ビットの値です。

Data: コントロールフレームに関連するデータです。このデータのフォーマットや長さはコントロールフレームの種類によって管理されます。

コントロールフレームの処理要件:

2.2.2 データフレーム

+----------------------------------+
|C|       Stream-ID (31bits)       |
+----------------------------------+
| Flags (8)  |  Length (24 bits)   |
+----------------------------------+
|               Data               |
+----------------------------------+

Control bit: データフレームではこの値は常に0になります。

Stream-ID: 31ビットのストリーム識別子です。

Flags: このフレームに関連するフラグです。有効なフラグは以下のものになります。

Length: Length フィールド以降のバイトの長さを表す符号なし24ビットの値です。データフレームのサイズの合計は、8バイト + Length になります。長さ0のデータフレームも有効です。

Data: 様々な長さのデータペイロードです。データの長さは Length フィールドで定義されます。

データフレームの処理要件:

2.3 ストリーム

ストリームは、いくつかのプロパティを持つフレームに分割された双方向データの独立したシーケンスです:

2.3.1 ストリームフレーム

SPDY ではストリームのライフサイクルを管理するために3つのコントロールフレームを定義します。

2.3.2 ストリームの作成

ストリームは、Type に SYN_STREAM (2.6.1節) を設定したコントロールフレームの送信にすることで作成されます。サーバーがストリームを開始する場合は、Stream-ID が偶数でなければなりません。同様に、クライアントがストリームを開始する場合は Stream-ID が奇数でなければなりません。0は不正な Stream-ID になります。接続のどちら側からの Stream-ID も、新しいストリームが作成されるごとに連続して値を増加しなければなりません。 例えば、ストリーム2はストリーム3の後に作成されるかもしれませんが、ストリーム7はストリーム9の後に作成されてはいけません。Stream-ID は繰り返しません: クライアントまたはサーバーが31ビットの値を超えずに、新しい Stream-ID を生成することができない場合は、新しいストリームを作成してはいけません (MUST NOT)。

Stream-ID は新しいストリームごとに増加した値でなければなりません (MUST)。エンドポイントが以前受信した SYN_STREAM よりも少ない値の Stream-ID で SYN_STREAM を受信した場合は、ステータスコード PROTOCOL_ERROR を設定したストリームエラー (2.4.2節) を発行しなければなりません (MUST)。

また、2つの SYN_STREAM が同一の Stream-ID で送信された場合もプロトコルエラーになります。 受信者が同一のストリームにおいて2つ目の SYN_STREAM を受信した場合も同様に、ステータスコード PROTOCOL_ERROR を設定したストリームエラー (2.4.2節) を発行しなければなりません (MUST)。

SYN_STREAM の受信した受信者は、エラーコード REFUSED_STREAM を設定したストリームエラー (2.4.2節) を送信することで、ストリームを拒否することができます。しかしながら、作成側エンドポイントはそのストリームをすぐに停止することができず、追加のフレームをすでに送信しているかもしれないことに注意してください。

ストリームは一度作成されると、受信者の応答を待つ必要なく、作成側エンドポイントはそのストリームに HEADERS フレームや DATA フレームをすぐに送信してもよいものとします。

2.3.2.1 単方向ストリーム

エンドポイントが FLAG_UNIDIRECTIONAL をフラグに設定して作成したストリームは、単方向ストリームになります。これは、作成したエンドポイントはフレームを送信することができますが、受信をすることはできません。受信側エンドポイントはすでに半切断 (2.3.6節) 状態として認識します。

2.3.2.2 双方向ストリーム

FLAG_UNIDIRECTIONAL フラグを仕様していない SYN_STREAM フレームは双方向ストリームになります。両側のエンドポイントが双方向ストリーム上でデータを送信することができます。

2.3.3 ストリームの優先度

ストリームを作成したエンドポイントは、ストリームの優先度を指定します。優先度は0から7までの整数で表現されます。0はもっとも優先度が高いことを示し、7はもっとも優先度が低いことを示します。

送信者と受信者は、優先度の高い順にストリームを処理するためにベストエフォートを使うべきです (SHOULD)。

2.3.4 ストリームヘッダー

ストリームは、自身に関連するメタデータを転送するための任意の Name/Value ペアのヘッダーセットを運ぶことができます。ストリームが作成され、送信者が終了 (2.3.7節) や半切断 (2.3.6節) をしていない限り、両側のエンドポイントはヘッダーデータを含む HEADERS フレームを送信することがあります。ヘッダーデータは複数の HEADERS フレームで送信することができ、複数のデータフレームの間に挟まって送信されることがあります。

2.3.5 ストリームでのデータ交換

ストリームが1度作成されると、それは任意の数のデータを送信するために使用することができます。一般的に、これは FLAG_FIN フラグが設定されたフレームまでの一連のデータフレームを、ストリーム上で送信することを意味します。FLAG_FIN は SYN_STREAM (2.6.1節) や SYN_REPLY (2.6.2節)、HEADERS (2.6.7節)、DATA (2.2.2節) フレームに設定することができます。FLAG_FIN が一度でも送信されると、ストリームは半切断として判断されます。

2.3.6 ストリームの半切断

ストリームの片側から FLAG_FIN フラグが設定されたフレームが送信されると、そのストリームはそのエンドポイントからみて半切断となります。FLAG_FIN の送信者はそのストリーム上でさらにフレームを送信してはいけません (MUST NOT)。ストリームの両側で半切断状態となった時、そのストリームは終了します。

ストリームが送信者から半切断された後に、エンドポイントがデータフレームを受信した場合 (例: そのエンドポイントはすでにそのストリームで FLAG_FIN フラグが設定されたフレームを受信した)、STREAM_ALREADY_CLOSED ステータスコードと共に、RST_STREAM を送信者に送信しなければなりません (MUST)。

2.3.7 ストリームの終了

ストリームは3つの方法で終了されます。

エンドポイントがストリームの終了後にデータフレームを受信した場合、送信者に対してステータスコード PROTOCOL_ERROR と共に RST_STREAM を送信する必要があります。

2.4 エラー処理

SPDY フレーミング層には2種類のエラーしかなく、常に一貫してエラー処理されます。この仕様における "セッションエラーを発行する" ことへの言及については、2.4.1節を参照してください。また、"ストリームエラーを発行する" ことへの言及については、2.4.2節を参照してください。

2.4.1 セッションエラー処理

セッションエラーとは、セッションの圧縮状態を破壊するものや、フレーミング層の処理の妨げになるエラーです。

セッションエラーが発生した時、エラーが発生したエンドポイントは、リモートエンドポイントからストリームで受信した最新のストリーム ID やセッションが中断された理由となるエラーコードと共に、最初に GOAWAY (2.6.6節) フレームを送信しなければなりません (MUST)。GOAWAY フレームを送信した後、そのエンドポイントは TCP 接続を終了しなければなりません (MUST)。

セッションの圧縮状態は、両側のエンドポイントが常に全ての圧縮データを処理することに依存するので注意してください。エンドポイントが圧縮状態を適切に更新せずに圧縮されたデータを含むフレームを部分処理すると、以降に圧縮を使用するコントロールフレームは全てエラーとなります。実装はストリームエラーとして扱うことができたエラーは、セッションエラーとならないように圧縮データを常に処理しようとするべきです (SHOULD)。

GOAWAY はセッションエラーの発生中に送られてくるので、受信者は期待通りに GOAWAY を受信することができない可能性があることに注意してください。セッションが終了する理由についてリモートとやり取りすることは、ベストエフォートの試みになります。

2.4.2 ストリームエラー処理

ストリームエラーとは、フレーミング層での他のストリームの処理に影響しない Stream-ID に関連するエラーです。ストリームエラーが発生したエンドポイントは、エラーが発生したストリームのストリーム ID と、発生したエラーのエラーステータスを含めた RST_STREAM (2.6.3節) フレームを送らなければなりません (MUST)。RST_STREAM を送信した後には、送信先エンドポイントとのストリームを終了します。RST_STREAM を送信後に、送信者が同じストリームIDの RST_STREAM 以外のフレームを受信した場合、追加の RST_STREAM フレームを送信することになります。エンドポイントは RST_STREAM のレスポンスとして RST_STREAM を送信してはいけません (MUST NOT)。これは RST_STREAM ループにつながるためです。RST_STREAM を送信することで SPDY セッションが終了することはありません。

もしエンドポイントが、同じ Stream-ID かつ同じエラーコードで連続して送信する複数の RST_STREAM フレームを保持しているなら、それらを1つの RST_STREAM フレームにまとめてもよいものとします(MAY)。(これはストリームが終了しているのに、リモートが複数のデータフレームを送信する場合に発生する可能性があります。各フレームに対して連続して RST_STREAM を送信する理由はないでしょう。)

2.5 データの流れ

TCP は単一のデータストリームを提供し、SPDY はその上で複数の論理ストリームを多重化しています。そのためクライアントとサーバーが同時セッションを実現するにはデータメッセージをうまく織り交ぜなければなりません。

2.6 コントロールフレームの種類

2.6.1 SYN_STREAM

SYN_STREAM コントロールフレームは、送信者がエンドポイント間のストリームを非同期で作成するためのものです。ストリームの作成 (2.3.2節) もご覧ください。

+------------------------------------+
|1|    version    |         1        |
+------------------------------------+
|  Flags (8)  |  Length (24 bits)    |
+------------------------------------+
|X|           Stream-ID (31bits)     |
+------------------------------------+
|X| Associated-To-Stream-ID (31bits) |
+------------------------------------+
| Pri|Unused | Slot |                |
+-------------------+                |
| Number of Name/Value pairs (int32) |   <+
+------------------------------------+    |
|     Length of name (int32)         |    | このセクションは "Name/Value のヘッダーブロック"
+------------------------------------+    | であり、圧縮されます。
|           Name (string)            |    |
+------------------------------------+    |
|     Length of value  (int32)       |    |
+------------------------------------+    |
|          Value   (string)          |    |
+------------------------------------+    |
|           (repeats)                |   <+

Flags: このフレームに関連するフラグです。有効なフラグは以下の通りです:

Length: フレームの Length フィールド以降のバイト数の長さを示します。SYN_STREAM フレームでは、圧縮された Name/Value ブロックの長さに10バイトが加えた値になります。

Stream-ID: 31ビットのストリーム識別子です。Stream-ID はこのストリームのフレーム内で使われます。

Associated-To-Stream-ID: このストリームに関連するストリームの31ビットの識別子です。このストリームが他のストリームから独立している場合は、この値は0にするべきです。

Priority: 3ビットの優先度 (2.3.3節) フィールドです。

Unused: 5ビットの未使用領域です。今後の利用のために予約されています。

Slot: このリクエストに使用されるクライアント証明書の、サーバー側における CREDENTIAL ベクトルインデックスを指定するための、8ビットの符合なし整数です。CREDENTIAL フレーム (2.6.9節) もあわせてご覧ください。この値が0であれば、このストリームに関連するクライアント証明書が存在しないことを意味します。

Name/Value Header Block: SYN_STREAM の一部として伝送される Name/Value のセットです。詳しくは Name/Value ヘッダーブロック (2.6.10節) をご覧ください。

実装がサポートするよりも巨大な SYN_STREAM をエンドポイントが受信した場合、エラーコード FRAME_TOO_LARGE と共に RST_STREAM を送信してもよいものとします (MAY)。全ての実装はコントロールフレーム (2.2.1節) で定義した最小サイズの制限はサポートしなければなりません (MUST)。

2.6.2 SYN_REPLY

SYN_REPLY は、SYN_STREAM フレームの受信者がストリームの作成を受け入れることを示します。

+------------------------------------+
|1|    version    |         2        |
+------------------------------------+
|  Flags (8)  |  Length (24 bits)    |
+------------------------------------+
|X|           Stream-ID (31bits)     |
+------------------------------------+
| Number of Name/Value pairs (int32) |   <+
+------------------------------------+    |
|     Length of name (int32)         |    | このセクションは "Name/Value のヘッダーブロック"
+------------------------------------+    | であり、圧縮されます。
|           Name (string)            |    |
+------------------------------------+    |
|     Length of value  (int32)       |    |
+------------------------------------+    |
|          Value   (string)          |    |
+------------------------------------+    |
|           (repeats)                |   <+

Flags: このフレームに関連するフラグです。有効なフラグは以下の通りです:

Length: フレームの Length フィールド以降のバイト数の長さを示します。SYN_REPLY フレームでは、圧縮された Name/Value ブロックの長さに4バイトを加えた値になります。

Stream-ID: 31ビットのストリーム識別子です。

エンドポイントが有効なストリーム ID の SYN_REPLY フレームを複数受信した場合は、エラーコード STREAM_IN_USE と共にストリームエラー (2.4.2節) を発行しなければなりません (MUST)。

Name/Value Header Block: SYN_REPLY の一部として伝送される Name/Value のセットです。詳しくは Name/Value ヘッダーブロック (2.6.10節) をご覧ください。

実装がサポートするよりも巨大な SYN_REPLY をエンドポイントが受信した場合、エラーコード FRAME_TOO_LARGE と共に RST_STREAM を送信してもよいものとします (MAY)。全ての実装はコントロールフレーム (2.2.1節) で定義した最小サイズの制限はサポートしなければなりません (MUST)。

2.6.3 RST_STREAM

RST_STREAM フレームはストリームを異常終了するためのものです。ストリームの作成者が送信した時は、作成者がストリームのキャンセルを期待することを示します。ストリームの受信者が送信した時には、エラーまたは受信者がストリームの受け入れを拒否することを示し、ストリームを終了しなければなりません。

+----------------------------------+
|1|   version    |         3       |
+----------------------------------+
| Flags (8)  |         8           |
+----------------------------------+
|X|          Stream-ID (31bits)    |
+----------------------------------+
|          Status code             |
+----------------------------------+

Flags: このフレームに関連するフラグです。RST_STREAM にはフラグが定義されていないため、この値は常に0でなければなりません。

Length: フレームの Length フィールド以降のバイト数を表す、符号なし24ビットの値です。RST_STREAM コントロールフレームは、この値が常に8になります。

Stream-ID: 31ビットのストリーム識別子です。

Status code: (32ビット) ストリームが終了した理由を示します。定義されているステータスコードは以下の通りです:

ストリームから RST_STREAM を受信した後、受信者はそのフレームに対してさらにフレームを送信してはならず、ストリームを終了状態にします。

2.6.4 SETTINGS

SETTINGS フレームには、2つのエンドポイント間での通信方式に関する設定データをやりとりするためのID/値ペアのセットが含まれています。SETTINGS フレームは両側のエンドポイントが必要に応じていつでも送信することができ、完全に非同期です。サーバーが送信側である場合、設定データが SPDY セッションをまたいでクライアントにより保持され、今後のやり取りにおいてその設定でサーバーに返すようにリクエストすることができます。

SETTINGS のID/値ペアの永続化は、オリジン/IPのペアごとにおこなわれます (オリジンとは、URI におけるスキーム、ホスト、ポートからなります。詳しくは RFC6454 をご覧ください)。クライアントがサーバーに接続し、サーバーがクライアント内に設定を永続化した場合、クライアントは同じ IP アドレスと TCP ポートのオリジンに対する将来的な接続では、永続化された設定を返すべきです (SHOULD)。クライアントはサーバーに対して、SETTINGS フレームの永続化機能を使用してリクエストしてはいけません (MUST NOT)。また、サーバーはクライアントから永続化に関するフラグが送信された場合は無視しなければなりません (MUST)。

+----------------------------------+
|1|   version    |         4       |
+----------------------------------+
| Flags (8)  |  Length (24 bits)   |
+----------------------------------+
|         Number of entries        |
+----------------------------------+
|          ID/Value Pairs          |
|             ...                  |

Control bit: このメッセージではコントロールビットは常に1になります。

Version: SPDY のバージョン番号です。

Type: SETTINGS メッセージのタイプは4です。

Flags: FLAG_SETTINGS_CLEAR_SETTINGS (0x1): このフラグが設定された時、クライアントは以前永続化した SETTINGS ID/値ペアを削除するべきです。フレームに FLAG_SETTINGS_PERSIST_VALUE が設定され、ID/値ペアを保持していた場合には、クライアントは最初に既存の永続化設定を削除し、そのフレームに含まれるフラグが設定された値を永続化します。永続化はクライアントにのみ実装されるため、送信者がサーバーである時にのみフラグを使うことができます。

Length: Length フィールド以降のバイト数を表す、符号なし24ビットの値です。SETTINGS フレームの合計サイズは8バイト + Length になります。

Number of entries: メッセージに含まれるID/値ペアの数を表す32ビットの値です。

各ID/値ペアは以下のように表現されます:

+----------------------------------+
| Flags(8) |      ID (24 bits)     |
+----------------------------------+
|          Value (32 bits)         |
+----------------------------------+

Flags: 8ビットの値です。定義済みフラグは以下のとおりです:

ID: ネットワークバイトオーダーの24ビットです。定義済みIDは以下の通りです:

Value: 32ビットの値です。

このメッセージは、クライアント・サーバー間通信を拡張することになるかもしれない将来的なデータのためにわざと拡張可能にしています。送信者はID/値の全てのタイプを送信する必要はありません。伝送するための正確な値を持っているものだけを送信する必要があります。複数のID/値ペアを送信する時には、値が少ないIDから順番に送られるべきです。1つの SETTINGS フレームに、同じ ID に対する値を複数含んではいけません (MUST NOT)。SETTINGS フレームの受信者が同じ ID に対する値を複数見つけた場合は、最初の1つ以外の全ての値を無視しなければなりません (MUST)。

サーバーは異なるID/値ペアを含む複数の SETTINGS フレームを送信する可能性があります。同じID/値ペアが2度送られた場合、もっとも新しい値が以前送られた値を上書きします。サーバーが最初の SETTINGS フレームで FLAG_SETTINGS_PERSIST_VALUE と共に ID 1、2、3 を送信し、さらに FLAG_SETTINGS_PERSIST_VALUE と共に、ID 4、5 を送信した場合、クライアントが永続化状態の SETTINGS フレームを返す時に、5つの設定の全て (この例では1、2、3、4、5) をサーバーに送信すべきです (SHOULD)。

2.6.5 PING

PING コントロールフレームは、送信者から最短のラウンドトリップ時間を計測するための仕組みです。これはクライアントとサーバーから送信することができます。PING フレームの受信者は、可能な限り早く同一フレームを送信者に送るべきです (他に送信待ちデータがあった場合でも、PING は最優先で送信すべきです)。送信者から送られる各 PING はユニーク ID を使用すべきです。

+----------------------------------+
|1|   version    |         6       |
+----------------------------------+
| 0 (flags) |     4 (length)       |
+----------------------------------|
|            32-bit ID             |
+----------------------------------+

Control bit: このメッセージではコントロールビットは常に1になります。

Version: SPDY のバージョン番号です。

Type: PING メッセージのメッセージタイプは6になります。

Length: このフレームは常に4バイトの長さです。

ID: 符合なし32ビットの値で表現される、この PING のためのユニークな ID です。クライアントが PING を開始した時は、奇数の ID を使わなければなりません。また、サーバーが PING を開始した場合は、偶数の ID を使用しなければなりません。奇数/偶数の ID の使用は、(両側がまったく同じ PING を同時に開始した時のような) 偶発的な PING のループを避けるために必要になります。

注: もし送信者が利用可能な PING ID を全て使ってしまった (ID として利用可能な 2^31 個を全て送信した) 場合、ID を循環させて再利用することができます。

サーバーが開始していない偶数の PING を受信した場合は、その PING は無視しなければなりません。同様にクライアントが開始していない奇数の PING を受信した場合も、その PING は無視しなければなりません。

2.6.6 GOAWAY

GOAWAY コントロールフレームは、セッション上でのストリームの作成を停止するために、リモート側の接続に通知する仕組みです。これはクライアントとサーバーの両方から送信することができます。このフレームが送信されると、送信者はそのセッションの SYN_STREAM には応答しません。GOAWAY フレームの受信者は、そのセッション上に追加フレームを送信してはいけません。しかし、新しいストリームのために新しいセッションを確立することはできます。このメッセージの目的は、以前確立したストリームの処理を完了している間に、エンドポイントが (メンテナンスや再起動などのために) 正常に新しいストリームの受け入れを停止できるようにすることです。

SYN_STREAM を送信したエンドポイントと GOAWAY メッセージを送信するリモート間には、特定の競合関係が存在します。このような場合に対処するために、GOAWAY はセッションにおいて送信側エンドポイントが作成した最後のストリームの Stream-ID を示す last-stream-id を含みます。GOAWAY の受信者が last-stream-id のあとでセッションに新しい SYN_STREAM を送信した場合、それらはサーバーによって処理されず、受信者はストリームが作成されなかったかのように扱うかもしれません (したがって、受信者は新しいストリーム上でそのストリームを再作成することになります)。

リモートがストリームが部分的に処理された状態かどうかを判断することができるように、 エンドポイントは接続を終了する前は、常に GOAWAY メッセージを送信するべきです (例えば、HTTP クライアントが POST を送信したと同時にサーバーが接続を終了したような場合、サーバーが POST リクエストの処理を開始したのか、サーバーが処理を中止したことを示す GOAWAY フレームを送信しなかったのか、クライアントは判断することができません)。

GOAWAY メッセージを送信後は、送信者は新しいストリームの SYN_STREAM フレームを全て無視しなければなりません。

+----------------------------------+
|1|   version    |         7       |
+----------------------------------+
| 0 (flags) |     8 (length)       |
+----------------------------------|
|X|  Last-good-stream-ID (31 bits) |
+----------------------------------+
|          Status code             |
+----------------------------------+

Control bit: このメッセージではコントロールビットは常に1になります。

Version: SPDY のバージョン番号です。

Type: GOAWAY メッセージのメッセージタイプは7になります。

Length: このフレームは常に8バイトの長さです。

Last-good-stream-id: GOAWAY メッセージの送信者が、最後に受信したストリームのストリーム ID です。 返信先のストリームが存在しない場合は、この値は0でなければなりません。

Status: セッションを終了する理由です。

2.6.7 HEADERS

HEADERS フレームは追加ヘッダーによりストリームを補うものです。これは、必要に応じていつでも既存のストリームに送信されることがあります。このフレームにおけるヘッダーの利用方法は、アプリケーションに依存します。フレーム内の Name/Value ヘッダーは圧縮されます。

+------------------------------------+
|1|   version     |          8       |
+------------------------------------+
| Flags (8)  |   Length (24 bits)    |
+------------------------------------+
|X|          Stream-ID (31bits)      |
+------------------------------------+
| Number of Name/Value pairs (int32) |   <+
+------------------------------------+    |
|     Length of name (int32)         |    | このセクションは "Name/Value のヘッダーブロック"
+------------------------------------+    | であり、圧縮されます。
|           Name (string)            |    |
+------------------------------------+    |
|     Length of value  (int32)       |    |
+------------------------------------+    |
|          Value   (string)          |    |
+------------------------------------+    |
|           (repeats)                |   <+

Flags: このフレームに関連するフラグです。有効なフラグは以下の通りです:

Length: Length フィールド以降のバイト数を表す、符号なし24ビットの値です。Length フィールドの最小の長さは4になります (Name/Value ペアの数が0の場合)。

Stream-ID: HEADERS ブロックに関連するストリームです。

Name/Value Header Block: SYN_STREAM の一部を伝送する Name/Value のセットです。詳しくは Name/Value ヘッダーブロック (2.6.10節) をご覧ください。

2.6.8 WINDOW_UPDATE

WINDOW_UPDATE コントロールフレームは SPDY におけるストリームごとのフロー制御に使用されます。SPDY のフロー制御はホップごと、つまり SPDY 接続の2つのエンドポイントの間でのみおこなわれます。クライアントとオリジンサーバーの間に1つ以上の中継者がいる場合、フロー制御信号は明示的に中継者から転送されません。(しかしながら、受信者によるデータ転送スロットリングは、間接的に上流にいる送信者にフロー制御情報を伝える効果があります。) フロー制御はデータフレームのデータ部にのみ適用されます。受信者は全てのコントロールフレームをバッファリングしなければなりません。受信者がコントロールフレーム全体のバッファリングに失敗した場合、FLOW_CONTROL_ERROR ステータスコードと共に、ストリームに対してストリームエラー (2.4.2節) を発生しなければなりません (MUST)。

SPDY におけるフロー制御は、各ストリームの送信者により保持されるデータ転送ウインドウで実装されています。データ転送ウインドウは、送信者が転送することができるデータのバイト数がどれぐらいかを表すシンプルな32ビットの符合なし整数です。ストリームが作成された後でかつデータフレームが転送される前では、送信者は初期ウインドウサイズから開始します。このウインドウサイズは受信者のバッファリング能力を測るものです。送信者は転送ウインドウサイズより大きい長さのデータをデータフレームで送信してはいけません。各データフレームを送信した後、送信者は転送済みのデータ量に応じて転送ウインドウサイズを減らします。ウインドウサイズが0またはそれ以下になった時、送信者はデータフレームの転送を中断しなければなりません。ストリームの反対側にいる受信者は、いくつかのデータを処理し、より多くのデータを受信するためのバッファ領域を解放したことを通知するため、WINDOW_UPDATE コントロールフレームを送信します。

+----------------------------------+
|1|   version    |         9       |
+----------------------------------+
| 0 (flags) |     8 (length)       |
+----------------------------------+
|X|     Stream-ID (31-bits)        |
+----------------------------------+
|X|  Delta-Window-Size (31-bits)   |
+----------------------------------+

Control bit: このメッセージではコントロールビットは常に1になります。

Version: SPDY のバージョン番号です。

Type: GOAWAY メッセージのメッセージタイプは9になります。

Length: Length フィールドはこのフレームでは常に8です (Length フィールド以降は8バイト)。

Stream-ID: WINDOW_UPDATE コントロールフレームが適用されるストリーム ID です。

Delta-Window-Size: 送信者が既存の残りウインドウサイズに加えて、追加で送信可能なバイト数です。このフィールドの適切な範囲は1から2^31 - 1 (0x7fffffff) バイトです。

送信者が確保するウインドウサイズは2^31バイトを越えてはいけません (しかしながら、ある特別なケースにおいては、負数になります)。ウインドウサイズが限界を超えた場合に発生する WINDOW_UPDATE を送信者が受信した場合には、ストリームを終了するために、ステータスコード FLOW_CONTROL_ERROR と共に RST_STREAM を送信しなければなりません。

SPDY の接続が最初に確立した時、全てのストリームのデフォルト初期ウインドウサイズは64KBになります。エンドポイントは SETTINGS コントロールフレームを使って、接続のための初期ウインドウサイズを調整することができます。SETTINGS フレームを受信する前にデータフレームを送信する場合、ピアは64KBのデフォルト初期ウインドウサイズから送信を開始することができます。SETTINGS は非同期であるため、受信者が初期ウインドウサイズを減らすことを期待しても、その設定が到着するのを待つ前にピアが新しい接続をおこない、すぐに64KBを送信した場合は競合状態となるかもしれません。これは、送信者に確保されるウインドウサイズが負数になるケースの1つです。送信者がこの状態を検出した場合、データフレームの送信を停止し、受信者が追いつくのを待たなければなりません。この時、受信者は2つの選択ができます:

2つめのオプションのケースでは、両側のエンドポイントが SETTINGS の初期ウインドウサイズを元にウインドウサイズを計算しなければなりません。例えば、受信者が初期ウインドウサイズを16KBに設定し、送信者が接続確立時に64KBをすぐに送信した場合、送信者は SETTINGS への返信のウインドウサイズが -48KB になることを検知します。そして、受信者が最初の16KBを処理して、送信者に 16KB の WINDOW_UPDATE を送信しなければなりません。このやり取りは送信者のウインドウサイズが正の値になり、データフレームの送信が再開できるまで繰り返し続けます。

データストリームの終わりを示す FLAG_FIN が設定されたデータフレームを受信者が読み込んだ後には、最後のデータフレームを処理するための WINDOW_UPDATE フレームを送信するべきではありません。送信者は、最後のフレームを送信した後のストリームに関連する WINDOW_UPDATE フレームを全て無視するべきです。

送信者からのデータフレームと、受信者からの WINDOW_UPDATE フレームは、お互いに完全非同期になります。この特性はストリームの停止を防ぐために、送信者が保持するウインドウサイズを受信者が積極的に更新することを可能にします。

2.6.9 CREDENTIAL

CREDENTIAL コントロールフレームはクライアントが追加のクライアント証明書をサーバーに送信するために使用します。対象のサーバーが2つのオリジンを扱うことが決まっている場合に、SPDY クライアントは同一の SPDY セッション上で異なるオリジンのリソースに対するリクエストを送信しようとするかもしれません。これは2つのホストネームに紐づく IP アドレスが一致し、初期ハンドシェイクにおける SSL サーバー証明書が両方のホストネームに有効な場合などに適用されます。SSL 接続では、最大で1つのクライアント証明書を含めることしかできないので、クライアントはサーバーに追加のクライアント証明書を送信するための仕組みが必要になります。

サーバーは SPDY セッションに関連するクライアント証明書ベクトルを保持する必要があります。クライアントがサーバーにクライアント証明書を送信する必要がある時、クライアントはスロットのインデックスを指定した CREDENTIAL フレームを送信します。そのフレームは、証明書やクライアントが対応する秘密鍵を所有しているという proof も保持しています。ベクトルの初期サイズは8バイトです。クライアントが最初の TLS ハンドシェイクの間にクライアント証明書を提供した場合、その証明書の内容は CREDENTIAL ベクトルの最初のスロット (インデックス1) にコピーされます。これは、その後に送信される CREDENTIAL フレームにより上書きされるかもしれません。サーバーは、オリジンに関連するクライアント証明書を評価するまで、CREDENTIAL ベクトルを限定的に使用しなければなりません。SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE 値を指定した SETTINGS フレームを送信することによって、サーバーはベクトルのサイズを変更するかもしれません。新しいサイズが現在のベクトルサイズよりも小さい場合は、小さいインデックススロットを可能な限り維持するために切り捨てが発生します。

クライアント認証を伴った TLS 再ネゴシエーションは SPDY の特徴である多重化とは相容れません。具体的には、 (異なるタブにある) 2つの異なるページに対して、クライアントがサーバで未処理のリクエストを2つ持っていることを想像してみてください。この時、再ネゴシエーション + クライアント証明書がリクエストされると、ブラウザはどちらのリソースがクライアント証明書リクエストを引き起こしたのかわかりません。ブラウザは、リクエストに応じてユーザに prompt を表示するための決定を行うことができないのです。

+----------------------------------+
|1|000000000000011|0000000000001010|
+----------------------------------+
| flags (8)  |  Length (24 bits)   |
+----------------------------------+
|  Slot (16 bits) |                |
+-----------------+                |
|      Proof Length (32 bits)      |
+----------------------------------+
|               Proof              |
+----------------------------------+ <+
|   Certificate Length (32 bits)   |  |
+----------------------------------+  | フレームの最後まで繰り返されます。
|            Certificate           |  |
+----------------------------------+ <+

Slot: 証明書が保存されるべきサーバーのクライアント証明書ベクトルにおけるインデックスです。すでにインデックスに証明書が保存されている場合は、それを上書きします。インデックスは0からではなく1からはじまります。0は不正なスロットインデックスになります。

Proof: 証明書に関連し、クライアントが所有する秘密鍵の暗号証明です。フォーマットは、TLS digitally-signed 要素となります。 (http://tools.ietf.org/html/rfc5246#section-4.7)。署名アルゴリズムは CertificateVerify メッセージで使用されるものと同じでなければなりません。しかしながら、TLS 1.0 接続で使われてきた MD5+SHA1 署名タイプは TLS digitally-signed 要素では正しくエンコードできないため、SSL 接続において MD5+SHA1 が使用された場合には、SHA1 を使用しなければなりません。署名は、コンテキストとして空の文字列を使用し、 "EXPORTER SPDY certificate proof" のラベルを付けて 32バイトの TLS extractor value (http://tools.ietf.org/html/rfc5705) から算出されます。RSA 証明書の署名は PKCS#1 v1.5 署名です。ECDSA では、ECDSA-Sig-Value (http://tools.ietf.org/html/rfc5480#appendix-A) を使用します。1024ビット RSA 鍵での CREDENTIAL メッセージは500バイト以下になります。

Certificate: リーフ証明書からはじまる証明書チェーンです。各証明書は DER エンコードされた後に、32ビットの長さでエンコードされていなければなりません。この証明書は SSL 接続に関連付けられているクライアント証明書と同じ種類 (RSA、ECDSA、など) でなければなりません。

サーバーが受け入れられない (欠落しているか、不正な) 証明書とリソースへのリクエストを受信した場合は、INVALID_CREDENTIALS のステータスコードとともに RST_STREAM フレームを返さなければなりません。INVALID_CREDENTIALS の RST_STREAM フレームを受信すると、クライアントはリクエストされたオリジンに対して直接新しいストリームを開始し、リクエストを再度送信するべきです。注: SPDY では、サーバーが同一オリジンにある異なるリソースに対して、異なるクライアント証明書をリクエストすることはできません。

サーバーが不正な CREDENTIAL フレームを受信した場合、GOAWAY フレームを返して、セッションを終了しなければなりません (MUST)。

2.6.10 Name/Value ヘッダーブロック

Name/Value ヘッダーブロックは SYN_STREAM や SYN_REPLY、HEADERS コントロールフレーム内に存在し、共通のフォーマットを共有します。

+------------------------------------+
| Number of Name/Value pairs (int32) |
+------------------------------------+
|     Length of name (int32)         |
+------------------------------------+
|           Name (string)            |
+------------------------------------+
|     Length of value  (int32)       |
+------------------------------------+
|          Value   (string)          |
+------------------------------------+
|           (repeats)                |

Number of Name/Value pairs: このフィールドに続く、Name/Value ペアの繰り返しの数です。

Name/Valueペアのリスト:

各ヘッダー名は、1つ以上の値をもっていなければなりません。ヘッダー名は US-ASCII 文字セット [ASCII] を使ってエンコードされ、全て小文字でなければなりません。また、Name はそれぞれ0より大きい長さでなければなりません。長さが0の Name を受信した場合は、そのストリーム ID に対してステータスコード PROTOCOL_ERROR と共にストリームエラー (2.4.2節) を発生しなければなりません (MUST)。

ヘッダー名の重複は認められていません。同じ Name のヘッダーを2つ送信するには、NUL (0) バイトで区切られた2つの Value を持つ1つのヘッダーを送信します。ヘッダー Value は空 (例: 長さが0) であったり、NUL で区切られた(それぞれの長さが0より大きい) 複数の Value を含めたりすることができます。また、Value は NUL 文字で開始したり、終わることはできません。不正な Value フィールドを受け取った受信者は、そのストリーム ID に対して PROTOCOL_ERROR のステータスコードと共にストリームエラー (2.4.2節) を発生しなければなりません (MUST)。

2.6.10.1 圧縮

Name/Valueヘッダーブロックは、メタデータのヘッダーを転送するために SYN_STREAM、SYN_REPLY、そして HEADERS フレームの一部に使用されます。このブロックは zlib 圧縮を使って常に圧縮されます。この仕様における 'zlib' という表記は、RFC1950 の一部である ZLIB 圧縮データフォーマットのバージョン3.3を参照します。

各 HEADERS 圧縮インスタンスの初期状態には、以下の辞書 [UDELCOMPRESSION] を使用して初期化されます:

const unsigned char SPDY_dictionary_txt[] = {
    0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,   \\ - - - - o p t i
    0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,   \\ o n s - - - - h
    0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,   \\ e a d - - - - p
    0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,   \\ o s t - - - - p
    0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,   \\ u t - - - - d e
    0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,   \\ l e t e - - - -
    0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,   \\ t r a c e - - -
    0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,   \\ - a c c e p t -
    0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,   \\ - - - a c c e p
    0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,   \\ t - c h a r s e
    0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,   \\ t - - - - a c c
    0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,   \\ e p t - e n c o
    0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,   \\ d i n g - - - -
    0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,   \\ a c c e p t - l
    0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,   \\ a n g u a g e -
    0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,   \\ - - - a c c e p
    0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,   \\ t - r a n g e s
    0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,   \\ - - - - a g e -
    0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,   \\ - - - a l l o w
    0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,   \\ - - - - a u t h
    0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,   \\ o r i z a t i o
    0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,   \\ n - - - - c a c
    0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,   \\ h e - c o n t r
    0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,   \\ o l - - - - c o
    0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,   \\ n n e c t i o n
    0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,   \\ - - - - c o n t
    0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,   \\ e n t - b a s e
    0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,   \\ - - - - c o n t
    0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,   \\ e n t - e n c o
    0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,   \\ d i n g - - - -
    0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,   \\ c o n t e n t -
    0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,   \\ l a n g u a g e
    0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,   \\ - - - - c o n t
    0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,   \\ e n t - l e n g
    0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,   \\ t h - - - - c o
    0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,   \\ n t e n t - l o
    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,   \\ c a t i o n - -
    0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,   \\ - - c o n t e n
    0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,   \\ t - m d 5 - - -
    0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,   \\ - c o n t e n t
    0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,   \\ - r a n g e - -
    0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,   \\ - - c o n t e n
    0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,   \\ t - t y p e - -
    0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,   \\ - - d a t e - -
    0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,   \\ - - e t a g - -
    0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,   \\ - - e x p e c t
    0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,   \\ - - - - e x p i
    0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,   \\ r e s - - - - f
    0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,   \\ r o m - - - - h
    0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,   \\ o s t - - - - i
    0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,   \\ f - m a t c h -
    0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,   \\ - - - i f - m o
    0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,   \\ d i f i e d - s
    0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,   \\ i n c e - - - -
    0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,   \\ i f - n o n e -
    0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,   \\ m a t c h - - -
    0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,   \\ - i f - r a n g
    0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,   \\ e - - - - i f -
    0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,   \\ u n m o d i f i
    0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,   \\ e d - s i n c e
    0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,   \\ - - - - l a s t
    0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,   \\ - m o d i f i e
    0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,   \\ d - - - - l o c
    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,   \\ a t i o n - - -
    0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,   \\ - m a x - f o r
    0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,   \\ w a r d s - - -
    0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,   \\ - p r a g m a -
    0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,   \\ - - - p r o x y
    0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,   \\ - a u t h e n t
    0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,   \\ i c a t e - - -
    0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,   \\ - p r o x y - a
    0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,   \\ u t h o r i z a
    0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,   \\ t i o n - - - -
    0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,   \\ r a n g e - - -
    0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,   \\ - r e f e r e r
    0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,   \\ - - - - r e t r
    0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,   \\ y - a f t e r -
    0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,   \\ - - - s e r v e
    0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,   \\ r - - - - t e -
    0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,   \\ - - - t r a i l
    0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,   \\ e r - - - - t r
    0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,   \\ a n s f e r - e
    0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,   \\ n c o d i n g -
    0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,   \\ - - - u p g r a
    0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,   \\ d e - - - - u s
    0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,   \\ e r - a g e n t
    0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,   \\ - - - - v a r y
    0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,   \\ - - - - v i a -
    0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,   \\ - - - w a r n i
    0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,   \\ n g - - - - w w
    0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,   \\ w - a u t h e n
    0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,   \\ t i c a t e - -
    0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,   \\ - - m e t h o d
    0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,   \\ - - - - g e t -
    0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,   \\ - - - s t a t u
    0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,   \\ s - - - - 2 0 0
    0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,   \\ - O K - - - - v
    0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,   \\ e r s i o n - -
    0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,   \\ - - H T T P - 1
    0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,   \\ - 1 - - - - u r
    0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,   \\ l - - - - p u b
    0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,   \\ l i c - - - - s
    0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,   \\ e t - c o o k i
    0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,   \\ e - - - - k e e
    0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,   \\ p - a l i v e -
    0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,   \\ - - - o r i g i
    0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,   \\ n 1 0 0 1 0 1 2
    0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,   \\ 0 1 2 0 2 2 0 5
    0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,   \\ 2 0 6 3 0 0 3 0
    0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,   \\ 2 3 0 3 3 0 4 3
    0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,   \\ 0 5 3 0 6 3 0 7
    0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,   \\ 4 0 2 4 0 5 4 0
    0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,   \\ 6 4 0 7 4 0 8 4
    0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,   \\ 0 9 4 1 0 4 1 1
    0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,   \\ 4 1 2 4 1 3 4 1
    0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,   \\ 4 4 1 5 4 1 6 4
    0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,   \\ 1 7 5 0 2 5 0 4
    0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,   \\ 5 0 5 2 0 3 - N
    0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,   \\ o n - A u t h o
    0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,   \\ r i t a t i v e
    0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,   \\ - I n f o r m a
    0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,   \\ t i o n 2 0 4 -
    0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,   \\ N o - C o n t e
    0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,   \\ n t 3 0 1 - M o
    0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,   \\ v e d - P e r m
    0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,   \\ a n e n t l y 4
    0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,   \\ 0 0 - B a d - R
    0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,   \\ e q u e s t 4 0
    0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,   \\ 1 - U n a u t h
    0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,   \\ o r i z e d 4 0
    0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,   \\ 3 - F o r b i d
    0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,   \\ d e n 4 0 4 - N
    0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,   \\ o t - F o u n d
    0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,   \\ 5 0 0 - I n t e
    0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,   \\ r n a l - S e r
    0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,   \\ v e r - E r r o
    0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,   \\ r 5 0 1 - N o t
    0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,   \\ - I m p l e m e
    0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,   \\ n t e d 5 0 3 -
    0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,   \\ S e r v i c e -
    0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,   \\ U n a v a i l a
    0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,   \\ b l e J a n - F
    0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,   \\ e b - M a r - A
    0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,   \\ p r - M a y - J
    0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,   \\ u n - J u l - A
    0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,   \\ u g - S e p t -
    0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,   \\ O c t - N o v -
    0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,   \\ D e c - 0 0 - 0
    0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,   \\ 0 - 0 0 - M o n
    0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,   \\ - - T u e - - W
    0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,   \\ e d - - T h u -
    0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,   \\ - F r i - - S a
    0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,   \\ t - - S u n - -
    0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,   \\ G M T c h u n k
    0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,   \\ e d - t e x t -
    0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,   \\ h t m l - i m a
    0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,   \\ g e - p n g - i
    0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,   \\ m a g e - j p g
    0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,   \\ - i m a g e - g
    0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,   \\ i f - a p p l i
    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,   \\ c a t i o n - x
    0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,   \\ m l - a p p l i
    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,   \\ c a t i o n - x
    0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,   \\ h t m l - x m l
    0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,   \\ - t e x t - p l
    0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,   \\ a i n - t e x t
    0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,   \\ - j a v a s c r
    0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,   \\ i p t - p u b l
    0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,   \\ i c p r i v a t
    0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,   \\ e m a x - a g e
    0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,   \\ - g z i p - d e
    0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,   \\ f l a t e - s d
    0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,   \\ c h c h a r s e
    0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,   \\ t - u t f - 8 c
    0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,   \\ h a r s e t - i
    0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,   \\ s o - 8 8 5 9 -
    0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,   \\ 1 - u t f - - -
    0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e          \\ - e n q - 0 -
};

Name/Value ヘッダーブロックの全ての内容は zlib を使って圧縮されます。接続上の一方向における全ての Name/Value ペアに対して、1つの zlib ストリームを使用します。SPDY は各圧縮フレームの間に SYNC_FLUSH を使用します。

実装における注意: 圧縮エンジンは速度や容量のいずれかを優先するように調整することができます。容量に最適化すると、メモリーの使用率や CPU 消費が増加します。ヘッダーブロックは一般的に小さいため、実装者は、デフォルトの15ビット (32KB ウインドウ) から11ビット (2KB ウインドウ) といったように圧縮エンジンのウインドウサイズを減らすことができます。正確な設定は圧縮器により選択され、解凍器はどんな設定でも動作するでしょう。

3. SPDY 上の HTTP レイヤー

SPDY は、現在の Web ベースのアプリケーションに可能な限り互換であることを目指しています。これは、サーバーのビジネスロジックやアプリケーション API の観点から、HTTP の機能を変更しないことを意味します。これを達成するために、アプリケーションリクエストやレスポンスヘッダーのセマンティクスは全て保護され、セマンティクスを伝える構文のみが変更されます。したがって、 RFC2616 の HTTP/1.1 仕様の規則に以下の節の変更を適用します。

3.1 接続管理

クライアントは、与えられたオリジンに対して同時に2つ以上の SPDY セッションを開始するべきではありません (SHOULD NOT)。

ある SPDY セッションを開始している間に、別の SPDY セッションを終了しようとしている状態 (例: GOAWAY メッセージが送信されているが、全てのストリームが完了していると限らない状態) は、可能であることに注意してください。

3.1.1 GOAWAY の使用

SPDY は、クライアントやサーバーのいずれかから接続を終了する時に使用するための GOAWAY メッセージを提供します。サーバーからの GOAWAY メッセージがなければ、HTTPはサーバが接続を切断した状態でクライアントがリクエスト(新しい SYN_STREAM)を送信する競合状態を持つことになります。さらにクライアントは、サーバがストリームを受信したかどうか知ることができません。GOAWAY に last-stream-id を指定すれば、サーバーはクライアントにリクエストが処理されたかどうかを示すことができます。

いくつかのサーバーは GOAWAY を送信し、アクティブなストリームの完了を待つことなく、すぐに接続を終了することを選ぶかもしれないことに注意してください。クライアントは SPDY ストリームが確定的に終了されるため、これを検知することができます。この突然の終了は、保留中のリクエストを再送信するかどうかをヒューリスティックに決定することをクライアントに強制します。クライアントは、常にこのような場合に対処できるようにする必要があります。なぜなら GOAWAY を送信しないサーバーと同じように、偶発的な接続終了に対応しなければならないからです。

より高度なサーバーは、より graceful な終了処理を実装するために GOAWAY を使用するでしょう。そのようなサーバーは接続を終了する前に、GOAWAY を送信し、アクティブなストリームを完了するための少しの時間を提供します。

SPDY クライアントが接続を終了する場合でも、GOAWAY メッセージを送信するべきです。これは、任意のサーバープッシュストリームをクライアントが受信したことをサーバーが検知するためです。

エンドポイントが、終了する接続においてリモートからの SYN_STREAM をまったく受信しなかった場合、GOAWAY には last-stream-id として0が設定されます。

3.2 HTTP リクエスト/レスポンス

3.2.1 リクエスト

クライアントは SYN_STREAM フレームを送信することでリクエストを開始します。

body を含まないリクエストでは、クライアントがストリームに追加のデータを送信しないことを示すために、SYN_STREAM フレームに FLAG_FIN を設定しなければなりません。body を含むリクエストでは、SYN_STREAM は FLAG_FIN を含まず、body は SYN_STREAM のあとに続く一連の DATA フレームに含まれます。最後の DATA フレームには、body の終わりであることを示すための FLAG_FIN が設定されます。

SYN_STREAM の Name/Value セクションには、HTTP リクエストに関連する HTTP ヘッダーの全てが含まれます。SPDY のヘッダーブロックでは、次のような違いがありますが、今日の HTTP ヘッダーブロックからはほとんど変更がありません:

ユーザーエージェントは、自由にリクエストの最適な優先順位付けをします。ユーザーエージェントが受信なしには進行できないリソースの場合、そのリソースの優先順位を上げることを試みるべきです。イメージのようなリソースには、一般的に最も低い優先順位付けをすべきです (SHOULD)。

クライアントが method、host、path、scheme、そして version ヘッダーなしに SYN_STREAM を送信した場合、サーバーは HTTP 400 Bad Request を返さなければなりません (MUST)。

3.2.2 レスポンス

サーバーは、クライアントのリクエストに SYN_REPLY フレームで応じます。クライアントのアップロードストリームとは対象的に、サーバーは SYN_REPLY フレーム後の一連の DATA フレームによりデータを送信し、最後の DATA フレームにはストリームが正しく終了したことを示す FLAG_FIN が含まれます。(202や204レスポンスといった) body を含まないレスポンスの場合、SYN_REPLY フレームには、このストリームではこれ以上送られるデータがないことを示す FLAG_FIN が設定されるかもしれません。

クライアントが status や version ヘッダーなしに SYN_REPLY を受信した場合、PROTOCOL ERROR を示す RST_STREAM フレームを返さなければなりません。

3.2.3 認証

クライアントが認証を要求するオリジンサーバーにリクエストを送信した時は、使用する認証方式を定義する WWW-Authenticate チャレンジヘッダーを含めた "401 Unauthorized" レスポンスをサーバーは返すことができます。クライアントは認証ヘッダーでのリクエストを再送信する際には、指定された認証方式を使用します。

プロキシ認証には Basic、Digest、NTLM そして Negotiate (SPNEGO) の4つの方式があります。最初の2つは RFC2617 で定義され、ステートレスです。後の2つは Microsoft での開発されたり RFC4559 で定義されたものでありステートフルです。別の名で "multi-round authentication" や "connection authentication" として知られています

3.2.3.1 ステートレス認証

SPDY 上でのステートレス認証は、HTTP 上でおこなわれるやり方とまったく同じです。単一サーバーに複数の SPDY ストリームが同時に送信される場合は、2つの HTTP 接続が独立してプロキシサーバーと認証するのと同じように、それぞれ独立して認証がおこなわれます。

3.2.3.2 ステートフル認証

残念ながら、ステートフルな認証機構は RFC2617 に違反するような方法で実装、定義されています - リクエストの一部に "realm" を含めていないためです。これは SPDY では問題です。なぜなら、クライアントが2つ同時にサーバー認証チャレンジをおこなうと曖昧さの排除が不可能になるからです。

このような場合に対処するために、ステートフル認証を使用する SPDY サーバは、2つの変更のいずれかを実装しなければなりません (MUST):

3.3 サーバープッシュトランザクション

SPDY では、サーバーが1つのリクエストに対して、クライアントに複数のレスポンスを送信することを可能にします。サーバーは1つのリクエストに対するレスポンスにおいて、複数のリソースを送信する必要があることを知っています。これがこの機能の論理的根拠です。サーバーのプッシュ機能がないと、クライアントは主要なリソースを最初にダウンロードし、関連するリソースを見つけてからそれらのリクエストをおこなわなければなりません。リソースをプッシュすることは、ラウンドトリップによる遅延を防ぎますが、クライアントがリクエストの処理をしているコンテンツをサーバーがプッシュできてしまうために、潜在的に競合を生む可能性もあります。以降では、パフォーマンスの恩恵を活かしながら、競合状態を回避しようとする仕組みをまとめます。

プッシュされたレスポンスを受信したブラウザは、サーバーがブラウザの同一オリジンポリシーを使用して URL をプッシュすることが認められているかを検証しなければなりません (MUST)。例えば、www.foo.com への SPDY 接続では、一般的に www.evil.com のレスポンスをプッシュすることは認められていません。

ブラウザがプッシュレスポンス (例: RST_STREAM を送信せずに) を受け入れたとき、ブラウザは他のレスポンスをキャッシュするのと同じ方法で、プッシュされたレスポンスのキャッシュを試みなければなりません (MUST)。これは、レスポンスヘッダーを検証し、ディスクキャッシュに挿入することを意味します。

プッシュレスポンスはリクエストを持たないため、関連するリクエストヘッダーを持ちません。フレーミングレイヤーでは、SPDY でプッシュされたストリームは、関連するリクエストストリームを示す "associated-stream-id" を含みます。プッシュされたストリームは associated-stream-id から、":host"、":scheme"、":path" を除いた全てのヘッダーを継承します。そしてそれらのヘッダーは、プッシュされたレスポンスのストリームヘッダーの一部として渡されます。ブラウザはこれらの継承された暗黙のリクエストヘッダーをキャッシュされたリソースと共に保存しなければなりません (MUST)。

実装での注意: サーバープッシュを使用すれば、サーバーが不当な量のコンテンツやリソースをユーザーエージェントに対してプッシュすることが理論上は可能になります。ブラウザは不当なプッシュ攻撃を防ぐためにスロットル機能を実装しなければなりません (MUST)。

3.3.1 サーバーの実装

サーバーがユーザーエージェントにリソースをプッシュしようとする時は、単方向 SYN_STREAM を送信して新しいストリームを開始します。SYN_STREAM には Associated-To-Stream-ID と、FLAG_UNIDIRECTIONAL フラグが設定されていなければなりません (MUST)。また、SYN_STREAM にはヘッダーとしてプッシュされたリソースのための URL を表す ":scheme"、":host"、":path" を含んでいなければなりません (MUST)。その後のヘッダーは、HEADERS フレームで送信してもよいです。プッシュストリームを引き起こすリクエストかどうか、ユーザーエージェントが区別できるようにすることが Associated-To-Stream-ID の目的です。これなしでは、ユーザーエージェントが同じページを2つのタブで開いていた場合、固定 URL での固有のコンテンツをそれぞれプッシュすると、ユーザーエージェントはリクエストを区別することができません。

Associated-To-Stream-ID は、開始済みでかつ存在するストリームの ID でなければなりません。この制限の理由は、プッシュされたコンテンツが明確なエンドポイントを持つようにするためです。ユーザーエージェントがストリーム11でリクエストをした場合、サーバーはストリーム11に応答します。ストリーム11では FLAG_FIN が送信される前に、クライアントに任意の数の追加ストリームをプッシュすることができます。しかしながら、起点となるストリームが終了すると、それ以上プッシュストリームは関連付けられないかもしれません。プッシュストリームは、起点のストリームが終了する前に終了 (FIN を設定) する必要がなく、必要なのは起点のストリームが閉じられる前に開始することだけです。

サーバーが、Associated-To-Stream-ID に0が設定されたリソースをプッシュすることは不正です。

クライアントとの競合を最小限にするために、クライアントがプッシュされたリソースを発見しそれをリクエストできるよう、プッシュされたリソースの SYN_STREAM は、いかなるコンテンツよりも前に送信しなければなりません (MUST)。

サーバーは GET リクエストで返されるリソースのみをプッシュしなければなりません (MUST)。

注: もしサーバーが、リソースをプッシュするために HEADERS フレームを送信しようとして、必要な Name/Value レスポンスヘッダーを全て持っていなかったなら、 Name/Value ペアを補うために追加の HEADERS フレームを使用することができます。後から送る HEADER フレームには ":host"、":scheme"、":path" ヘッダーを含めてはいけません (例: サーバーはプッシュされるリソースの同一性を変更することはできません)。HEADERS フレームには、先に送った HEADERS フレームと重複したヘッダーを含めてはいけません。サーバーは、データフレームをストリームに送信する前に、scheme/host/port ヘッダーを含む HEADERS フレームを送信しなければなりません。

3.3.2 クライアントの実装

クライアントがリソースを取得する場合は、3つの可能性が考えられます:

Associated-To-Stream-ID を含む SYN_STREAM と HEADERS フレームを受信した場合、クライアントはプッシュストリームにおいて、そのリソースに対する GET リクエストを発行してはいけません。代わりに、プッシュストリームからの受信を待たなければなりません。

Stream-ID が0のサーバープッシュストリームをクライアントが受信した場合、ステータスコード PROTOCOL_ERROR と共にセッションエラー (2.4.1節) を発生しなければなりません (MUST)。

サーバーから Name/Value セクションに ":host"、":scheme"、":path" ヘッダーが設定されていない SYN_STREAM をクライアントが受信した場合は、エラーコード HTTP_PROTOCOL_ERROR と共に RST_STREAM を返さなければなりません (MUST)。

サーバーのプッシュストリーム単体をキャンセルするために、クライアントはエラーコード CANCEL と共にストリームエラー (2.4.2節) を発生させることができます。ストリームエラーを受信すると、サーバーはこのストリーム上での送信を直ちに停止 (これは突然の終了になります) しなければなりません (MUST)。

リクエストに関連する全てのプッシュストリームをキャンセルするために、クライアントは associated-stream-id 上で CANCEL のエラーコードのストリームエラー (2.4.2節) を発生させるかもしれません。ストリームをキャンセルすることにより、サーバーは最初のストリームに関連する全てのストリームに対してフレームの送信を直ちに停止しなければなりません (MUST)。

同一ストリーム上で以前受信した HEADERS フレームと重複するヘッダーを含む HEADERS フレームをサーバーが送信した場合、クライアントはエラーコード PROTOCOL_ERROR と共にストリームエラー (2.4.2節) を発生しなければなりません。

同一ストリーム上に DATA フレームを送信した後に HEADERS フレームをサーバーが送信した場合、クライアントはその HEADERS フレームを無視してもよい。DATA フレームの後の HEADERS フレームを無視することは、HTTP の Trailing ヘッダーの処理を禁止します (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40)。

4. デザインの基本原則と注記

著者注: この章における注記は、この文書に記載される SPDY プロトコルの仕様には関係がなく、どの注記もプロトコルがどのように動作するかについてを正式に熟考したものではありません。しかしながらこれらの注記は、プロトコルの曖昧さをどのように解決するか、プロトコルをどのように発展させて進化するかといった、将来の議論における証拠として役立つかもしれません。最終的なドラフトになる前にこれらの注記は削除されます。

4.1 フレーミングレイヤーとアプリケーションレイヤーの分割

読者は、この仕様はしばしば、特定のアプリケーション - HTTP (3章) の要件をフレーミングレイヤー (2章) と混同していることに気づくかもしれません。これはストリームのリクエスト/レスポンスの性質や、HTTP に非常によく似た HEADERS や圧縮コンテキストの定義、同様に他の様々な部分に反映されています。

この混同は意図的なものです。このプロトコルの最も重要なゴールは、HTTP と共に利用する低レイテンシのプロトコルを策定することです。2つのレイヤーを分離すると、プロトコルや既存の HTTP の実装との関わりについての記述が非常に便利になりますが、SPDY フレーミングレイヤーを再利用することはゴールではないのです。

4.2 エラー処理 - フレーミングレイヤー

SPDY レイヤーのエラー処理は2つのグループに分けられます: 個々の SPDY ストリームに影響するものと、そうでないものです。

エラーが単一のストリームに限定され、フレーミング全体では影響を受けない時には、 SPDY は完全な接続の中断をおこなわずに通信を継続し、ストリームのみを無効化する仕組みとして RST_STREAM の使用を試みます。

単一ストリームコンテキストの外でエラーが発生すると、SPDY はセッション全体がまずい状態になっていると仮定します。このようなケースでは、エラーを検出したエンドポイントが接続を終了するようにすべきです。

4.3 ドメインごとに1つの接続

SPDY は他のプロトコルが慣習的に使用しているよりも少ない接続を使おうとしています。この振る舞いの根拠は、クライアントが複数のチャンネルを通じてサーバーに接続した時に、一貫したレベルのサービス (例: TCP スロースタート) や優先順位付け、最適な圧縮を提供することが非常に難しいことにあります。

ラボでの測定を通じて、私たちは、クライアントからの接続を減らすことによる安定したレイテンシの利点を見てきました。SPDY により送信されるパケットの全ての数は、HTTP の40%以下にすることができます。サーバー上で非常に多くの同時接続を扱うことは、スケーラビリティの問題にもつながりますが、SPDY はこの負荷を減らします。

しかし、複数の接続を使用することに利点がないわけではありません。SPDY は単一のストリーム上に多数の独立したストリームを多重化しますが、これはトランスポートレベルで行頭ブロック問題を引き起こす可能性があります。これまでのテストでは、行頭ブロック問題の悪い影響は (特にパケットロスの面で)、圧縮と優先順位付けの利点を上回ります。

4.4 固定 vs 可変 長さフィールド

SPDY は固定長の32ビットフィールドの使用を支持していますが、場合によっては、より小さな、可変長エンコーディングを使用することもできます。一部では、これは悲劇的なまでに帯域幅の無駄のように思うでしょう。SPDY は速度と単純さのために単純なエンコーディングを選択しました。

SPDY のゴールはネットワークのレイテンシを減らすことです。SPDY フレームのオーバーヘッドはおおむね非常に少なくなっています。各データフレームは、1452バイトのペイロードに対して8バイトのオーバーヘッドしかありません (~0.6%)。このドキュメントの執筆時点では、帯域幅はすでに広く、帯域幅が増え続けることを示す強い傾向があります。1Mbps の平均的な世界の帯域幅で、可変エンコーディングがオーバーヘッドを50%減らすことができると仮定すると、可変エンコーディングを使うことで節約できるレイテンシは100ナノ秒以下になります。さらに興味深いのは、巨大なエンコーディングはパケットの境界を強制するため、このようなケースではラウンドトリップをさらに引き起こします。しかし、SPDY と TCP との相互作用による他の側面に取り組むことにより、私たちはうまく軽減されると信じています。

4.5 圧縮コンテキスト

複数のオリジンとの通信に使用される圧縮コンテキストを分離する時には、いくつかの選択肢がありました。私たちには、各オリジンに使用できる圧縮コンテキストのマップ (またはリスト) を保持する可能性がありました。基本的なケースは簡単です - 各 HEADERS フレームは、自身のフレームに使用するコンテキストを特定する必要があります。しかしながら、圧縮コンテキストのコストは高く、各コンテキストのライフサイクルを制限する必要がありました。プロキシサーバーでは多くのコンテキストを引き回すことも問題になるでしょう。私たちはメモリーの使用を制限した16個のコンテキストの静的なセットを使うことを考ました。また、オンザフライでコンテキストを作成することができ、後で削除する必要のある動的なコンテキストについても考えました。これらは全て複雑ですが、最終的に私たちはこのような仕組みが非常に多くの解決しなければならない問題を生むことを確信しました。

そこで、私たちは代わりに圧縮コンテキストをリセットするためのフラグを提供する、単純なアプローチを選択しました。よくあるケース (プロキシなし) では、都合がいいことに、たいていのリクエストは同一オリジンへのものであり、コンテキストをリセットする必要がありません。また、1つの SPDY セッション上で2つの異なるオリジンを扱うようなケースでは、遷移ごとに圧縮状態を単純にリセットします。

4.6 単方向ストリーム

多くの読者は単方向ストリームのコンセプトが少し混乱させることと、冗長であることの両方に気づくでしょう。ストリームの受信者がストリーム上にデータを送信したくない場合は、単純に FLAG_FIN ビットを設定して SYN_REPLY を送信することができます。したがって、FLAG_UNIDIRECTIONAL は必要がないことになります。

UNIDIRECTIONAL マーキングが必要ないことは事実です。これはプッシュストリームの受信者が、何の目的もないような空のフレームセット (例: FLAG_FIN が設定された SYN_STREAM) の送信が必要になることを避けるために追加されました。

4.7 データ圧縮

ストリームの内容を知ることなく、ストリームのデータ部分を圧縮することは (ヘッダーの圧縮とは対照的に) 冗長です。すでに圧縮されたストリームを圧縮することにメリットはありません。このため、SPDY は当初からデータの圧縮は任意になっています。既存のウェブサイトの研究では、多くのサイトが圧縮を使用しないことを必要としており、ユーザーがその状況に苦しんでいることを示していたため、このような仕様になりました。私たちは SPDY レイヤーで、サイトの管理者がわかりやすく圧縮を強制することができる仕組みを求めていました - 圧縮しないよりは2度圧縮するほうがよいでしょう。

しかしながら、この機能は任意であり、時には冗長で、全ての人にとって有用かどうかが不明であったため、仕様から削除しました。

4.8 サーバープッシュ

細かいですが重要なポイントは、サーバープッシュストリームは関連するストリームが閉じる前に宣言しなければならないことです。この理由は、プロキシが以前のストリームの情報を破棄することができるようにライフサイクルを持つことにあります。すでに終了したストリームにプッシュストリームを関連付けることができてしまうと、その時エンドポイントは、以前におこなったストリームであることの認識を否定するための、特定のライフサイクルを持たないでしょう。

5. セキュリティへの配慮

5.1 同一オリジンの制約の使用

この仕様では、コンテンツの検証が必要とされるすべての状況において、同一オリジンポリシーを使用します。

5.2 HTTP ヘッダーと SPDY ヘッダー

アプリケーションレベルでは、HTTP はヘッダーの Name/Value ペアを使用します。SPDY は既存の HTTP ヘッダーを SPDY ヘッダーにマージしますが、いくつかの HTTP アプリケーションは特定のヘッダー名をすでに使用している可能性があります。このような衝突を防ぐために、SPDY 上の HTTP レイヤーに取り入れる全てのヘッダーの前には ":" がつけられます。HTTP ヘッダーの命名においては ":" は不正なシーケンスであり、どんな衝突の可能性も防ぎます。

5.3 クロスプロトコル攻撃

TLS を使用することで、SPDY が新しいクロスプロトコル攻撃を引き起こすことはないと信じています。TLS は (自身のハンドシェイクを除く) 全ての転送コンテンツを暗号化することで、攻撃者がクロスプロトコル攻撃に使うことができるデータの制御するを難しくします。

5.4 暗黙のサーバープッシュヘッダー

プッシュリソースには紐づくリクエストがありません。既存の (Vary ヘッダーのような) HTTP キャッシュ制御の検証を動作させるためには、全てのキャッシュリソースがリクエストヘッダーのセットを持つ必要があります。このような理由から、ブラウザはプッシュに関連するストリームのリクエストヘッダーを継承するように注意しなければなりません (MUST)。この対象には 'Cookie' ヘッダーも含みます。

6. プライバシーへの配慮

6.1 長時間の接続

SPDYは、ユーザーがリクエストを発行した時のレイテンシを削減するために、長い時間接続をクライアントとサーバ間に開いたままにしようとします。時間をかけてこれらの接続を維持することは、個人情報をさらすことに使われる可能性があります。例えば、前のユーザーが使うのをやめた後のブラウザを別のユーザーが使うことで、前のユーザーが何をしていたかを知ることができてしまうかもしれません。この問題は現在の HTTP の問題でもありますが、短い時間の接続はこのリスクを減らします。

6.2 SETTINGS フレーム

SPDY の SETTINGS フレームは、サーバーから、クライアントとサーバー間の通信に関する外部への転送情報をクライアントに保存することができます。これはレイテンシを減らすことにのみ使用されることを意図していますが、不正なサーバーが、この仕組を将来のリクエストにおけるクライアントに関する識別情報の保存にも使うことができてしまいます。

Google Chrome の "incognito mode" のようなプライバシーモードを実装しているクライアントは、永続化 SETTINGS 保存領域を無効化したい場合があるかもしれません。

クライアントは Cookie が削除される時に、永続化 SETTINGS 情報も削除しなければなりません (MUST)。

TODO:不適切な使用を制限するために、設定の各タイプにおける範囲の最大値を指定すること。

7. SPDY ドラフト #2 からの変更

以下は、このドラフトとドラフト #2 の間の主な変更点のリストです。

8. 要件の定義

このドキュメントにおける "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY"、そして "OPTIONAL" といったキーワードは RFC 2119 で記述されているとおりに解釈します。

9. 謝辞

多くの人が SPDY のデザインや進化に貢献してくれました: Adam Langley、Wan-Teh Chang、Jim Morrison、Mark Nottingham、Alyssa Wilk、Costin Manolache、William Chan、Vitaliy Lvin、Joe Chan、Adam Barth、Ryan Hamilton、Gavin Peters、Kent Alstad、Kevin Lindsay、Paul Amer、Fan Yang、Jonathan Leighton

10. 引用規格

[TLSNPN] Langley, A., "TLS Next Protocol Negotiation", <http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-01>.
[ASCII] "US-ASCII. Coded Character Set - 7-Bit American Standard Code for Information Interchange. Standard ANSI X3.4-1986, ANSI, 1986.".
[UDELCOMPRESSION] Yang, F., Amer, P., and J. Leighton, "A Methodology to Derive SPDY’s Initial Dictionary for Zlib Compression", <http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf>.

11. エラッタ

2.6.6節では、当初 INTERNAL_ERROR をステータスコード11と表記していました。

12. 著者の連絡先

Mike Belshe Twist EMail: [email protected]
Roberto Peon Google, Inc EMail: [email protected]