-
Notifications
You must be signed in to change notification settings - Fork 4
/
314.txt
493 lines (431 loc) · 32.4 KB
/
314.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
[61] [[WebSocket]] では、 [[HTTP]] の [CODE(HTTP)@en[[[Upgrade:]]]] [[ヘッダー]]と
[CODE(HTTP)[[[101]]]] [[応答]]を使って[[接続]]の[[確立]] ([[ハンドシェイク]])
を行います。
[62] [CODE(DOMi)@en[[[WebSocket]]]] [[コンストラクター]]は、
新たに [[WebSocket接続]]を確立するものです。
* 仕様書
[REFS[
- [15] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-2.1>
- [1] '''[CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-4>'''
- [47] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-7.1.4>
- [49] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-9>
- [50] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-10.2>
- [51] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-10.5>
- [53] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-10.7>
- [56] [CITE[RFC Errata Report]] ([TIME[2015-05-16 22:26:12 +09:00]] 版) <http://www.rfc-editor.org/errata_search.php?rfc=6455>
-- [113] [CITE[RFC Errata Report]] ([TIME[2015-06-30 11:25:51 +09:00]] 版) <http://www.rfc-editor.org/errata_search.php?rfc=6455&eid=4398>
- [60] [CITE@en-GB-x-hixie[HTML Standard]] ([TIME[2015-05-06 10:42:35 +09:00]] 版) <https://html.spec.whatwg.org/#dom-websocket>
- [69] [CITE@en-GB-x-hixie[HTML Standard]] ([TIME[2015-05-06 10:42:35 +09:00]] 版) <https://html.spec.whatwg.org/#dom-websocket-url>
- [77] [CITE@en-GB-x-hixie[HTML Standard]] ([TIME[2015-05-06 10:42:35 +09:00]] 版) <https://html.spec.whatwg.org/#feedback-from-the-protocol>
- [108] [CITE@en[Mixed Content]] ([TIME[2015-05-17 18:30:14 +09:00]] 版) <https://w3c.github.io/webappsec/specs/mixedcontent/#websockets-integration>
]REFS]
* クライアントの動作
[63] [CODE(DOMi)@en[[[WebSocket]]]] [[コンストラクター]]は、
次のように動作しなければ[['''なりません''']]。
[FIG(steps)[
= [71] 第1[[引数]]を [CODE(IDL)@en[[[DOMString]]]] として解釈します。この[[引数]]は必須です。 [SRC[>>60]]
= [72] 第2[[引数]]を解釈します。 [SRC[>>60]]
== [CODE(IDL)@en[[[DOMString]]]] またはその[[配列]]として解釈します。
== 指定されていなければ、[[空文字列]]とみなします。
== [[配列]]でなければ、その値のみを含む[[配列]]とみなします。
= [75] 第1引数について [[WebSocket URLの部品の構文解析]]を行います。
[VAR[[[ホスト]]]]、[VAR[[[ポート]]]]、[VAR[[[資源名]]]]、[VAR[[[secure]]]]
を得るか、失敗します。 [SRC[>>60]]
= [76] 失敗なら、 [CODE(DOMe)@en[[[SecurityError]]]] [[例外]]を投げ、停止します。 [SRC[>>60]]
= [73] 新しい [CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]を作成します。
[FIG(list members)[
[FIGCAPTION[
[CODE(DOMi)@en[[[WebSocket]]]] ([[WebSocket接続]])
]FIGCAPTION]
:接続の状態:[DFN[[CODE[[[CONNECTING]]]]]] [SRC[>>1]]。
:[CODE(DOMa)@en[[[readyState]]]]:[DFN[[CODE[[[CONNECTING]]]]]] ([CODE(HTTP)[[[0]]]]) [SRC[>>60]]。
:[CODE(DOMa)@en[[[url]]]]:[[解決]]して得られた [[URL]] [SRC[>>60]]。
:[CODE(DOMa)@en[[[extensions]]]]:[[空文字列]] [SRC[>>60]]。
:[CODE(DOMa)@en[[[protocol]]]]:[[空文字列]] [SRC[>>60]]。
:[CODE(DOMa)@en[[[binaryType]]]]:[CODE(DOM)@en[[[blob]]]] [SRC[>>60]]。
]FIG]
= [78] [VAR[[[secure]]]] が[[偽]]の場合、
== [125] [[入口設定群オブジェクト]]の[[起源]]が [[URL scheme]] を持ち、それが[[保安プロトコル]]である場合、
[CODE(DOMe)@en[[[SecurityError]]]] [[例外]]を投げ、停止します。 [SRC[>>60]]
== [126] [VAR[[[ホスト]]]]が[[ドメイン]]であり、
[[既知HSTSホストドメイン名一致]] ([CODE(HTTP)@en[[[includeSubDomains]]]]
[[指令]]ありのものと[[超ドメイン一致]]するか、有無に関わらず[[合同一致]]) するなら、 [VAR[>>60]]
=== [127] [VAR[[[secure]]]] を[[真]]に設定します。
=== [128] [VAR[[[ポート]]]]が [CODE[[[80]]]] なら、[CODE[[[443]]]] に設定します。
= [79] [VAR[[[ポート]]]]が [[port blocking]] する設定となっているなら、
[CODE(DOMe)@en[[[SecurityError]]]] [[例外]]を投げ、停止します。 [SRC[>>60]]
= [80] 第2引数から得られた[[配列]]の要素のいずれかが[[部分プロトコル]]名として構文的に正しくなければ、
[CODE(DOMe)@en[[[SyntaxError]]]] [[例外]]を投げ、停止します。 [SRC[>>60]]
= [81] [VAR[[[起源]]]]を、[[入口設定群オブジェクト]]の[[起源]]の[[ASCII直列化]]したものに設定します。 [SRC[>>60]]
= [87] [[文書環境]]の場合、[CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]を、本[[コンストラクター]]が属する
[CODE(DOMi)@en[[[Window]]]] [[オブジェクト]]の [CODE(DOMi)@en[[[WebSocket]]]]
のリストに[[弱い参照]]として追加します。 ([[unloading document cleanup steps]] で参照されます。)
= [82] [CODE(DOMi)@en[[[WebSocket]]]] オブジェクトを返します。 [SRC[>>60]]
= [83] [[並列に]]実行します。 [SRC[>>60]]
== [84] [CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]の[[クライアント指定プロトコル群]]を、
第2引数から得られた[[配列]]に設定します。
== [85] [[WebSocket接続の確立]]を行います。
[FIG(list members)[
:[[ホスト]]:[VAR[[[ホスト]]]]
:[[ポート]]:[VAR[[[ポート]]]]
:[[資源名]]:[VAR[[[資源名]]]]
:[[secure]]:[VAR[[[secure]]]]
:[[部分プロトコル]]群:[[クライアント指定プロトコル群]]
:[[拡張]]:空のリスト
:[[適切なクッキーを送るヘッダー群]]:第1引数で指定された [[URL]]
について[[利用者]]の[[クッキーストア]]から計算した [[cookie-string]] が値である
[CODE(HTTP)@en[[[Cookie:]]]] [[ヘッダー]] ([[「非HTTP」API]]では''無い'')
]FIG]
]FIG]
@@ [CODE(DOMa)@en[[[url]]]] [[属性]]や [[Mixed Content]] 制約との適用順序は不明です。
@@ [[Mixed Content]] [SRC[>>108]], >>113,
[CITE@en[Upgrade Insecure Requests]] ([TIME[2015-05-17 18:30:14 +09:00]] 版) <https://w3c.github.io/webappsec/specs/upgrade/#websockets-integration>
[CITE@en[Content Security Policy]] ([TIME[2015-05-17 18:30:14 +09:00]] 版) <https://w3c.github.io/webappsec/specs/content-security-policy/#directive-connect-src>
[2] [[クライアント]]は、[DFN[[RUBYB[WebSocket接続の確立]@en[Establish a WebSocket Connection]]]]で、
次のようにしなければ[['''なりません''']] [SRC[>>1]]。
[8] この手順は、入力として次のものを受け取ります。
[FIG(list members)[
:[[ホスト]]:接続先の[[ホスト名]]です。必須です。
:[[ポート]]:接続先の[[ポート番号]]です。必須です。
:[[資源名]]:接続先の[[資源]]を表します。必須です。
:[[secure]]:[[TLS]] を使うか否かを表します。
:[[起源]]:
[10] [[Webブラウザー]]は、[[起源]]を指定しなければ[['''なりません''']]。
これは接続を開いた元を表すものです。
それ以外の[[クライアント]]は、[[起源]]を指定しても構いません。 [SRC[>>1]]
:[[部分プロトコル]]群:
[11] [[クライアント]]が通信したい[[部分プロトコル]]を優先順に指定するものです。
各[[部分プロトコル]]名は、[[字句]]です。
同じ[[部分プロトコル]]を複数指定しては[['''なりません''']]。 [SRC[>>1]]
:拡張:
[12] [[クライアント]]が利用したい[[WebSocket拡張]]を指定するものです [SRC[>>1]]。
:[DFN[[RUBYB[適切なクッキーを送るヘッダー群]@en[headers to send appropriate cookies]]]]:
送信するべき [CODE(HTTP)@en[[[Cookie:]]]] [[ヘッダー]]を指定するものです。
[[HTML Standard]] が参照していますが、 [[RFC 6455]] にはありません。
([[WHATWG]] 時代には存在していたものが、 [[IETF]] で削除されたようです。 [[IETF]]
ではよくあることです。)
]FIG]
[FIG(steps)[
= 入力として与えられた[[ホスト]]、[[ポート]]、[[資源名]]、[[secure]]
フラグが [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]] [[URL]]
の構成要素として正しいかどうかを検査します。
正しくなければ[[WebSocket接続失敗]]を実行し、停止します。
= 他の接続を待ちます (>>3)。
= [[プロキシ]]を使うかどうかを決定します。[[ホスト]]、[[ポート]]、[[資源名]]、[[「保安」]]フラグを使います。
= [[プロキシ]]を使う場合は、
== 当該[[ホスト]]、[[ポート]]への [[TCP接続]]を開くよう[[プロキシ]]に接続して要求する[['''べき''']]です。
= そうでない場合は、
== 当該[[ホスト]]、[[ポート]]への [[TCP接続]]を開く[['''べきです''']]。
= [[TCP接続]]を開くのに失敗したり、[[プロキシ]]がエラーを返したりした時は、
[[WebSocket接続失敗]]を実行し、停止します。
= [[「保安」]]フラグが設定されていれば、
== [[RFC 2818]] [[HTTPS]] の方法で [[TLS handshake]] を行います。[[SNI]] を使います。
== 失敗したら、[[WebSocket接続失敗]]を実行し、停止します。
= [[RFC 2616]] [[HTTP要求]]を送信します。 (なお、バッファリングなどで遅延しても構いません [SRC[>>15]]。)
[FIG(list members)[
[FIGCAPTION[
[[HTTP要求]]
]FIGCAPTION]
:[[要求メソッド]]:[CODE(HTTP)@en[[[GET]]]]
:[[要求対象]]:[[資源名]]、または[[ホスト]]、[[ポート]]、[[資源名]]を使った [CODE(URI)@en[[[http:]]]]/[CODE(URI)@en[[[https:]]]] [[URL]] のいずれか
:[[プロトコルの版]]:[[HTTP/1.1]] [[以上]]
:[CODE(HTTP)@en[[[Host]]]]:[[ホスト]]と、[[既定のポート番号]]で無い場合、
[CODE(HTTP)[[[:]]]] と[[ポート]]
:[CODE(HTTP)@en[[[Upgrade]]]]:[CODE(HTTP)@en[[[websocket]]]]
:[CODE(HTTP)@en[[[Connection]]]]:[CODE(HTTP)@en[[[Upgrade]]]]
:[CODE(HTTP)@en[[[Sec-WebSocket-Key]]]]:[[接続]]毎に[[無作為]]に選択した
16バイトの [[nonce]] を [[RFC 4648]] [[Base64]] 符号化したもの
:[CODE(HTTP)@en[[[Origin]]]]:([[起源]]の指定がある場合のみ) [[起源]]の[[ASCII直列化]]
:[CODE(HTTP)@en[[[Sec-WebSocket-Version]]]]:[CODE(HTTP)[[[13]]]]
:[CODE(HTTP)@en[[[Sec-WebSocket-Protocol]]]]:(部分プロトコル群の指定がある場合のみ)
1つ[[以上]]の[[部分プロトコル]]の[[リスト (HTTP)]] ([CODE(HTTP)[#]])。
:[CODE(HTTP)@en[[[Sec-WebSocket-Extensions]]]]:(拡張の指定がある場合のみ)
プロトコル拡張の指定。
:その他:[[HTTP認証]]その他の[[HTTPヘッダー]]を含めて構いません。
[CODE(HTTP)@en[[[Accept-Language:]]]] [[ヘッダー]]を含めるべきです [SRC[>>114]]。
[[適切なクッキーを送るヘッダー群]]を (あれば) 含めなければなりません [SRC[仕様無し]]。
]FIG]
= [[応答]]を待ちます。
= [[応答]]の[[状態符号]]が [CODE(HTTP)[[[101]]]] 以外なら、
[[WebSocket接続失敗]]を実行し、停止します [SRC[>>60]]。
= [[応答]]を検査し、次のいずれかの条件を満たすなら、
[[WebSocket接続失敗]]を実行し、停止します。
[FIG(list)[
- [31] [CODE(HTTP)@en[[[Upgrade:]]]] [[ヘッダー]]が無いか、
[CODE(HTTP)@en[[[websocket]]]] ([[ASCII大文字・小文字不区別]]) が含まれていない場合
- [32] [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]が無いか、
[CODE(HTTP)@en[[[Upgrade]]]] ([[ASCII大文字・小文字不区別]]) が含まれていない場合
- [33] [CODE(HTTP)@en[[[Sec-WebSocket-Accept:]]]] [[ヘッダー]]が無いか、
値が[[要求]]の [CODE(HTTP)@en[[[Sec-WebSocket-Key]]]] の値に
[DFN[[CODE[[[258EAFA5-E914-47DA-95CA-C5AB0DC85B11]]]]]]
を連結した値の [[SHA-1]] を [[Base64]] 符号化したものでない場合
(前後に[[空白]]があっても構いません。)、
- [34] [CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]]
[[ヘッダー]]が構文的に正しくない場合や、[[要求]]で指定しなかった拡張が指定されている場合
- [35] [CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]]
[[ヘッダー]]が構文的に正しくない場合や、
[[要求]]で指定しなかった[[部分プロトコル]]が指定されている場合
]FIG]
= [[WebSocket接続]]の状態を、 [CODE[[[OPEN]]]] に設定します。
= [DFN[[RUBYB[利用中拡張群]@en[Extensions In Use]]]]を、[[応答]]の
[CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]] [[ヘッダー]]の値
(なければ [[null]]) に設定します。
= [DFN[[RUBYB[利用中部分プロトコル]@en[Subprotocol In Use]]]]を、[[応答]]の
[CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]] [[ヘッダー]]の値
(なければ [[null]]) に設定します。
= [[応答]]の [CODE(HTTP)@en[[[Set-Cookie:]]]] [[ヘッダー]]で[[クッキー]]の設定が指示されていれば、
これを[DFN[[[Cookies Set During the Server's Opening Handshake]]]]とします。
= [DFN[[RUBYB[WebSocket接続確立]@en[The WebSocket Connection is Established]]]]とします。
= [86] [[[CODE(DOMi)@en[WebSocket]]コンストラクター]]から本処理が始まった場合、
[[タスク]]を追加します [SRC[>>77]]。
[FIG(list members)[
[FIGCAPTION[
[[タスク]]
]FIGCAPTION]
:[[タスク源]]:[[WebSocketタスク源]]
:処理:
[FIG(steps)[
= [[クライアント指定プロトコル群]]が空のリストではなく、
[[利用中部分プロトコル]]が [[null]] なら、
== [[WebSocket接続失敗]]を実行します。
== [CODE(DOMa)@en[[[readyState]]]] を、 [CODE(DOM)@en[[[CLOSING]]]] ([CODE(DOM)[[[2]]]])
に設定します。
== 停止します。
= [CODE(DOMa)@en[[[readyState]]]] を、 [DFN[[CODE(DOM)@en[[[OPEN]]]]]] ([CODE(DOM)[[[1]]]])
に設定します。
= [[利用中拡張群]]が [[null]] でなければ、
== [CODE(DOMa)@en[[[extensions]]]] を、[[利用中拡張群]]に設定します。
= [[利用中プロトコル]]が [[null]] でなければ、
== [CODE(DOMa)@en[[[protocol]]]] を、[[利用中プロトコル]]に設定します。
= [[Cookies Set During the Server's Opening Handshake]] があれば、
[CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]の [CODE(DOMa)@en[[[url]]]] について、
これを [[set-cookie-string]] として受信したものとして処理します。
= [[単純イベントを発火]]します。
[FIG(list members)[
[FIGCAPTION[
[[単純イベント]]
]FIGCAPTION]
:[[イベント型]]:[CODE(DOMe)@en[[[open]]]]
:[[イベント対象]]:[CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]
]FIG]
]FIG]
]FIG]
= [89] 以後受信データは[[WebSocketメッセージ受信]]の処理を行います。
]FIG]
[64] 入力が [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]] として正しくなければ失敗となります。
[[HTML Standard]] は [[URL Standard]] に基づき[[正準化]]した値を使っており、
[[RFC]] は [[RFC 3986]] [[URI]] を参照して規定しているため、両者には違いが生じる可能性があります。
[[正準化]]が失敗しなかったということは、[[ホスト]]や[[ポート]]は [[RFC 3986]]
[[URI]] としても適切な値になっているはずです。[[資源名]]は、 [[RFC 3986]]
では認められない壊れた[[パーセント符号化]]もどきが含まれる可能性が残ります。
実装がこれをどう扱うのかは不明です。
[3] 他の接続を待つ場合は、次のようにしなければ[['''なりません''']] [SRC[>>1]]。
[FIG(steps)[
= [[ホスト]]から、 [[IPアドレス]]を得ます ([[名前解決]])。
= [[ホスト]]から[[IPアドレス]]を得られない場合 (例えば[[名前解決]]を[[プロキシ]]に委ねている場合)、
== [VAR[host]] を、[[ホスト]]に設定します。
== [VAR[n]] を、十分小さな値とする[['''べきです''']]。例えば開いている[[タブ]]数を考慮して決めます。
= それ以外の場合、
== [VAR[host]] を、[[IPアドレス]]に設定します。
== [VAR[n]] を、1 に設定します。
= 同じ [VAR[host]] と[[ポート]]への状態が [CODE[[[CONNECTING]]]]
である[[WebSocket接続]]があるか調べます。
= その数が [VAR[n]] [[未満]]となるまで、待ちます。
]FIG]
;; [4] この制限は、[[著者]]が多数の [[WebSocket接続]]を開いて [[DoS攻撃]]することを難しくするためのものです
[SRC[>>1]]。
;; [57] [[ホスト]]のみで制限する実装と[[ホスト]]と[[ポート]]の組で制限する実装があります
[SRC[>>56]]。
;; [29] これをうまく使うとある[[ホスト]]とある[[ホスト]]が同じ [[IPアドレス]]かどうかをある程度の精度で推測できるかもしれませんが、
それによって何か問題になることはあまり無さそうです。
[6] [[プロキシ自動設定スクリプト]]に渡す [[URL]] は、
[[ホスト]]、[[ポート]]、[[資源名]]、[[「保安」]]フラグ ([CODE(URI)@en[[[ws:]]]] or [CODE(URI)@en[[[wss:]]]])
から構築します [SRC[>>1]]。
[5] [[WebSocket]] 用の[[プロキシ]]の設定を設けていない場合は、
[[SOCKS5]]、[[HTTPS]] 用、[[HTTP]] 用の優先順で[[プロキシ]]を選択することが[RUBYB[推奨]@en[encourage]]されています [SRC[>>1]]。
[9] [[TLS]] を使う場合 [[SNI]] が必須とされていますが、[[ホスト]]が [[IPアドレス]]で指定された時どうしなければならないのかは不明です。
;; [111] [[TLS]] の場合については [[HTTPS]] も参照。
@@ [[TLSクライアント認証]]
[14] [[要求対象]]は、直接接続なら[[資源名]]のみ、 [[プロキシ]]接続なら
[[HTTP]] [[URL]] と思われますが、明記されていません。どちらでも良いということでしょうか
(それは一般的な慣習とは異なります)。また [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]]
がそれぞれ [CODE(URI)@en[[[http:]]]]/[CODE(URI)@en[[[https:]]]] に変換されるものと思われますが、
明記されていません。
[58] [[要求ヘッダー]]には [CODE(HTTP)@en[[[User-Agent:]]]] [SRC[[[Chrome]], [[Firefox]]]] や
[CODE(HTTP)@en[[[Referer:]]]] や [CODE(HTTP)@en[[[DNT:]]]] [SRC[[[Chrome]], [[Firefox]]]] や
[CODE(HTTP)@en[[[Accept-Encoding:]]]] [SRC[[[Chrome]], [[Firefox]]]] や
[CODE(HTTP)@en[[[Accept:]]]] [SRC[[[Firefox]]]] も含まれるかもしれません。
;; [109] がこれを明確に規定した仕様書はありません。 [CODE(HTTP)@en[[[Referer:]]]] は、
[[Referrer Policy]] の適用対象となるかもしれません。
[117] [[Chrome]] は仕様通り [CODE(HTTP)@en[[[Connection:]] [[Upgrade]]]]
ですが、 [[Firefox]] は [CODE(HTTP)@en[[[Connection:]] [[keep-alive]], [[Upgrade]]]]
です。 [TIME[2015-08-08T13:34:03.400Z]]
;; [110] [[ヘッダー]]によっては、またどの[[ヘッダー]]を送信するかは、
[[fingerprinting vector]] です。
[118] [[応答]]の[[プロトコルの版]]の検査は求められていないようです。
;; [119] [[Firefox]] も [[Chrome]] も、 [[HTTP/1.0]] でも [[HTTP/1.1]]
でもかわらず続行します。 [TIME[2015-08-11T12:54:08.600Z]]
[65] [[RFC]] では、[CODE(HTTP)[[[101]]]] 以外の[[状態符号]]の[[応答]]を受信した時、
[[HTTP]] に従い処理することになっています。例えば [CODE(HTTP)[[[401]]]]
なら[[HTTP認証]]の処理を行えますし、 [CODE(HTTP)[[[3xx]]]] なら
[[HTTPリダイレクト]]しても良いことになっています。 [SRC[>>1]]
しかし、 [[HTML Standard]] は [[WebSocket接続失敗]]として処理しなければ[['''ならない''']]と規定しています [SRC[>>60]]。
[66] これは、[[サーバー]]が[[リダイレクト]]することで、[[スクリプト]]が意図しない相手と接続してしまうため危険であるのが理由 [SRC[>>60]] とされています。
理論上は [CODE(DOMi)@en[[[WebSocket]]]] 以外の [[WebSocketクライアント]]はこの規定に従う義務はありませんが、
敢えて危険をおかして [[Webブラウザー]]と異なる動作を採る必要性も無さそうです。
;; [67] [[HTTP認証]]はそのような危険性は無さそうですが...
[115] [[Chrome]] は、 [CODE(HTTP)[[[401]]]] が返されたら、適切な [[credentials]]
を持っていなければエラーとして扱います。 [[Firefox]] は、通常の
[[HTTP認証]]の[[モーダルダイアログ]]を表示します。
[[Firefox]] は[[HTTP接続]]を再利用可能なら、再利用して再試行するようです。 [TIME[2015-08-04T13:33:15.200Z]]
@@ 407
[122] [[Firefox]] も [[Chrome]] も、 [CODE(HTTP)[[[1xx]]]] ([CODE(HTTP)[[[101]]]] 以外)
をエラーとして扱います。 [TIME[2015-08-17T08:38:07.400Z]]
[124] [[Chrome]] は[[ヘッダー]]を読み終わったところでエラーなら切断するようですが、
[[Firefox]] はそうでもないようで、しばらく (ずっとではない) 切断されません。 [TIME[2015-08-23T05:48:04.100Z]]
[68] [CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]は、
内部状態として[DFN[[RUBYB[クライアント指定プロトコル群]@en[client-specified protocols]]]]を持ちます。
[54] 受信したデータが理解できない、想定外であるなどの理由があれば、
いつでも[[TCP接続]]を閉じることができます [SRC[>>53]]。
[116] [[Chrome]] は [CODE(HTTP)@en[[[Content-Length:]]]] [[ヘッダー]]について、
通常の[[HTTP応答]]同様の検査を行うようです。 [TIME[2015-08-04T13:46:51.00Z]]
[120] [[応答]]の [CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]] の値の検査を
[[Chrome]] は行いますが、 [[Firefox]] は行わないようです。
なお [[Chrome]] は ([[RFC]] と異なり) 値を[[リスト]] ([CODE[#]])
として構文解析するようです。 [TIME[2015-08-15T14:15:24.600Z]]
[121] [[応答]]の [CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]] の値が[[空文字列]]の時、
[[Firefox]] はエラーにせず、 [[Chrome]] はエラーにします。値が [CODE[,]]
だけの時 (空のリストだが空文字列でない時)、 [[Firefox]] はエラーにし、
[[Chrome]] はエラーにしません。 [[RFC]] に従うならどちらもエラーになるべきです。 [TIME[2015-08-15T14:25:48.600Z]]
[123] [[Chrome]] は接続成功時と [CODE(HTTP)[[[401]]]] 時に [CODE(HTTP)@en[[[Set-Cookie:]]]]
を処理するようです。 [[Firefox]] は接続が成功か否かや[[状態符号]]に関わらず、
[CODE(HTTP)@en[[[Set-Cookie:]]]] を処理するようです。 [TIME[2015-08-17T08:46:08.900Z]]
[90] [[WebSocket]] の規定に従わない[[サーバー]]は、[[クライアント]]からの要求を待たずに[[応答]]
(や[[応答]]になっていないデータ) を送信するかもしれません。[[クライアント]]はそれに特別な対処を行う必要はありませんが、 >>54 を根拠に切断しても良いのかもしれません。
* サーバーの動作
[30] [[サーバー]]は、 [[TCP]] ないし [[TLS]] over [[TCP]] で[[ホスト]]と[[ポート]]の組を
[[listen]] していることが期待されています。
[16] [[サーバー]]は、[[クライアント]]との[[TCP接続]]が確立されたら、
次のようにしなければ[['''なりません''']]。
[FIG(steps)[
= [19] [[TLS]] を使う場合、[[TLS handshake]] を行います [SRC[>>1]]。
[[TLSクライアント認証]]を使っても構いません [SRC[>>51]]。
失敗なら、[[接続]]を閉じ、停止します [SRC[>>1]]。
= [18] [[要求]]を受信したら、
その一部または全部を構文解析して、必要な情報を取得します。
次のような問題があれば:
[FIG(list)[
- [36] [[プロトコルの版]]が [[HTTP/1.1]] [[以上]]でない場合
- [37] [[要求メソッド]]が [CODE(HTTP)@en[[[GET]]]] でない場合
- [38] [[要求対象]]が[[資源名]]か、[[資源名]]を含む [CODE(URI)@en[[[http:]]]]/[CODE(URI)@en[[[https:]]]] の[[絶対URL]]でない場合
(構文的に正しくない場合を含む。)
- [39] [CODE(HTTP)@en[[[Host:]]]] が無いか、構文的に正しくないか、
[[サーバー]]の [[authority]] でない場合
- [40] [CODE(HTTP)@en[[[Upgrade:]]]] が無いか、 [CODE(HTTP)@en[[[websocket]]]]
([[ASCII大文字・小文字不区別]]) を含まない場合
- [41] [CODE(HTTP)@en[[[Connection:]]]] が無いか、 [CODE(HTTP)@en[[[Upgrade]]]]
([[ASCII大文字・小文字不区別]]) を含まない場合
- [42] [CODE(HTTP)@en[[[Sec-WebSocket-Key:]]]] が無いか、
16バイトの値を [[Base64]] 符号化したもので無い場合
- [43] [CODE(HTTP)@en[[[Sec-WebSocket-Version:]]]] が無いか、
[CODE(HTTP)[[[13]]]] で無い場合
- [44] [CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]] や
[CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]]
がある場合で、構文的に正しくない場合
- [45] その他[[クッキー]]や[[HTTP認証]]などの既知の[[ヘッダー]]で構文などが正しくないものがある場合
]FIG]
== [98] エラーを表す [CODE(HTTP)[[[400]]]] [[応答]]など適切な[[HTTP応答]]を返します。 [SRC[>>1]]
== [99] [[Abort the WebSocket Connection]] します。
== [103] 停止します。
= [20] 必要に応じて、
== [100] [CODE(HTTP)@en[[[WWW-Authenticate:]]]] [[ヘッダー]]を検査して
[CODE(HTTP)@en[[[401]]]] [[応答]]を返したり、
[[クッキー認証]]など適切な[[認証]]を行い [SRC[>>51]] 適切なエラーの[[応答]]を返したり、
[CODE(HTTP)[[[3xx]]]] [[応答]]で[[HTTPリダイレクト]]したりします。 [SRC[>>1]]
== [102] [[Abort the WebSocket Connection]] します。
== [104] 停止します。
= [21] [CODE(HTTP)[[[Origin:]]]] [[ヘッダー]]を検査して不適切なら、
== [95] [CODE(HTTP)[[[403]]]] [[応答]]など適切な[[応答]]を返します [SRC[>>1, >>50]]。
== [96] [[Abort the WebSocket Connection]] します。
== [105] 停止します [SRC[>>1]]。
= [22] [CODE(HTTP)@en[[[Sec-WebSocket-Version:]]]] [[ヘッダー]]の値が
[CODE[[[13]]]] でなければ、
== [91] [CODE(HTTP)[[[426]]]] [[応答]]など適切な[[応答]]を返します。
[CODE(HTTP)@en[[[Sec-WebSocket-Version:]]]] に対応する版番号を指定します。 [SRC[>>1]]
== [92] [[Abort the WebSocket Connection]] します。
== [52] 停止します [SRC[>>1]]。
= [23] [[要求対象]]から得た[[資源名]]で示されるものが利用できないなら、
== [93] [CODE(HTTP)[[[404]]]] [[応答]]など適切な[[応答]]を返します。[SRC[>>1]]
== [94] [[Abort the WebSocket Connection]] します。
== [106] 停止します [SRC[>>1]]。
= [24] [CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]] [[ヘッダー]]の値から得られた[[部分プロトコル]]群から、
[[サーバー]]が承認するもののみのリストを得ます。該当するものがなければ、 [[null]] とします。 [SRC[>>1]]
= [25] [CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]] [[ヘッダー]]の値から得られたプロトコル拡張群から、
[[サーバー]]が承認するもののみのリストを得ます。該当するものがなければ、 [[null]] とします。 [SRC[>>1]]
= [26] [[HTTP応答]]を送ります。 [SRC[>>1]]
[FIG(list members)[
[FIGCAPTION[
[[HTTP応答]]
]FIGCAPTION]
:[[状態符号]]:[CODE(HTTP)[[[101]]]]。
:[CODE(HTTP)@en[[[Upgrade]]]]:[CODE(HTTP)@en[[[websocket]]]]。
:[CODE(HTTP)@en[[[Connection]]]]:[CODE(HTTP)@en[[[Upgrade]]]]。
:[CODE(HTTP)@en[[[Sec-WebSocket-Accept]]]]:
[[要求]]の [CODE(HTTP)@en[[[Sec-WebSocket-Key:]]]] の値に
[CODE(HTTP)@en[[[258EAFA5-E914-47DA-95CA-C5AB0DC85B11]]]] を連結し、
[[SHA-1]] を計算し、[[RFC 4648]] [[Base64]] 符号化したもの。
:[CODE(HTTP)@en[[[Sec-WebSocket-Protocol]]]]:>>24 で得られた[[部分プロトコル]]の[[リスト (HTTP)]] ([CODE(HTTP)[#]]) ([[null]] でない場合のみ)。
:[CODE(HTTP)@en[[[Sec-WebSocket-Extensions]]]]:>>25 で得られたプロトコル拡張 ([[null]] でない場合のみ)。
[[引数]]は、[[拡張]]の規定に従い適切に決定します [SRC[>>49]]。
(複数の本[[ヘッダー]]があっても構いません。)
]FIG]
= [27] [[WebSocket接続]]の状態を [CODE(HTTP)[[[OPEN]]]] とします。 [SRC[>>1]]
= [88] 以後受信データは[[WebSocketメッセージ受信]]の処理を行います。
]FIG]
;; [97] サーバーのエラー処理について [[RFC]] は明確に記述していませんが、
他の部分の記述から、 [[Abort the WebSocket Connection]] を呼び出すことが想定されているようです。
;; [107] [CODE(HTTP)@en[[[Host:]]]] と[[要求対象]]の衝突時の処理を [[RFC]]
は明記していませんが、後の [[RFC 723x]] による [[HTTP]] における処理
([[要求対象]]参照。) に従うべきと思われます。
[17] [CODE(HTTP)@en[[[Origin:]]]] [[ヘッダー]]が無ければ、
[[Webブラウザー]]からの[[要求]]と解釈する[['''べきではありません''']] [SRC[>>1]]。
[59] なお [[Webブラウザー]]以外の[[クライアント]]は、好きな [CODE(HTTP)@en[[[Origin:]]]]
を送ることができます。[[クライアント]]が [[Webブラウザー]]であることを判定する方法はありません
([[Webブラウザー]]でないことは >>17 の通り判定できますが)。
[CODE(HTTP)@en[[[Origin:]]]] は [[Webブラウザー]]上で適切なアクセス元からの接続かどうかを判断するために使うことができますが、
非 [[Webブラウザー]]に対する[[認証]]のような仕組みとして用いることはできません。
[28] 状態が [CODE(HTTP)[[[OPEN]]]] となると、データを送受信できます [SRC[>>1]]。
[7] この手順の途中で停止する時は、[[WebSocket接続を閉じる]]ものと思われます。
[55] 受信したデータが理解できない、想定外であるなどの理由があれば、
いつでも[[TCP接続]]を閉じることができます [SRC[>>53]]。
不正なデータを受信した時は、適切な [[HTTP応答]]を送信する[['''べきです''']] [SRC[>>53]]。
[48] この手順を完走したら、[[WebSocket接続確立]]となるものと思われます。
;; [112] [[TLS]] の場合については [[HTTPS]] も参照。
* [CODE(DOMi)@en[WebSocket]] インターフェイス [CODE(DOMa)@en[url]] 属性
[70] [CODE(DOMi)@en[[[WebSocket]]]] [[インターフェイス]]の
[DFN[[CODE(DOMa)@en[[[url]]]]]] [[IDL属性]]は、
[[構築]]時に設定された値を返さなければ[['''なりません''']] [SRC[>>69]]。
この値は常に [CODE(URI)@en[[[ws:]]]] または [CODE(URI)@en[[[wss:]]]]
の[[絶対URL]]です。
[74] この[[IDL属性]]の[[データ型]]は、 [CODE(IDL)@en[[[DOMString]]]] です [SRC[>>69]]。
* 歴史
[REFS[
- [449] [CITE@en[664284 – Add HSTS support for websockets]]
( ([TIME[2014-12-11 11:50:38 +09:00]] 版))
<https://bugzilla.mozilla.org/show_bug.cgi?id=664284>
- [450] [CITE@en[''''''[''''''chrome'''''']'''''' Revision 82069]]
( ([TIME[2014-12-11 11:51:03 +09:00]] 版))
<http://src.chromium.org/viewvc/chrome?revision=82069&view=revision>
- [451] [CITE@en[Bug 27554 – After the WebSocket object is returned we should probably integrate with HSTS. For Fetch that happen ''''''[''''''...'''''']'''''']]
( ([TIME[2014-12-11 11:51:13 +09:00]] 版))
<https://www.w3.org/Bugs/Public/show_bug.cgi?id=27554>
]REFS]
[114] [CITE[Issue 174956 - chromium - Websocket request does not send Accept-Language header - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-04-24 20:08:54 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=174956>
[129] [CITE@en[Apply HSTS to WebSocket · whatwg/html@8b46c20]]
([TIME[2015-09-19 13:23:28 +09:00]] 版)
<https://github.com/whatwg/html/commit/8b46c205cc2b54bb4d57bd7ad12baf9492e40edd>
[130] [CITE@en[Apply HSTS to WebSocket · whatwg/html@8b46c20]]
([TIME[2015-09-19 13:24:20 +09:00]] 版)
<https://github.com/whatwg/html/commit/8b46c205cc2b54bb4d57bd7ad12baf9492e40edd>