SPDY (スピーディ) プロトコル (後半部) 日本語訳 12/01/2009 版

SPDY プロトコル仕様書日本語訳

前回の SPDY プロトコル仕様書の翻訳前半戦に引き続き、SPDY プロトコルの仕様書 (ドラフト) の翻訳の後半戦です。プロトコルを実装しようとしない限り、あまり必要とする人はいない情報かもしれませんが・・・ (汗)

# かつ、数日時間が開いてしまったので、前半戦は 11/28 版だったのに対して、後半は 12/01 版です。すみません。

翻訳の怪しいところはコメントでご指摘いただけることを祈りつつ・・・

それでは後半戦をお楽しみください。

フレーミング

TCP コネクションが確立されると、クライアントとサーバーはフレーム化されたメッセージ (framed message) を交換可能になります。フレームには2種類あります。コントロールフレーム (control frame) とデータフレーム (data frame) です。フレームは常に共通の8バイトのヘッダを持っています。

第一ビットはコントロールフレームかデータフレームであるかを示すコントロールビットです。コントロールフレームはバージョン番号、フレームタイプ、フラグ及び長さを含みます。データフレームはストリーム ID、フラグ及び共通ヘッダの後に運ばれるペイロードの長さを含みます。単純なヘッダにより、フレームの読み書きを単純になります。

長さ、バージョン、型などを含む全ての整数値はネットワークバイトオーダーです。SPDY は動的サイズフレームのアラインメントの方法を強制しません。

コントロールフレーム

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

コントロールフレームフィールド:

コントロールビット: ‘C’ ビットはこれがコントロールメッセージであることを示します。コントロールフレームについては、この値が常に 1 です。

バージョン: セッションプロトコルのバージョン番号 (現在は 1 です)

タイプ: コントロールフレームのタイプ。コントロールフレームは、SYN_STREAM, SYM_REPLY などです。

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

長さ: 長さフィールドのあとのバイト数。これは符号なしの 24 ビット値で表します。

データフレーム

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

データフレームフィールド:

コントロールビット: データフレームでは、この値は常に 0 です。

ストリーム ID: ストリームを識別するための 31 ビット値

フラグ: このフレームに関連したフラグ。正しいフラグは次のものです。

  • 0x01 = FLAG_FIN – このストリームのハーフクローズを表します。以下のストリームハーフクローズを参照してください。

長さ: 長さフィールドに続くバイト数を表す 24 ビット値。データフレームのトータルサイズは、8 バイト + “長さ” です。長さゼロのデータフレームでも構いません。

データ: ペイロード中の可変長フィールドです。

Hello メッセージ

接続が確立してから、SPDY は双方が通信の詳細を教えあうための非同期の Hello シーケンスを行います。多くのプロトコルと違って、この Hello シーケンスは任意であり、完全に非同期的に行われます。非同期であるため、接続の開始に関してラウンドトリップによる遅延を発生させません。しかし、非同期で任意であるために、双方はこのメッセージがいかなるときに到達するかもしれず、また、全く到達しないかもしれないことについて準備していなければなりません。

Hello シーケンスを始めるために、どちらかは HELLO コントロールフレームを送信可能です。Hello フレームは任意ですが、もし送信されるのであれば、それは送信される最初のフレームでなければいけません。Hello メッセージを受け取ったときに、Hello メッセージの応答を返信しなければいけないこともありません。従って、このメッセージは完全に参考値となります。

HELLO コントロールメッセージ:

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

HELLO メッセージフィールド:

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

バージョン: SPDY バージョン番号

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

未使用: 将来のために 16 ビットが未使用です。

エントリー数: メッセージ中の 識別子/値 の数を表す 16 ビット値

