Chromium Code Reviews| 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 = "permessage-deflate"; |
|
Søren Gjesse
2015/07/03 13:14:54
Please add constants for all these strings.
| |
| 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 ? 15 : clientMaxWindowBits; | |
|
Søren Gjesse
2015/07/03 13:14:54
Please use a constant for 15.
| |
| 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"))) { | |
| 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"))) { | |
| 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 ? 15 : serverMaxWindowBits; |
| 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 } |
| (...skipping 22 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 |