[61] WebSocket では、 HTTP の Upgrade:
ヘッダーと
101
応答を使って接続の確立 (ハンドシェイク)
を行います。
[62] WebSocket
コンストラクターは、
新たに WebSocket接続を確立するものです。
[84] WebSocket
をコンストラクターとして呼び出すと、
WebSocket サーバーに接続することができます。
[125] 第1引数には、 WebSocket サーバーのエンドポイントの URL
を指定します。これは URL scheme が wss:
または ws:
のものです。第1引数は必須です。
[126] 第2引数には部分プロトコルの名前を指定できます。 部分プロトコルの指定が必要ない場合は、省略できます。 複数ある場合は名前の配列として指定できます。
[127] コンストラクターは WebSocket
オブジェクトを返します。
以後このオブジェクトを通じて送受信したり、エラーを受け取ったり、
接続を閉じたりできます。
[63] WebSocket
コンストラクターは、
次のように動作しなければなりません。
[83] 更に、並列に、次のようにしなければなりません。 >>60
[81] Webブラウザー以外の WebSocket クライアントは必ずしもこの通りに処理できないかもしれませんが (例えば設定群オブジェクトに相当するものが存在しないことも多いでしょう。)、 有用であるためには Webブラウザーと同様の形で動作することが期待されます。
[137] WebSocket接続を得るとは、
URL URL について次のようにすることをいいます >>130。http
なら偽、それ以外なら真に設定します >>130。
[6] プロキシ自動設定スクリプトに渡す URL は、
ホスト、ポート、資源名、「保安」フラグ (ws:
or wss:
)
から構築します >>1。
[5] WebSocket 用のプロキシの設定を設けていない場合は、 SOCKS5、HTTPS 用、HTTP 用の優先順でプロキシを選択することが推奨されています >>1。
[9] TLS を使う場合 SNI が必須とされていますが、ホストが IPアドレスで指定された時どうしなければならないのかは不明です。
[153] WebSocket接続を得る手続きは、 RFC では WebSocket接続の確立の一部として規定されていましたが、 Fetch Standard によって独立した手順とされました。
[128] この接続を得る処理は、 HTTP-network fetch から呼び出されます。 通常のHTTP接続を得る処理と似た処理ではありますが、 通常のHTTP接続のように要求と応答のやり取りの後に他の要求に再利用できない点が大きく異なっています。
[2] WebSocket接続の確立は、 URL、プロトコル群、クライアントについて、 次のようにすることを言います >>130。
ws
なら http
に、
それ以外なら https
に変更します。none
no-referrer
websocket
include
no-store
error
Upgrade
websocket
Connection
Upgrade
Sec-WebSocket-Key
Sec-WebSocket-Version
13
Sec-WebSocket-Protocol
Sec-WebSocket-Extensions
permessage-deflate
拡張の値
(例えば permessage-deflate; client_max_window_bits
)[134] HSTS、Upgrade Insecure Requests、CSP、Mixed Content、 クッキー、port blocking など fetch に関わる諸機能は、 WebSocket 接続にも適用されます。これらは fetch アルゴリズム内部で処理されます。
[158] fetch 内で Host:
や User-Agent:
や Origin:
などのヘッダーが追加されます。
[109] Referer:
は使用されず、参照元ポリシーも適用されません。
[58] 要求ヘッダーには User-Agent:
Chrome, Firefox や
DNT:
Chrome, Firefox や
Accept-Encoding:
Chrome, Firefox や
Accept:
Firefox も含まれるかもしれません。
[117] Chrome は仕様通り Connection: Upgrade
ですが、 Firefox は Connection: keep-alive, Upgrade
です。
[12] Web互換性のため、
Accept-Language:
ヘッダーを含めるべきです >>114。
[184] このWebSocket接続の確立 >>1 の処理はかつては RFC で規定されていましたが、 2016年3月の Fetch Standard と HTML Standard の大規模リファクタリングによってほとんどが Fetch Standard に移動しました。
[64] 入力 URL の処理について、 HTML Standard は URL Standard に基づき正準化した値を使っており、 RFC は RFC 3986 URI を参照して規定しているため、 理論上は両者の差異のために予測できない挙動となる可能性がありました。 実際はすべて当初より URL Standard に近い動作で統一されているものと思われますが、 リファクタリングにより URL Standard ベースの処理になり、理論上も問題は解消しました。
[10] RFC は、 Webブラウザーは起源を指定しなければならず、
それ以外は指定しても良い >>1 と規定していました。
これは Origin:
ヘッダーが指定されるかどうかに影響します。
本来 WebSocket は Webブラウザー向けプロトコルなのですから、
Webブラウザー以外のクライアントもできるだけ
Webブラウザーに似せた動作にするのが適当そうです。 (が
Webブラウザー以外のクライアントは Web
の起源ベースのセキュリティーモデルには従っていないかもしれませんから、
適当な値を決めるのが難しいこともあるかもしれません。)
[8] 適切なクッキーを送るヘッダー群は、
送信するべき Cookie:
ヘッダーを指定するものです。
かつての HTML Standard が参照していますが、 RFC 6455 にはありません。
(WHATWG 時代には存在していたものが、 IETF で削除されたようです。 IETF
ではよくあることです。)
[11] RFC は HTTP/1.1 以上を使って要求を送信することを求めていましたが、 現在の Fetch Standard はなぜかこれを (HTTP についても WebSocket についても) 明言していません。
[14] 要求対象は、直接接続なら資源名のみ、 プロキシ接続なら
HTTP URL と思われますが、明記されていません。どちらでも良いということでしょうか
(それは一般的な慣習とは異なります)。また ws:
/wss:
がそれぞれ http:
/https:
に変換されるものと思われますが、
明記されていません。
[159] fetch により応答応答が利用可能となったら、次のようにします
>>130。101
以外なら、Upgrade:
ヘッダーが無いか、
websocket
(ASCII大文字・小文字不区別) が含まれていない場合 >>1Connection:
ヘッダーが無いか、
Upgrade
(ASCII大文字・小文字不区別) が含まれていない場合 >>1Sec-WebSocket-Accept:
ヘッダーが無いか、
値が要求の Sec-WebSocket-Key
の値に
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
を連結した値の SHA-1 を Base64 符号化したものでない場合
(前後に空白があっても構いません。) >>1Sec-WebSocket-Extensions:
ヘッダーが構文的に正しくない場合や、要求で指定しなかった拡張が指定されている場合
>>1Sec-WebSocket-Protocol:
ヘッダーが構文的に正しくない場合や、
要求で指定しなかった部分プロトコルが指定されている場合 >>1Sec-WebSocket-Protocol
ヘッダーをヘッダー値の構文解析した結果が
null、失敗、空バイト列のいずれかの場合OPEN
に設定します。 RFCSec-WebSocket-Extensions:
ヘッダーの値
(なければ null) に設定します。 RFCSec-WebSocket-Protocol:
ヘッダーの値
(なければ null) に設定します。 RFC
[118] 応答のプロトコルの版の検査は求められていないようです。
[65] RFC では、101
以外の状態符号の応答を受信した時、
HTTP に従い処理することになっていました。例えば 401
ならHTTP認証の処理を行えますし、 3xx
なら
HTTPリダイレクトしても良いことになっています。 >>1
しかし、 HTML Standard は WebSocket接続失敗として処理しなければならないと規定しています >>60。
HTML Standard を引き継いだ Fetch Standard も、
101
以外をエラーとして処理することを求めています >>130。
[66] これは、サーバーがリダイレクトすることで、スクリプトが意図しない相手と接続してしまうため危険であるのが理由 >>60 とされています。
理論上は WebSocket
以外の WebSocketクライアントはこの規定に従う義務はありませんが、
敢えて危険をおかして Webブラウザーと異なる動作を採る必要性も無さそうです。
[115] Chrome は、 401
が返されたら、適切な credentials
を持っていなければエラーとして扱います。 Firefox は、通常の
HTTP認証のモーダルダイアログを表示します。
Firefox はHTTP接続を再利用可能なら、再利用して再試行するようです。
[122] Firefox も Chrome も、 1xx
(101
以外)
をエラーとして扱います。
[124] Chrome はヘッダーを読み終わったところでエラーなら切断するようですが、 Firefox はそうでもないようで、しばらく (ずっとではない) 切断されません。
[68] WebSocket
オブジェクトは、
内部状態としてクライアント指定プロトコル群を持ちます。
[54] 受信したデータが理解できない、想定外であるなどの理由があれば、 いつでもTCP接続を閉じることができます >>53。
[116] Chrome は Content-Length:
ヘッダーについて、
通常のHTTP応答同様の検査を行うようです。
[120] 応答の Sec-WebSocket-Protocol:
の値の検査を
Chrome は行いますが、 Firefox は行わないようです。
なお Chrome は (RFC と異なり) 値をリスト (#
)
として構文解析するようです。
[121] 応答の Sec-WebSocket-Extensions:
の値が空文字列の時、
Firefox はエラーにせず、 Chrome はエラーにします。値が ,
だけの時 (空のリストだが空文字列でない時)、 Firefox はエラーにし、
Chrome はエラーにしません。 RFC に従うならどちらもエラーになるべきです。
[123] Chrome は接続成功時と 401
時に Set-Cookie:
を処理するようです。 Firefox は接続が成功か否かや状態符号に関わらず、
Set-Cookie:
を処理するようです。
[90] WebSocket の規定に従わないサーバーは、クライアントからの要求を待たずに応答 (や応答になっていないデータ) を送信するかもしれません。クライアントはそれに特別な対処を行う必要はありませんが、 >>54 を根拠に切断しても良いのかもしれません。
[180] かつて RFC はクッキーの処理のため応答の処理で Cookies Set During the Server's Opening Handshake という語を使い、これを HTML Standard が利用する形を採っていました。 これは Fetch Standard との統合により死文化しました。
[30] サーバーは、 TCP ないし TLS over TCP でホストとポートの組を listen していることが期待されています。
[16] サーバーは、クライアントとのTCP接続が確立されたら、 次のようにしなければなりません。
GET
でない場合http:
/https:
の絶対URLでない場合
(構文的に正しくない場合を含む。)Host:
が無いか、構文的に正しくないか、
サーバーの authority でない場合Upgrade:
が無いか、 websocket
(ASCII大文字・小文字不区別) を含まない場合Connection:
が無いか、 Upgrade
(ASCII大文字・小文字不区別) を含まない場合Sec-WebSocket-Key:
が無いか、
16バイトの値を Base64 符号化したもので無い場合Sec-WebSocket-Version:
が無いか、
13
で無い場合Sec-WebSocket-Protocol:
や
Sec-WebSocket-Extensions:
がある場合で、構文的に正しくない場合Origin:
ヘッダーを検査して不適切なら、Sec-WebSocket-Protocol:
ヘッダーの値から得られた部分プロトコル群から、
サーバーが承認するもののみのリストを得ます。該当するものがなければ、 null とします。 >>1Sec-WebSocket-Extensions:
ヘッダーの値から得られたプロトコル拡張群から、
サーバーが承認するもののみのリストを得ます。該当するものがなければ、 null とします。 >>1101
。Upgrade
websocket
。Connection
Upgrade
。Sec-WebSocket-Accept
Sec-WebSocket-Key:
の値に
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
を連結し、
SHA-1 を計算し、RFC 4648 Base64 符号化したもの。Sec-WebSocket-Protocol
#
) (null でない場合のみ)。Sec-WebSocket-Extensions
OPEN
とします。 >>1[17] Origin:
ヘッダーが無ければ、
Webブラウザーからの要求と解釈するべきではありません >>1。
[59] なお Webブラウザー以外のクライアントは、好きな Origin:
を送ることができます。クライアントが Webブラウザーであることを判定する方法はありません
(Webブラウザーでないことは >>17 の通り判定できますが)。
Origin:
は Webブラウザー上で適切なアクセス元からの接続かどうかを判断するために使うことができますが、
非 Webブラウザーに対する認証のような仕組みとして用いることはできません。
[87] サーバーが返す応答に他のHTTPヘッダーを指定できるかどうか、
RFC >>1 は明記していません。 HTTPサーバーとしては Server:
や Date:
のような必須のヘッダーが他にありますし、
受信するクライアントの側では Set-Cookie:
や HSTS や UIR
などの一般的なHTTPヘッダーの処理を行いますから、
現実問題としてこれらを使うことは可能です。しかし Upgrade:
や
Content-Language:
や Refresh:
のようにここでの意味が明確でないものは、
使うべきではないでしょう。
[7] この手順の途中で停止する時は、WebSocket接続を閉じるものと思われます。
[55] 受信したデータが理解できない、想定外であるなどの理由があれば、 いつでもTCP接続を閉じることができます >>53。 不正なデータを受信した時は、適切な HTTP応答を送信するべきです >>53。
[28] 状態が OPEN
となると、データを送受信できます >>1。
[48] この手順を完走したら、WebSocket接続確立となるものと思われます。
[29] 要求本体が含まれる場合のサーバーの処理について明文規定はありません。
正常なクライアントの WebSocket接続の確立では、要求本体が含まれることはありません。
従って、要求本体が空でないなら、サーバーは 400
応答などを返して拒絶して構わないと思われます。
要求ヘッダーより後のデータが WebSocket データと考えているサーバーは、
要求本体が含まれているとおかしくなってしまいます。
[189] 実際には、
WebSocketハンドシェイクに失敗した時や、
Sec-WebSocket-Protocol
がサーバーの予期せぬ値 (または予期せぬ未指定)
だったとき、
応答を返すかわりにすぐに接続を閉じたり、
RST
を送ったりするサーバーもあるようです。
WebSocket
インターフェイス url
属性[70] WebSocket
インターフェイスの
url
IDL属性は、
文脈オブジェクトの URL
にURLの直列化を適用した結果を返さなければなりません >>69。
この値は常に ws:
または wss:
の絶対URLです。
[176] WebSocket
オブジェクトは、
URL を持ちます >>53。
これは WebSocket
コンストラクターにより設定され、
以後変化しません。接続先として指定された URL を表します。
[131] CSP、Mixed Content、Upgrade Insecure Requests は猿パッチを定義し、 後にこれを RFC や HTML Standard と統合しようとしましたが、 IETF は仕様の改訂を行おうとしませんでした (WebSocket の歴史の項を参照)。
[133] 2016年3月、 RFC と HTML Standard にあった接続の確立に関わる部分がこれら猿パッチを解消する形で Fetch Standard の fetch アルゴリズムと統合される形で再定義され、 一連の処理の流れが明確化されました。 クッキーや HSTS や Referrer Policy や Service Workers など fetch に関わる諸仕様との関係も明確になりました。
[169] WebSocket: leave port blocking to the network layer (Fetch) · whatwg/html@17336ad ( 版) https://github.com/whatwg/html/commit/17336ad69be4744dfc17194f2ee51bd730ca4d93
[79] Update WebSocket to use Fetch's WebSocket alterations · whatwg/html@3dadbca ( 版) https://github.com/whatwg/html/commit/3dadbcad063a10b586ef52dd4b427aa339048ee7
[185] Dealing with websockets #61 ( (deian著, )) https://github.com/w3c/webappsec-cowl/commit/05757139e1a8a4e842d7d43d2acc91d1cf62cce9
If the HTTP GET request contains an Origin header, the MSRP WebSocket
Server SHOULD indicate Cross-Origin Resource Sharing [CORS] by adding
an Access-Control-Allow-Origin header to the 101 response.
[4] Properly set the Origin header for WebSocket requests (nox著, ) https://github.com/whatwg/fetch/commit/406c5a60595c63d323693050b45d40823933e185
[57] 426736 - WebSocket connections not using configured system HTTPS Proxy in MacOS - chromium - Monorail () https://bugs.chromium.org/p/chromium/issues/detail?id=426736
[91] WebSocket connections don't appear to send referrers · Issue #630 · whatwg/fetch () https://github.com/whatwg/fetch/issues/630
[92] WebSocket handshake has no referrer (annevk著, ) https://github.com/whatwg/fetch/commit/60db35ed0d18c6636f002da91593bfa5ee58494e
[187] WebSocket handshake has no referrer by annevk · Pull Request #632 · whatwg/fetch () https://github.com/whatwg/fetch/pull/632
[188] WebSocket connections don't appear to send referrers · Issue #630 · whatwg/fetch () https://github.com/whatwg/fetch/issues/630
[190] Stop saying HTTP authentication over WebSocket is disallowed (ricea著, ) https://github.com/whatwg/fetch/commit/8b070f14a1fb2d1f8f4d07e1902a40a14f77b060
[191] WebSocket: "HTTP authentication will not function" is not correct · Issue #565 · whatwg/fetch () https://github.com/whatwg/fetch/issues/565
[192] Stop saying WebSocket auth is disallowed by ricea · Pull Request #761 · whatwg/fetch () https://github.com/whatwg/fetch/pull/761
[193] Use forgiving-base64 encode on WebSocket's keyValue (Garee著, ) https://github.com/whatwg/fetch/commit/e26376910a3f1b230177104759de8fcf33a02f2e
[194] Use forgiving-base64 encode for WebSocket · Issue #712 · whatwg/fetch () https://github.com/whatwg/fetch/issues/712
[195] Change encoding of WebSocket keyValue to forgiving-base64-encoding by Garee · Pull Request #844 · whatwg/fetch () https://github.com/whatwg/fetch/pull/844