ID: 32 ビットの ID 番号。次の ID が妥当です:

  • 1 – HELLO_BANDWIDTH_TO_YOU この値によって送信者はこのチャネルで期待されるアップロード帯域幅を送信できます。この値は概算値です。この値は、期待される最大アップロードチャネルキャパシティとして送信者が予測している数値を、一秒間あたりのキロバイト数として表した整数値です。
  • 2 – HELLO_BANDWIDTH_FROM_YOU この値によって送信者はこのチャネルで期待されるダウンロード帯域幅を送信できます。この値は概算値です。この値は、期待される最大ダウンロードチャネルキャパシティとして送信者が予測している数値を、一秒間あたりのキロバイト数として表した整数値です。
  • 3 – HELLO_ROUND_TRIP_TIME 送信者は、このチャネルで期待されるラウンドトリップ時間を送ることが可能です。このラウンドトリップ時間は、このクライアントからリモートに対してコントロールフレームを送信して、応答を受け取るための最小時間として定義されます。この値はミリ秒で表現します。
  • 4 – HELLO_MAX_CONCURRENT_STREAMS これによって許容される最大同時ストリーム数をリモートに送信可能です。既定では制限はありません。実装者は、この値を100以下にはしないようにしてください。

値: 32 ビット値

将来的にクライアントサーバー通信を改善できるように、メッセージは意図的に拡張可能にしてあります。送信者はいかなる種類の識別子/値も送信する必要はありません。送信者は伝達するために正確な値を持つ識別子/値のみを送らなければなりません。複数の 識別子/値ペアが送信されたときは、小さな値の ID から大きな値の ID の順序で送信されるべきです。

ストリーム

ストリームは複数のフレームに分割される、独立した双方向のデータです。ストリームは、クライアント、サーバーのいずれ側からでも作成可能であり、他のストリームと交互に行き来するデータを送信でき、さらにキャンセルも可能です。HTTP でストリームを使う場合は、単一の HTTP 要求/応答が単一のストリームを占めるようにし、そのストリームはそれに続く要求で再利用されないようにします。これはストリームはラウンドトリップなで、独立的に作成可能であるからです。

ストリームの初期化にて、ストリームは双方が相手側のエンドポイントに固定長の名前/値ペアのリストを送信可能です。

ストリーム生成

ストリームは、タイプを SYN_STREAM (1) にセットしたコントロールパケットを送ることによって作成可能です。もしサーバーがストリームを開始した場合、ストリーム ID は偶数でなければいけません。クライアントがストリームを開始する場合は、ストリーム ID は奇数です。0 は正しいストリーム ID ではありません。接続の双方からのストリーム ID は、新しいストリームを作るたびに、単調に増加させなければなりません。例えば、ストリーム 2 はストリーム 3 の後に作成できますが、ストリーム 7 はストリーム 9 の後に作成してはいけません。

SYN_STREAM フレームの受取り確認としては、受け取り手は SYN_PREPLY フレームで応答します。クライアントは、データフレームを送る前に SYN_REPLY を待ち受ける必要はありません。

もし SYN_STREAM を受け取ったエンドポイントが、新しいストリームを作成することを望まないならば、直ちに FIN_STREAM コントロールフレームで応答することも可能です。しかしながら、ストリームを開始したエンドポイントはそのストリーム上で既にデータを送信してきているかもしれないことに注意してください。このデータは無視しなければなりません。

SYN_STREAM コントロールメッセージ:

  +----------------------------------+
  |1|       1          |       1     |
  +----------------------------------+
  | Flags (8)  |  Length (24 bits)   |
  +----------------------------------+
  |X|          Stream-ID (31bits)    |
  +----------------------------------+
  | Pri | Unused    |   NV Entries   |
  +----------------------------------|
  |     Name/value header block      |
  |             ...                  |

SYN_STREAM メッセージフィールド:

フラグ (Flags): このフレームに関するフラグ。妥当なフラグは以下の通り:

  • 0x01 = FLAG_FIN – そのストリームのハーフクローズを示します。これがセットされると、送信者はこのストリーム上でこれ以上データを送信しません。

長さ (Length): 長さフィールドの後に続くバイト数を表す符号なし 24 ビット値です。SYN_STREAM フレームの合計サイズは 8 バイト + 長さフィールドの値です。このフレームの長さは、8 かそれ以上でなければいけません。

