WebSocketフレーム

フレーム (WebSocket)

[53] フレーム (frame) は、WebSocket接続の確立の後に WebSocketサーバーWebSocketクライアントとの間でやり取りされる情報の単位です。

仕様書

構文

[8] フレームは、次のような構造です >>1。 可変長のヘッダーと、可変長のデータで構成されます。 ヘッダーの長さとデータの長さは、どちらもヘッダーの値により決まります。

width
32
  1. 1 FIN
  2. 1 RSV1
  3. 1 RSV2
  4. 1 RSV3
  5. 4 opcode
  6. 1 マスク
  7. 23 payload長
  8. 32 マスクキー
  9. 32... Payload Data
フレーム
FIN
メッセージの最後の断片 (fragment) であるかどうかを示します。 0 は最後でないこと、 1 は最後であることを表します。
RSV1
拡張により規定される場合を除き、 0 でなければなりません
RSV2
拡張により規定される場合を除き、 0 でなければなりません
RSV3
拡張により規定される場合を除き、 0 でなければなりません
opcode
payload data の解釈を規定するものです。
マスク (mask) (frame-masking-key)
payload dataマスクされるかどうかを示します。 1マスクされていること、0マスクされていないことを示します。
payload長 (payload length)
payload data の長さをバイト単位で示します。
マスクキー (masking key) (frame-masking-key)
マスクする際に使う32ビットの値です。マスクビットが 1 であれば、本欄が存在します。 0 なら、存在しません。
拡張データ
拡張により規定された長さと用途のデータです。拡張がなければ長さ0です。
応用データ (application data)
任意の応用のデータです。

opcode

[14] データフレーム (非制御フレーム) の opcode には、 次のものがあります >>1

[44] 制御フレーム (control frame) opcode には、次のものがあります >>1

[45] 制御フレームは、状態を通信するために使うものです >>1

[51] 予約された opcode は、拡張が使うことができます >>49

[62] opcode にはIANA登録簿があります >>61, >>65

[10] 未知の opcodeフレームを受信した場合 WebSocket接続失敗としなければなりません >>1

payload

[18] payloadデータ (payload data) は、 拡張データ応用データを指します >>1

[47] payload長は、バイト単位のpayloadデータの長さを表すものです。 次のうち、最短の形を使わなければなりません>>1

[54] 従って最大長は263-1バイトです。 (つまり 8388608 TB 未満まで表現できます。)

[46] 制御フレームpayload長は、125バイト以下でなければなりません >>1

[50] これらの規定に違反したフレームを受信した時にどう処理するべきかは不明です。

[56] 最短形でない場合、 Chrome状態符号1002 で理由が WebSocket Protocol ErrorCloseフレームを送信します。 Firefox は16ビット整数なら最短形でなくてもよく、 64ビット整数なら送信しないで接続を閉じます。

[57] 値が 232-1 以下なら、 ChromeFirefox も受信しようと試みるようです。 しかし Chrome は受信し続けた末にクラッシュ、 Firefox は途中で断念して RST するようです。 232 以上なら (64ビット整数で最上位ビットが立っている場合も)、 ChromeコンソールInvalid frame header と表示して (error イベントは無し) すぐに切断します。 Firefoxerror イベントを発火してすぐに切断します。

[58] 制御フレームなのに長さが125を超えていると、 ChromeFirefoxerror イベント発火し、 ChromeCloseフレームを送信 (1002 WebSocket Protocol Error)、 Firefox接続を閉じます。

[55] まとめると、フレームの長さの決定は次のように行えます。

  1. 次の2バイトを取得します。
  2. 長さを、取得した2バイト目の下位7ビットとします。
  3. 長さが 126 なら、
    1. 次の2バイトを取得します。
    2. 長さを、ネットワークバイト順の16ビット符号無し整数として解釈した値に設定します。
    3. 長さが 126 未満なら、WebSocket接続失敗とします。
  4. 長さが 127 なら、
    1. 次の8バイトを取得します。
    2. 長さを、ネットワークバイト順の64ビット符号無し整数として解釈した値に設定します。
    3. 長さが 216 未満なら、 WebSocket接続失敗とします。
  5. 長さが263以上なら、 WebSocket接続失敗とします。
  6. 長さが実装の扱える範囲を超えていれば、 WebSocket接続失敗とします。
  7. 制御フレームで、長さが125バイトを超えているなら、
    1. WebSocket接続失敗とします。
  8. 2バイト目の最上位ビットが立っていれば、
    1. 次の32ビットを取得します。

マスク

[19] フレームは、マスク (mask) する場合とマスクしない場合があります。

[20] マスクしたフレームは、マスク欄の値が 1 でなければなりません >>1

