OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 /** | 7 /** |
8 * WebSocket status codes used when closing a WebSocket connection. | 8 * WebSocket status codes used when closing a WebSocket connection. |
9 */ | 9 */ |
10 abstract class WebSocketStatus { | 10 abstract class WebSocketStatus { |
11 static const int NORMAL_CLOSURE = 1000; | 11 static const int NORMAL_CLOSURE = 1000; |
12 static const int GOING_AWAY = 1001; | 12 static const int GOING_AWAY = 1001; |
13 static const int PROTOCOL_ERROR = 1002; | 13 static const int PROTOCOL_ERROR = 1002; |
14 static const int UNSUPPORTED_DATA = 1003; | 14 static const int UNSUPPORTED_DATA = 1003; |
15 static const int RESERVED_1004 = 1004; | 15 static const int RESERVED_1004 = 1004; |
16 static const int NO_STATUS_RECEIVED = 1005; | 16 static const int NO_STATUS_RECEIVED = 1005; |
17 static const int ABNORMAL_CLOSURE = 1006; | 17 static const int ABNORMAL_CLOSURE = 1006; |
18 static const int INVALID_FRAME_PAYLOAD_DATA = 1007; | 18 static const int INVALID_FRAME_PAYLOAD_DATA = 1007; |
19 static const int POLICY_VIOLATION = 1008; | 19 static const int POLICY_VIOLATION = 1008; |
20 static const int MESSAGE_TOO_BIG = 1009; | 20 static const int MESSAGE_TOO_BIG = 1009; |
21 static const int MISSING_MANDATORY_EXTENSION = 1010; | 21 static const int MISSING_MANDATORY_EXTENSION = 1010; |
22 static const int INTERNAL_SERVER_ERROR = 1011; | 22 static const int INTERNAL_SERVER_ERROR = 1011; |
23 static const int RESERVED_1015 = 1015; | 23 static const int RESERVED_1015 = 1015; |
24 } | 24 } |
25 | 25 |
26 /** | 26 /** |
27 * The [CompressionOptions] class allows you to control | 27 * The [CompressionOptions] class allows you to control |
28 * the options of WebSocket compression. | 28 * the options of WebSocket compression. |
29 */ | 29 */ |
30 class CompressionOptions { | 30 class CompressionOptions { |
31 /** | 31 /** |
32 * Default WebSocket Compression options. | 32 * Default WebSocket Compression options. |
33 * Compression will be enabled with the following options: | 33 * Compression will be enabled with the following options: |
34 * clientNoContextTakeover: false | 34 * clientNoContextTakeover: false |
35 * serverNoContextTakeover: false | 35 * serverNoContextTakeover: false |
36 * clientMaxWindowBits: 15 | 36 * clientMaxWindowBits: 15 |
37 * serverMaxWindowBits: 15 | 37 * serverMaxWindowBits: 15 |
38 */ | 38 */ |
39 static const CompressionOptions DEFAULT = const CompressionOptions(); | 39 static const CompressionOptions DEFAULT = const CompressionOptions(); |
40 | 40 |
41 /** | 41 /** |
42 * Disables WebSocket Compression. | 42 * Disables WebSocket Compression. |
43 */ | 43 */ |
44 static const CompressionOptions OFF = const CompressionOptions(enabled: false) ; | 44 static const CompressionOptions OFF = |
45 const CompressionOptions(enabled: false); | |
45 | 46 |
46 /** | 47 /** |
47 * Control whether the client will reuse it's compression instances. | 48 * Control whether the client will reuse it's compression instances. |
48 */ | 49 */ |
49 final bool clientNoContextTakeover; | 50 final bool clientNoContextTakeover; |
50 | 51 |
51 /** | 52 /** |
52 * Control whether the server will reuse it's compression instances. | 53 * Control whether the server will reuse it's compression instances. |
53 */ | 54 */ |
54 final bool serverNoContextTakeover; | 55 final bool serverNoContextTakeover; |
55 | 56 |
56 /** | 57 /** |
57 * Sets the Max Window Bits for the Client. | 58 * Sets the Max Window Bits for the Client. |
58 */ | 59 */ |
59 final int clientMaxWindowBits; | 60 final int clientMaxWindowBits; |
60 | 61 |
61 /** | 62 /** |
62 * Sets the Max Window Bits for the Server. | 63 * Sets the Max Window Bits for the Server. |
63 */ | 64 */ |
64 final int serverMaxWindowBits; | 65 final int serverMaxWindowBits; |
65 | 66 |
66 /** | 67 /** |
67 * Enables or disables WebSocket compression. | 68 * Enables or disables WebSocket compression. |
68 */ | 69 */ |
69 final bool enabled; | 70 final bool enabled; |
70 | 71 |
71 const CompressionOptions({this.clientNoContextTakeover: false, | 72 const CompressionOptions( |
72 this.serverNoContextTakeover: false, this.clientMaxWindowBits, | 73 {this.clientNoContextTakeover: false, |
73 this.serverMaxWindowBits, this.enabled: true}); | 74 this.serverNoContextTakeover: false, |
75 this.clientMaxWindowBits, | |
76 this.serverMaxWindowBits, | |
77 this.enabled: true}); | |
74 | 78 |
75 /** | 79 /** |
76 * Create a Compression Header | 80 * Create a Compression Header |
77 */ | 81 */ |
78 String _createHeader([List<String> requested]) { | 82 String _createHeader([List<String> requested]) { |
79 if (!enabled) { | 83 if (!enabled) { |
80 return ""; | 84 return ""; |
81 } | 85 } |
82 | 86 |
83 var header = "permessage-deflate"; | 87 var header = _WebSocketImpl.PER_MESSAGE_DEFLATE; |
84 | 88 |
85 if (requested == null) { | 89 if (requested == null) { |
86 header += "; client_max_window_bits"; | 90 header += "; client_max_window_bits"; |
87 } else { | 91 } else { |
88 if (requested.contains("client_max_window_bits")) { | 92 if (requested.contains("client_max_window_bits")) { |
89 var myMaxWindowBits = clientMaxWindowBits == null ? 15 : clientMaxWindow Bits; | 93 var myMaxWindowBits = |
94 clientMaxWindowBits == null ? _WebSocketImpl.DEFAULT_WINDOW_BITS : c lientMaxWindowBits; | |
kustermann
2015/07/20 09:34:12
long line
| |
90 header += "; client_max_window_bits=${myMaxWindowBits}"; | 95 header += "; client_max_window_bits=${myMaxWindowBits}"; |
91 } | 96 } |
92 } | 97 } |
93 | 98 |
94 if (clientNoContextTakeover && (requested != null | 99 if (clientNoContextTakeover && |
95 && requested.contains("client_no_context_takeover"))) { | 100 (requested != null && |
101 requested.contains("client_no_context_takeover"))) { | |
kustermann
2015/07/20 09:34:12
Indentation seems wrong. Would be nice if you coul
| |
96 header += "; client_no_context_takeover"; | 102 header += "; client_no_context_takeover"; |
97 } | 103 } |
98 | 104 |
99 if (serverNoContextTakeover && (requested != null | 105 if (serverNoContextTakeover && |
100 && requested.contains("server_no_context_takeover"))) { | 106 (requested != null && |
107 requested.contains("server_no_context_takeover"))) { | |
kustermann
2015/07/20 09:34:12
ditto
| |
101 header += "; server_no_context_takeover"; | 108 header += "; server_no_context_takeover"; |
102 } | 109 } |
103 | 110 |
104 if (requested != null) { | 111 if (requested != null) { |
105 var mwb = serverMaxWindowBits == null ? 15 : serverMaxWindowBits; | 112 var mwb = serverMaxWindowBits == null ? _WebSocketImpl.DEFAULT_WINDOW_BITS : serverMaxWindowBits; |
kustermann
2015/07/20 09:34:12
long line
| |
106 header += "; server_max_window_bits=${mwb}"; | 113 header += "; server_max_window_bits=${mwb}"; |
107 } | 114 } |
108 | 115 |
109 return header; | 116 return header; |
110 } | 117 } |
111 } | 118 } |
112 | 119 |
113 /** | 120 /** |
114 * The [WebSocketTransformer] provides the ability to upgrade a | 121 * The [WebSocketTransformer] provides the ability to upgrade a |
115 * [HttpRequest] to a [WebSocket] connection. It supports both | 122 * [HttpRequest] to a [WebSocket] connection. It supports both |
(...skipping 17 matching lines...) Expand all Loading... | |
133 * stream transformer that transforms a stream of HttpRequest into a | 140 * stream transformer that transforms a stream of HttpRequest into a |
134 * stream of WebSockets by upgrading each HttpRequest from the HTTP or | 141 * stream of WebSockets by upgrading each HttpRequest from the HTTP or |
135 * HTTPS server, to the WebSocket protocol. | 142 * HTTPS server, to the WebSocket protocol. |
136 * | 143 * |
137 * server.transform(new WebSocketTransformer()).listen((webSocket) => ...); | 144 * server.transform(new WebSocketTransformer()).listen((webSocket) => ...); |
138 * | 145 * |
139 * This transformer strives to implement WebSockets as specified by RFC6455. | 146 * This transformer strives to implement WebSockets as specified by RFC6455. |
140 */ | 147 */ |
141 abstract class WebSocketTransformer | 148 abstract class WebSocketTransformer |
142 implements StreamTransformer<HttpRequest, WebSocket> { | 149 implements StreamTransformer<HttpRequest, WebSocket> { |
143 | |
144 /** | 150 /** |
145 * Create a new [WebSocketTransformer]. | 151 * Create a new [WebSocketTransformer]. |
146 * | 152 * |
147 * If [protocolSelector] is provided, [protocolSelector] will be called to | 153 * If [protocolSelector] is provided, [protocolSelector] will be called to |
148 * select what protocol to use, if any were provided by the client. | 154 * select what protocol to use, if any were provided by the client. |
149 * [protocolSelector] is should return either a [String] or a [Future] | 155 * [protocolSelector] is should return either a [String] or a [Future] |
150 * completing with a [String]. The [String] must exist in the list of | 156 * completing with a [String]. The [String] must exist in the list of |
151 * protocols. | 157 * protocols. |
152 */ | 158 */ |
153 factory WebSocketTransformer({protocolSelector(List<String> protocols), | 159 factory WebSocketTransformer( |
154 CompressionOptions compression: CompressionOptions.DEFAULT}) | 160 {protocolSelector(List<String> protocols), |
155 => new _WebSocketTransformerImpl(protocolSelector, compression); | 161 CompressionOptions compression: CompressionOptions.DEFAULT}) => |
162 new _WebSocketTransformerImpl(protocolSelector, compression); | |
156 | 163 |
157 /** | 164 /** |
158 * Upgrades a [HttpRequest] to a [WebSocket] connection. If the | 165 * Upgrades a [HttpRequest] to a [WebSocket] connection. If the |
159 * request is not a valid WebSocket upgrade request an HTTP response | 166 * request is not a valid WebSocket upgrade request an HTTP response |
160 * with status code 500 will be returned. Otherwise the returned | 167 * with status code 500 will be returned. Otherwise the returned |
161 * future will complete with the [WebSocket] when the upgrade pocess | 168 * future will complete with the [WebSocket] when the upgrade pocess |
162 * is complete. | 169 * is complete. |
163 * | 170 * |
164 * If [protocolSelector] is provided, [protocolSelector] will be called to | 171 * If [protocolSelector] is provided, [protocolSelector] will be called to |
165 * select what protocol to use, if any were provided by the client. | 172 * select what protocol to use, if any were provided by the client. |
166 * [protocolSelector] is should return either a [String] or a [Future] | 173 * [protocolSelector] is should return either a [String] or a [Future] |
167 * completing with a [String]. The [String] must exist in the list of | 174 * completing with a [String]. The [String] must exist in the list of |
168 * protocols. | 175 * protocols. |
169 */ | 176 */ |
170 static Future<WebSocket> upgrade(HttpRequest request, | 177 static Future<WebSocket> upgrade(HttpRequest request, |
171 {protocolSelector(List<String> protocols), | 178 {protocolSelector(List<String> protocols), |
172 CompressionOptions compression: CompressionO ptions.DEFAULT}) { | 179 CompressionOptions compression: CompressionOptions.DEFAULT}) { |
173 return _WebSocketTransformerImpl._upgrade(request, protocolSelector, compres sion); | 180 return _WebSocketTransformerImpl._upgrade( |
181 request, protocolSelector, compression); | |
174 } | 182 } |
175 | 183 |
176 /** | 184 /** |
177 * Checks whether the request is a valid WebSocket upgrade request. | 185 * Checks whether the request is a valid WebSocket upgrade request. |
178 */ | 186 */ |
179 static bool isUpgradeRequest(HttpRequest request) { | 187 static bool isUpgradeRequest(HttpRequest request) { |
180 return _WebSocketTransformerImpl._isUpgradeRequest(request); | 188 return _WebSocketTransformerImpl._isUpgradeRequest(request); |
181 } | 189 } |
182 } | 190 } |
183 | 191 |
184 | |
185 /** | 192 /** |
186 * A two-way HTTP communication object for client or server applications. | 193 * A two-way HTTP communication object for client or server applications. |
187 * | 194 * |
188 * The stream exposes the messages received. A text message will be of type | 195 * The stream exposes the messages received. A text message will be of type |
189 * [:String:] and a binary message will be of type [:List<int>:]. | 196 * [:String:] and a binary message will be of type [:List<int>:]. |
190 */ | 197 */ |
191 abstract class WebSocket implements Stream, StreamSink { | 198 abstract class WebSocket implements Stream, StreamSink { |
192 /** | 199 /** |
193 * Possible states of the connection. | 200 * Possible states of the connection. |
194 */ | 201 */ |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
234 * - `sec-websocket-protocol` | 241 * - `sec-websocket-protocol` |
235 * - `sec-websocket-version` | 242 * - `sec-websocket-version` |
236 * - `upgrade` | 243 * - `upgrade` |
237 * | 244 * |
238 * If any of these are passed in the `headers` map they will be ignored. | 245 * If any of these are passed in the `headers` map they will be ignored. |
239 * | 246 * |
240 * If the `url` contains user information this will be passed as basic | 247 * If the `url` contains user information this will be passed as basic |
241 * authentication when setting up the connection. | 248 * authentication when setting up the connection. |
242 */ | 249 */ |
243 static Future<WebSocket> connect(String url, | 250 static Future<WebSocket> connect(String url, |
244 {Iterable<String> protocols, | 251 {Iterable<String> protocols, Map<String, dynamic> headers}) => |
245 Map<String, dynamic> headers}) => | |
246 _WebSocketImpl.connect(url, protocols, headers); | 252 _WebSocketImpl.connect(url, protocols, headers); |
247 | 253 |
248 @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`' | 254 @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`' |
249 ' instead of `extends` if implementing this abstract class.') | 255 ' instead of `extends` if implementing this abstract class.') |
250 WebSocket(); | 256 WebSocket(); |
251 | 257 |
252 /** | 258 /** |
253 * Creates a WebSocket from an already-upgraded socket. | 259 * Creates a WebSocket from an already-upgraded socket. |
254 * | 260 * |
255 * The initial WebSocket handshake must have occurred prior to this call. A | 261 * The initial WebSocket handshake must have occurred prior to this call. A |
256 * WebSocket client can automatically perform the handshake using | 262 * WebSocket client can automatically perform the handshake using |
257 * [WebSocket.connect], while a server can do so using | 263 * [WebSocket.connect], while a server can do so using |
258 * [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest], | 264 * [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest], |
259 * [HttpRequest.detachSocket] may be called. | 265 * [HttpRequest.detachSocket] may be called. |
260 * | 266 * |
261 * [protocol] should be the protocol negotiated by this handshake, if any. | 267 * [protocol] should be the protocol negotiated by this handshake, if any. |
262 * | 268 * |
263 * [serverSide] must be passed explicitly. If it's `false`, the WebSocket will | 269 * [serverSide] must be passed explicitly. If it's `false`, the WebSocket will |
264 * act as the client and mask the messages it sends. If it's `true`, it will | 270 * act as the client and mask the messages it sends. If it's `true`, it will |
265 * act as the server and will not mask its messages. | 271 * act as the server and will not mask its messages. |
266 */ | 272 */ |
267 factory WebSocket.fromUpgradedSocket(Socket socket, {String protocol, | 273 factory WebSocket.fromUpgradedSocket(Socket socket, |
268 bool serverSide, CompressionOptions compression: CompressionOptions.DEFA ULT}) { | 274 {String protocol, |
275 bool serverSide, | |
276 CompressionOptions compression: CompressionOptions.DEFAULT}) { | |
269 if (serverSide == null) { | 277 if (serverSide == null) { |
270 throw new ArgumentError("The serverSide argument must be passed " | 278 throw new ArgumentError("The serverSide argument must be passed " |
271 "explicitly to WebSocket.fromUpgradedSocket."); | 279 "explicitly to WebSocket.fromUpgradedSocket."); |
272 } | 280 } |
273 return new _WebSocketImpl._fromSocket(socket, protocol, compression, serverS ide); | 281 return new _WebSocketImpl._fromSocket( |
282 socket, protocol, compression, serverSide); | |
274 } | 283 } |
275 | 284 |
276 /** | 285 /** |
277 * Returns the current state of the connection. | 286 * Returns the current state of the connection. |
278 */ | 287 */ |
279 int get readyState; | 288 int get readyState; |
280 | 289 |
281 /** | 290 /** |
282 * The extensions property is initially the empty string. After the | 291 * The extensions property is initially the empty string. After the |
283 * WebSocket connection is established this string reflects the | 292 * WebSocket connection is established this string reflects the |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 void add(data); | 329 void add(data); |
321 | 330 |
322 /** | 331 /** |
323 * Sends data from a stream on WebSocket connection. Each data event from | 332 * Sends data from a stream on WebSocket connection. Each data event from |
324 * [stream] will be send as a single WebSocket frame. The data from [stream] | 333 * [stream] will be send as a single WebSocket frame. The data from [stream] |
325 * must be either [:String:]s, or [:List<int>:]s holding bytes. | 334 * must be either [:String:]s, or [:List<int>:]s holding bytes. |
326 */ | 335 */ |
327 Future addStream(Stream stream); | 336 Future addStream(Stream stream); |
328 } | 337 } |
329 | 338 |
330 | |
331 class WebSocketException implements IOException { | 339 class WebSocketException implements IOException { |
332 final String message; | 340 final String message; |
341 | |
333 const WebSocketException([this.message = ""]); | 342 const WebSocketException([this.message = ""]); |
343 | |
334 String toString() => "WebSocketException: $message"; | 344 String toString() => "WebSocketException: $message"; |
335 } | 345 } |
OLD | NEW |