優先度 (Priority): 2 ビットの優先度フィールド。もしエンドポイントが複数のストリームを開始した場合、優先度フィールドがどのストリームに優先順位を与えればよいか決めます。サーバーは厳密にその優先度に従うことを必要とされてはいませんが、最善の努力 (best-effort) をすることが想定されています。0 は最低の優先順位を表し、3 が最高の優先順位です。The highest-priority data is that which is most desired by the client.

未使用: 14 ビットの未使用のスペース。将来的な利用のため予約されています。

NV エントリー: (16 ビット) 続く名前/値のペアの数。

名前/値ブロック (Name/Value Block) は以下に説明しています。

SYN_REPLY コントロールメッセージ:

  +----------------------------------+
  |1|        1        |        2     |
  +----------------------------------+
  | Flags (8)  |  Length (24 bits)   |
  +----------------------------------+
  |X|          Stream-ID (31bits)    |
  +----------------------------------+
  | Unused        |    NV entries    |
  +----------------------------------|
  |     Name/value header block      |
  |              ...                 |

SYN_REPLY メッセージフィールド:

フラグ: このフレームに関するフラグ。正しいフラグは以下の通り:

  • 0x01 – FLAG_FIN これはストリームのハーフクローズを示します。これがセットされると、送信者はこのストリーム上でこれ以上データを送信しません。

長さ (Length): 長さフィールドの後に続くバイト数を表す符号なし 24 ビット値です。SYN_STREAM フレームの合計サイズは 8 バイト + 長さフィールドの値です。このフレームの長さは、8 かそれ以上でなければいけません。

未使用: 16 ビットの未使用領域。将来の利用のために予約されています。

NV エントリ: (16 ビット) これに続く名前/値ペアの数

名前/値ブロックについては、以下に説明しています。

名前/値ヘッダブロックフォーマット

SYN_STREAM と SYN_REPLY フレームの両方共に、名前/値ヘッダブロック (Name/Value Header Block) を含みます。要求と応答の両方で使用されるヘッダブロックは同一です。リストの最後に容易に追加できるように設計されています。また、受け取り手が容易に解析できるように設計されています。それぞれの数値は 2 バイトです。

  +----------------------------------+
  |     Length of name (int16)       |
  +----------------------------------+
  |           Name (string)          |
  +----------------------------------+
  |     Length of value  (int16)     |
  +----------------------------------+
  |          Value   (string)        |
  +----------------------------------+
  |           (repeats)              |

それぞれのヘッダ名は少なくともひとつの値を持たなければなりません。それぞれの名前及び値の長さは 0 より大きくなければなりません。

ヘッダ名の重複は許されません。二つの同一の名前のヘッダを送信するためには、一つのヘッダーに二つの値を設定して送信します。この値は単一の NUL (0) バイトによって分割されます。

文字列は UTF8 エンコードを行い、NUL 終端ではありません。

名前/値ペアは gzip で圧縮されます。ひとつのコネクション上に、単一方向の、全ての名前/値ペアの名前に対する単一の gzip ストリーム (コンテキスト) があります。このストリームは以下の辞書によって初期化されます(改行無し):

optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-
languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi
f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser
-agent10010120020120220320420520630030130230330430530630740040140240340440
5406407408409410411412413414415416417500501502503504505accept-rangesageeta
glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic
ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran
sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati
oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo
ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe
pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic
ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1
.1statusversionurl

ストリームデータ交換

ストリームが作られると、それはどちらの方向にも任意の量のデータを送るために使用できます。どちらかが送信を終了したら、FIN_FLAG をセットしたフレームを送信できます (TCP 接続の切断を参照してください)

ストリーム・ハーフクローズ

ストリームの片方が FLAG_FIN フラグをセットしたコントロールフレーム、またはデータフレームを送信したら、そのストリームはその側からハーフクローズされたとみなされます。FLAG_FIN の送信者は、このストリーム上でこれ以上データを送信しないことを表しています。両者がハーフクローズされると、そのストリームはクローズとみなされます。

