[25] [DFN[[CODE(URI)@en[[[ws:]]]]]] は [[WebSocket]] over [[TCP]]、
[DFN[[CODE(URI)@en[[[wss:]]]]]] は [[WebSocket]] over [[TLS]] over [[TCP]]
によってアクセスできる [[WebSocket]] [[資源]]を表す [[URL scheme]] です。

* 仕様書

[REFS[
- [2] '''[CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-3>'''
- [17] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-11.1>
- [20] [CITE@en-GB-x-hixie[HTML Standard]] ([TIME[2015-05-06 10:42:35 +09:00]] 版) <https://html.spec.whatwg.org/#parse-a-websocket-url's-components>
]REFS]

* 構文

[3] [[URL scheme]]、[CODE[[[://]]]]、 [[authority]]、[[path]]、
省略可能な [[query]] で構成されます。 [[query]] がある場合は、
直前に [CODE[[[?]]]] が必要です。 [SRC[>>2]]

[FIG(railroad)[
= [[URL scheme]]
= [CODE[[[://]]]]
= [[authority]]
= [[path]]
= ?
== [CODE[[[?]]]]
== [[query]]
]FIG]

[12] [[素片識別子]]を使っては[['''なりません''']] [SRC[>>2]]。

* URL scheme

[4] [[URL scheme]] は、 [CODE(URI)@en[[[ws]]]] または [CODE(URI)@en[[[wss]]]]
です [SRC[>>2]]。

[10] [CODE(URI)@en[[[wss]]]] であれば、当該 [[URL]] は[DFN[[RUBYB[「保安」]@en["secure"]]]]であり、
[DFN[[[the secure flag is set]]]] といいます [SRC[>>2]]。

* authority

[5] [[authority]] は、[[ホスト]]と、省略可能な [[port]] です。
[[port]] がある場合は直前に [CODE[[[:]]]] が必要です。 [SRC[>>2]]

[FIG(railroad)[
= [[ホスト]]
= ?
== [CODE[[[:]]]]
== [[port]]
]FIG]

[6] [[ホスト]]と [[port]] は、 [[RFC 3986]] の定義が参照されています [SRC[>>2]]。
現実には [[URL Standard]] に従い解釈されるものと思われます。

[9] [CODE(URI)@en[[[ws:]]]] の[[既定のポート]]は [CODE[[[80]]]]、
[CODE(URI)@en[[[wss:]]]] の[[既定のポート]]は [CODE[[[443]]]] です [SRC[>>2]]。

* 資源名

[7] [[path]] は、 [[RFC 3986]] [CODE(ABNF)@en[[[path-abempty]]]] です [SRC[>>2]]。

[8] [[query]] は、 [[RFC 3986]] [CODE(ABNF)@en[[[query]]]] が参照されています [SRC[>>2]]。

[11] [DFN[[RUBYB[資源名]@en[resource name]]]]は、
[FIG(list)[
= [[path]] が空なら、 [CODE[[[/]]]]
= [[path]]
= [[query]] が非空なら、 [CODE[[[?]]]]
= [[query]]
]FIG]
... を連結したものです [SRC[>>2]]。

[21] [[資源名]]の解釈は、 [[HTTP]] の場合と同じく、[[サーバー]]に委ねられています。
[[クライアント]]はその意味を一般的に解釈することはできません。

[EG[
[22] 例えば [[query]] を [CODE(MIME)@en[[[application/x-www-form-urlencoded]]]]
形式にすることができますが、そう解釈して良いのは[[サーバー]]と、
[[サーバー]]がそのように解釈していることを知っている[[スクリプト]]だけです。
[[サーバー]]がどう解釈するか事前に知識を得ていない[[クライアント]]がそのように解釈してはいけません。
]EG]

[23] [[[CODE(DOMi)@en[WebSocket]]コンストラクター]]は [[UTF-8]] として[[URLの解決]]を行うと規定されています。
つまり[[スクリプト]]が[[非ASCII文字]]を [[query]] に含めると、
[[UTF-8]] として[[パーセント符号化]]されて[[サーバー]]に送信されます。
[[パス]]部分の[[非ASCII文字]]も、 [[UTF-8]] として[[パーセント符号化]]されます。
ですから、[[WebSocketクライアント]]は[[パーセント符号化]]を [[UTF-8]]
として解釈することが好ましいと思われます。

;; [24] 元々[[パーセント符号化]]されているものは再変換されませんから、
[[UTF-8]] 以外の[[文字コード]]や[[バイナリーデータ]]を含めることも理論上は可能です。
しかし実用上は常に [[UTF-8]] を使うとするべきでしょう。

* 妥当性

[29] [[RFC]] は [[WebSocket接続の確立]]で [[URL]] の妥当性を確認することを求めていましたが、
その検査方法の詳細は不明でした。その曖昧な規定は [[Fetch Standard]] と
[[HTML Standard]] の規定の厳密化により死文化しました。

[HISTORY[
[13] [[WebSocket接続の確立]]は、 [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]]
[[URL]] が妥当なものであるかどうか確認し、非妥当なら失敗します。

[14] どのような検査か完全に明記はされていませんが、[[素片識別子]]が含まれる場合や、
[[ポート]]が数値でない文字列の場合、[CODE[[[//]]]] が含まれない場合などが該当しそうです。

;; [15] [[WebSocket]] の [[RFC]] は [[RFC 3986]] を参照しているので[[非ASCII文字]]は使えないことになりますが、
実際には [[URL Standard]] に従い[[構文解析]]・[[正準化]]が行われた後の [[URL]]
が使われますから、[[非ASCII文字]]は[[正準化]]の段階で [[ASCII文字]]に変換されています。
]HISTORY]

* 構文解析

[28] かつては独自の[[構文解析]]の手続きが [[HTML Standard]] で規定されていましたが、
その後 [[URL Standard]] が整備されたことから、削除されました。
[CODE(URI)@en[ws:]] や [CODE(URI)@en[wss:]] の [[URL]] も通常の
[[URLの構文解析]]が行われた後、 [CODE(JS)@en[new WebSocket]]
の処理で最低限の検査を行い、[[プロトコル]]で利用されることになります。

[HISTORY[
[19] [DFN[[RUBYB[WebSocket URLの部品の構文解析]@en[parse a WebSocket URL's components]]]]は、
次のようにしなければ[['''なりません''']] [SRC[>>20]]。
[FIG(steps)[
= 入力が[[絶対URL]]でなければ、失敗を返し、停止します。
= 入力について[[URLの解決]]を行います。[[URL文字符号化]]は、 [[UTF-8]] とします。
[[基底URL]]は何でも構いません。
= 解決結果の [[URL scheme]] が [CODE(URI)@en[[[ws]]]] か [CODE(URI)@en[[[wss]]]]
でなければ、失敗を返し、停止します。
= 解決結果に[[素片識別子]]があれば、失敗を返し、停止します。
= [VAR[secure]] を、[[URL scheme]] が [CODE[[[wss]]]] なら[[真]]、[CODE[[[ws]]]] なら[[偽]]に設定します。
= [VAR[[[ホスト]]]]を、解決結果の[[ホスト]]に設定します。
= 解決結果に[[空文字列]]以外の[[ポート]]があれば、
== [VAR[[[ポート]]]]を、指定された[[ポート]]に設定します。
= それ以外なら、
== [VAR[[[ポート]]]]を、[VAR[secure]] が[[真]]なら [CODE[[[443]]]]、そうでないなら [CODE[[[80]]]] に設定します。
= [VAR[[[資源名]]]]に、解決結果の[[パス]]を設定します。ただし[[空文字列]]なら、
[CODE[[[/]]]] に設定します。
= 解決結果に [[URL query]] があるなら、[VAR[[[資源名]]]]の末尾に [CODE[[[?]]]]
と [[query]] を追加します。
= [VAR[[[ホスト]]]]、[VAR[[[ポート]]]]、[VAR[[[資源名]]]]、[VAR[[[secure]]]]
を返します。
]FIG]
]HISTORY]

* 比較

[18] [[ホスト]]を [[Punycode]] により表現するのと[[パーセント符号化]]により表現するのは等価です [SRC[>>17]]。

* HTTP URL への変換

[32] [[fetch]] は、 [[WebSocket]] の処理の場合、 [[URL scheme]]
を [[WebSocket]] のものから [[HTTP]] のものに書き換えます。
各種[[仕様]]の [[URL]] に基づく操作は書き換え後の状態で適用されます。

[EG[
[33] 従って [[HSTS]]、[[Mixed Content]]、[CODE(HTTP)@en[Upgrade-Insecure-Requests]]
などは、 [[HTTP]] のみならず [[WebSocket]] にも同様の形で適用されます。
]EG]

[HISTORY[
[30] [[RFC]] 時代は、 [[HTTP]] [[URL]] と [[WebSocket]] [[URL]] の関係性が曖昧でした。

[16] [[WebSocket接続の確立]]は、相当する [CODE(URI)@en[[[http:]]]]/[CODE(URI)@en[[[https:]]]]
[[URL]] を使うことがあります。これは [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]]
にそれぞれ相当するものと思われますが、明記はされていません。

[31] [[HSTS]] が [[WebSocket]] に適用されるのかどうかも曖昧でした。
]HISTORY]

* 歴史

[REFS[
- [1] [CITE@en[draft-ietf-hybi-thewebsocketprotocol - The WebSocket protocol]] 
<http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol#section-3>
]REFS]

[26] [CITE@en[Fix #244: improve HSTS language · whatwg/fetch@6568ab8]]
([TIME[2016-03-27 22:44:34 +09:00]] 版)
<https://github.com/whatwg/fetch/commit/6568ab88c1fbfb581f63f8e5f020c367ef38e78d>

[27] [CITE@en[Update WebSocket to use Fetch's WebSocket alterations · whatwg/html@3dadbca]]
([TIME[2016-03-28 23:11:15 +09:00]] 版)
<https://github.com/whatwg/html/commit/3dadbcad063a10b586ef52dd4b427aa339048ee7>