/
314.txt
173 lines (157 loc) · 11.1 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
* 仕様書
[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>'''
]REFS]
* クライアントの動作
[2] [[クライアント]]は、[DFN[[RUBYB[WebSocket接続の確立]@en[Establish a WebSocket Connection]]]]で、
次のようにしなければ[['''なりません''']] [SRC[>>1]]。
[8] この手順は、入力として次のものを受け取ります。
[FIG(list members)[
:[[URL]]:接続先の[[資源]]を表します。必須です。
:[[起源]]:
[10] [[Webブラウザー]]は、[[起源]]を指定しなければ[['''なりません''']]。
これは接続を開いた元を表すものです。
それ以外の[[クライアント]]は、[[起源]]を指定しても構いません。 [SRC[>>1]]
:[[部分プロトコル]]群:
[11] [[クライアント]]が通信したい[[部分プロトコル]]を優先順に指定するものです。
各[[部分プロトコル]]は、 [CODE[[[,]]]] や [CODE(charname)@en[[[SPACE]]]]
を除く[[ASCII印字可能文字]]の1文字以上の列で表さなければ[['''なりません''']]。
同じ[[部分プロトコル]]を複数指定しては[['''なりません''']]。 [SRC[>>1]]
:プロトコル拡張:
[12] [[クライアント]]が利用したいプロトコル拡張を指定するものです [SRC[>>1]]。
]FIG]
[7] この手順は、
[DFN[[RUBYB[WebSocket接続確立]@en[The WebSocket Connection is Established]]]]か
[DFN[[RUBYB[WebSocket接続失敗]@en[Fail the WebSocket Connection]]]]か [SRC[>>1]]
を返します。
接続が確立された場合は、 [[WebSocket接続]]も得られます。
[FIG(steps)[
= 入力として与えられた [[URL]] を [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]] [[URL]]
として解釈し、[[ホスト]]、[[ポート]]、[[資源名]]、[[「保安」]]フラグを得ます。
= 前項が失敗したら、[[WebSocket接続失敗]]を返し、停止します。
= 新しい [[WebSocket接続]]を作成します。
= [[WebSocket接続]]の状態を、 [CODE[[[CONNECTING]]]] に設定します。
= 他の接続を待ちます (>>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ヘッダー]]を含めて構いません。
]FIG]
= [[応答]]を待ちます。
= [[応答]]の[[状態符号]]が [CODE(HTTP)[[[101]]]] 以外なら、
== [[HTTP]] に従い処理します。例えば [CODE(HTTP)[[[401]]]] なら[[HTTP認証]]したり、
[CODE(HTTP)[[[3xx]]]] なら[[HTTPリダイレクト]]したりできます。
== ここで停止します。
= [[応答]]の [CODE(HTTP)@en[[[Upgrade:]]]] [[ヘッダー]]が無いか、
[CODE(HTTP)@en[[[websocket]]]] ([[ASCII大文字・小文字不区別]]) が含まれていないなら、
[[WebSocket接続失敗]]を返し、停止します。
= [[応答]]の [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]が無いか、
[CODE(HTTP)@en[[[Upgrade]]]] ([[ASCII大文字・小文字不区別]]) が含まれていないなら、
[[WebSocket接続失敗]]を返し、停止します。
= [[応答]]の [CODE(HTTP)@en[[[Sec-WebSocket-Accept:]]]] [[ヘッダー]]が無いか、
値が[[要求]]の [CODE(HTTP)@en[[[Sec-WebSocket-Key]]]] の値に
[DFN[[CODE[[[258EAFA5-E914-47DA-95CA-C5AB0DC85B11]]]]]]
を連結した値の [[SHA-1]] を [[Base64]] 符号化したものでなければ
(前後に[[空白]]があっても構いません。)、
[[WebSocket接続失敗]]を返し、停止します。
= [[応答]]の [CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]]
[[ヘッダー]]に[[要求]]で指定しなかった拡張が指定されていれば、
[[WebSocket接続失敗]]を返し、停止します。
= [[応答]]の [CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]]
[[ヘッダー]]に[[要求]]で指定しなかった[[部分プロトコル]]が指定されていれば、
[[WebSocket接続失敗]]を返し、停止します。
=
@@ 仕様書 4.2.2 の要件を満たさなければ、
[[WebSocket接続失敗]]を返し、停止します。
= [[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]]]]とします。
= [[WebSocket接続確立]]を返します。
]FIG]
[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]]。
[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アドレス]]で指定された時どうしなければならないのかは不明です。
[14] [[要求対象]]は、直接接続なら[[資源名]]のみ、 [[プロキシ]]接続なら
[[HTTP]] [[URL]] と思われますが、明記されていません。どちらでも良いということでしょうか
(それは一般的な慣習とは異なります)。また [CODE(URI)@en[[[ws:]]]]/[CODE(URI)@en[[[wss:]]]]
がそれぞれ [CODE(URI)@en[[[http:]]]]/[CODE(URI)@en[[[https:]]]] に変換されるものと思われますが、
明記されていません。
* サーバーの動作
[16] [[サーバー]]は、[[クライアント]]から[[要求]]を受信したら、
その一部または全部を構文解析して、必要な情報を取得しなければなりません。
次のような問題があれば、エラーを表す [CODE(HTTP)[[[400]]]] [[応答]]など適切な
[[HTTP応答]]を返し、停止しなければ[['''なりません''']]。 [SRC[>>1]]
[FIG(list)[
- [[プロトコルの版]]が [[HTTP/1.1]] [[以上]]でない場合
- [[要求メソッド]]が [CODE(HTTP)@en[[[GET]]]] でない場合
- [[要求対象]]が[[資源名]]か、[[資源名]]を含む [CODE(URI)@en[[[http:]]]]/[CODE(URI)@en[[[https:]]]] の[[絶対URL]]でない場合
(構文的に正しくない場合を含む。)
- [CODE(HTTP)@en[[[Host:]]]] が[[サーバー]]の [[authority]] でない場合
(構文的に正しくない場合を含む。)
- [CODE(HTTP)@en[[[Upgrade:]]]] が [CODE(HTTP)@en[[[websocket]]]]
[[ASCII大文字・小文字不区別]]) を含まない場合
- [CODE(HTTP)@en[[[Connection:]]]] が [CODE(HTTP)@en[[[Upgrade]]]]
[[ASCII大文字・小文字不区別]]) を含まない場合
- [CODE(HTTP)@en[[[Sec-WebSocket-Key:]]]] が無いか、
16バイトの値を [[Base64]] 符号化したもので無い場合
- [CODE(HTTP)@en[[[Sec-WebSocket-Version:]]]] が無いか、
[CODE(HTTP)[[[13]]]] で無い場合
- [CODE(HTTP)@en[[[Sec-WebSocket-Protocol:]]]] や
[CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]]
がある場合で、構文的に正しくない場合
- その他[[クッキー]]や[[HTTP認証]]などの既知の[[ヘッダー]]で構文などが正しくないものがある場合
]FIG]
[17] [CODE(HTTP)@en[[[Origin:]]]] [[ヘッダー]]が無ければ、
[[Webブラウザー]]からの[[要求]]と解釈する[['''べきではありません''']] [SRC[>>1]]。