ストリーム・クローズ

ストリームを終了する方法は3つあります。通常終了 (normal termination)、異常終了 (abrupt termination)、そして、TCP 接続切断 (TCP connection teardown) です。

通常終了

通常終了は、ストリームの双方が、ストリームをハーフクローズとしたときに発生します。

異常終了

クライアントまたはサーバーのいずれかは、いつでも FIN_STREAM コントロールパケットを送信可能です。FIN_STREAM の応答として、双方共にそのストリームから受け取ったデータを無視しなければならず、また、双方共にそのストリームへのデータ送信を停止しなければなりません。FIN_STREAM はストリームの異常停止のために用意されています。

FIN_STREAM コントロールフレーム:

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

FIN_STREAM メッセージフィールド

フラグ (Flags): このフレームに関連したフラグ。正しい値は次の通りです。

  • 0x01 = FLAG_FIN これがセットされると、このストリーム上で送信者はこれ以上データを送信しません。上記ストリームハーフクローズを参照してください。

長さ (Length): 長さフィールドに続くバイト数を表す 24 ビット値。FIN_STREAM コントロールフレームに対しては、この値は常に 8 です。

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

  • 1 – PROTOCOL_ERROR これは一般的なエラーで、特定のエラーが利用できない場合にのみ使います。このエラーを受け取った側は、セッション全体を終了 (abort) して、通常ユーザーにエラーを返します。
  • 2 – INVALID_STREAM アクティブではないフレームを受信した場合に返します。このエラーの受信者は通信エラーを記録します。
  • 3 – REFUSED_STREAM これはストリーム上で処理される前にストリームが拒否されたことを示します。非 indepotent メソッドに対しては、これは要求は再試行可能であることを意味します。

注: FIN_STREAM では 0 は正しいステータスコードではありません。

TODO (やること) – より詳細のエラーを定義する。

TCP 接続の切断

もし終了していないストリームがアクティブなうちに (すなわち、そのストリームに対して FIN_STREAM が送受信されていない場合)、TCP コネクションが切断された場合、エンドポイントはそのストリームは異常に割り込みされ、不完全な状態になっているかもしれないことを想定しなければなりません。

クライアントまたはサーバーが、既に切断されているストリーム上からデータを受け取った場合、切断後に受け取ったデータは無視しなければなりません。

データフロー

SPDY は複数の論理的なストリームで多重化していますが、TCP は単一のデータストリームを提供しているので、クライアントとサーバーが同時セッションでデータメッセージを交換することは重要です。

実装者は小さいチャンクでデータを送ると、ブラウザがメタデータを早く解析でき、レイアウトを最終化できるために、エンドユーザーの遅延を低めることになることに注意してください。大きなチャンクでデータを送ることは、帯域幅の効率を若干高めるものの、多くのリソースを持つページにおいてユーザーの体験をスローダウンさせることになります。

他のコントロールフレーム

NOOP

NOOP コントロールフレームは非制御フレームです。これはクライアントあるいはサーバーから送信可能です。NOOP フレームの受信者は単にそれを無視するだけです。

注: このコントロールフレームは最終的には削除されるかもしれません。これは実験的な目的で実装されました。

NOOP コントロールメッセージ:

  +----------------------------------+
  |1|       1          |       5     |
  +----------------------------------+
  | 0 (Flags)  |    0 (Length)       |
  +----------------------------------+

コントロール ビット: このメッセージにおけるコントロールビットは常に 1 です。

バージョン: SPDY のバージョン番号

タイプ: NOOP メッセージのメッセージタイプは 5 です。

長さ: このフレームはデータを運びません。長さは常に 0 です。

PING

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

注: このコントロールフレームは最終的に削除されるかもしれません。これは実験の目的で実装されました。

PING コントロールメッセージ:

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

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

バージョン: SPDY のバージョン番号

タイプ: PING メッセージのメッセージタイプは 6 です。

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

ID: ピングのユニーク ID