[21] マスクキー (masking key) は、クライアント無作為に選択した32ビット値です。 マスクキーは、マスクしたフレーム内のマスクキー欄に示されます。 >>1

[2] クライアントは、サーバーに送信するすべてのフレームマスクしなければなりません >>1

[5] サーバーは、クライアントマスクしたフレームを送信してはなりません >>1

[23] マスクする際に新鮮な値をマスクキーとして選ばなければなりません >>1マスクキーは予測不能である必要がありますから、 強いエントロピー源から得なければなりません >>1。 前のフレームから以後のフレームマスクキーを容易に予測できてはなりません >>1

[3] これは、プロキシ等の中間器の混乱を防ぐため、またセキュリティーのために必要な措置です >>1, >>43
[22] RFC 4086 に強いエントロピー源についての議論があります >>1

[24] マスクの適用と復元は、どちらも次の手順により行います >>1

  1. [25] 入力データの各オクテットについて、
    1. [26] 出力のオクテット i は、入力のオクテット iマスクデータのオクテット i mod 4 の XOR とします。

[4] サーバーは、マスクされていないフレームを受信したら、 接続を閉じなければなりません >>1。 この場合サーバーClose フレーム状態符号 1002 で送信して構いません >>1

[6] クライアントは、マスクされたフレームを受信したら、 接続を閉じなければなりません >>1。 この場合クライアントClose フレーム状態符号 1002 で送信して構いません >>1

[68] Microsoft は、 Web ではなく公衆インターネットでもない限られた環境ではマスクしないことでパフォーマンスが向上するとして、 マスクキーを 0 とすることによりデータをマスクしないで送信するオプションを実装しています >>67

断片化

[27] 断片化 (fragmentation) により、 送信開始時点で送信データの大きさがわからない場合でも送信開始できます >>1

[28] 断片化を使って、送信データの末端を待たずに適度にバッファーにデータが溜まった時点で送信できます >>1

[29] 断片化多重化 (multiplexing) により単一のWebSocket接続を複数の大きなメッセージで共有するために使うことができます。 ただし WebSocket 本体では多重化のための拡張は規定していません。 >>1

[48] 断片化された(かもしれない)状態のものがフレームと呼ばれるのに対し、 そのデータを結合したものがメッセージ (message) >>1 と呼ばれています。

[39] 受信者は断片化に対応しなければなりません >>1

[31] 1つのメッセージが単一フレームで表現される時は、 FIN1 に設定され opcode0 以外となります >>1

  1. (FIN = 1, opcode0)

[32] 1つのメッセージが複数フレームで表現される時は、 FIN0 に設定され opcode0 以外となるフレーム、 0個以上の FIN0 に設定され opcode0フレームFIN0 に設定され opcode0 のフレームの列となります >>1

  1. (FIN = 0, opcode0)
  2. *
    1. (FIN = 0, opcode = 0)
  3. (FIN = 1, opcode = 0)

[33] 制御フレームは、断片化してはなりません >>1中間器制御フレームの断片化状態を変更してはなりません >>1

[59] 制御フレームFIN が 0 の場合には、 Chrome でも Firefox でも接続が閉じられます。 Chrome状態符号1002 で理由が WebSocket Protocol ErrorCloseフレームを送信します。

[35] 断片は、送信者が送信した順序で受信者に配送しなければなりません >>1

[34] 制御フレームを他の断片化されたメッセージフレーム間に注入しても構いません >>1。受信者はこれを扱えなければなりません >>1

[42] 大きなメッセージの転送中に ping の遅延が大きくなることを防ぐためです >>1

[36] 拡張により特に規定される場合を除き、 断片を他の断片化されたメッセージフレーム間に注入してはなりません >>1

[52] これら禁止規定に反した場合にどう処理するべきかは不明です。

[30] 拡張で特に規定される場合を除き、フレーム (の境界) は意味を持ちません。 1つの大きなメッセージも、複数に分割されたフレームを順に連結したものも、等価です。 送信者は任意の大きさに分割できます。 >>1

[37] 中間器は、拡張が適用されない場合や、 すべての適用される拡張を理解し問題ないと判断できる場合には、 フレームを分割したり結合したりするかもしれません。 >>1 RSV1, RSV2, RSV3 のいずれかが設定されているか拡張が用いられていて、その意味を理解できなければ、 断片化の状態を変更してはなりません >>1

[40] WebSocket handshake を見ていない中間器は、 断片化の状態を変更してはなりません >>1

[41] どういう状況でしょうか? WebSocket接続の確立とそれ以後の処理を別の中間器で行う場合??

[38] 拡張によっては、各フレームにのみ拡張データを含められる、 最初のフレームにのみ含められるといったような規定があるかもしれません。 >>1

受信

[69] WebSocketメッセージ受信を参照。