注: もし送信者が可能な PING ID を使った場合 (つまり、 2 の 32 乗の ID を送った場合)、「折り返し」て ID を再利用しても良いです。

GOAWAY

GOAWAY コントロールフレームは、リモート側に対してこのセッションをこれ以上使わないことを伝えるための仕組みです。これはクライアント、サーバー両方から送られる可能性があります。送信されると、その送信者はこのセッション上に新しいストリームを初期化しないことになります。GOAWAY フレームの受信者は、新しい要求のため新しいセッションを確立することは出来ますが、このセッション上に追加の要求を送信してはいけません。このメッセージの目的は、以前に確立していた要求の処理を続けさせつつ、サーバーに行儀良く、新しい要求を受け取ることを止めさせ (多くの場合、リブートやメンテナンスのために)ることです。

要求を送信するクライアントと GOAWAY メッセージを送信するサーバーの間には、特有の競合状態があります。この状況に対応するために、GOAWAY メッセージはこのセッションで受け入れられた最後のストリームを表すストリーム ID を含んでいます。このストリーム ID の後に、クライアントがセッションの要求を発行したならば、それらはサーバーによって受け入れられず、クライアントの裁量において、後ほど再発行されます。

注: このコントロールフレームは最終的に削除されるかもしれません。これは実験の目的で実装されました。

注: (mnot@mnot.org は必須の GOAWAY がセッションを行儀良く閉じるのに役に立つだろうと提言しています。もしあるセッション上での最後の要求が POST であったとして、サーバーが閉じていたとしたら、クライアントはリクエストが送信されたかどうかわかりません。閉じる前に GOAWAY を要求することは、クライアントに対して、クライアントに対して、どの要求が処理されたか、されていないか通知することになります)

GOAWAY コントロールメッセージ:

  +----------------------------------+
  |1|       1          |       7     |
  +----------------------------------+
  | 0 (flags) |     4 (length)       |
  +----------------------------------|
  |       Last-good-stream-ID        |
  +----------------------------------|

コントロールビット: このメッセージに対するコントロールビットは常に 1 です。

バージョン: SPDY のバージョン番号

タイプ: GOAWAY メッセージのメッセージタイプは 7 です。

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

Last-good ストリーム ID: GOAWAY メッセージの送信者によって、受け入れられた最後のストリーム ID

SUBRESOURCE

サブリソース (SUBRESOURCE) コントロールフレームは、任意のコントロールフレームであり、受信者に必要なリソースを教えるために使われます。もし名前/値ペア内の URL とメソッドが、そのストリーム ID に関連付けされたものと一致しないならば、このコントロールメッセージは無視されなければなりません。

コントロールフレーム

  +----------------------------------+
  |C| Version(15bits) |      8       |
  +----------------------------------+
  | Flags (8)  |  Length (24 bits)   |
  +----------------------------------+
  |0| Stream id (31 bits)            |
  |----------------------------------|
  |  Unused (16 bits) | NV Entries   |
  |----------------------------------|
  | Key value pairs                  |
  +----------------------------------+

長さ: 長さフィールドの後に続くバイト数を表す符号なしの 24 ビット値。SUBRESOURCE フレームの合計長は 8 バイト + 長さです。このフレームの長さは、8 と同じかそれ以上でなければなりません。

ストリーム ID (Stream-id) はサブリソースが関連付けされたストリームのストリーム ID です。

NV エントリ: これに続く名前/値ペアの数

名前/値ブロックは SYN_REPLY と同じです。しかし、url と method は必須フィールドです。

もし送信者が SUBRESOURCE コントロールフレームを使って、クライアントにストリームが作成される (X-Associated-Content) ことを教えたならば、SUBRESOURCE メッセージは、受信者が追加リソースを見つけられるようにデータフレームよりも先に送信されなければならない。

参考資料

タイトルの通り、この日本語訳資料は 2009年12月1日時点のドラフトを元に作成してあります。

最新版は本家 Chromium プロジェクトの SPDY プロトコル仕様書ページをご覧ください。