Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Side by Side Diff: sdk/lib/io/websocket.dart

Issue 1390353005: Web Socket compression - take two (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
28 * the options of WebSocket compression.
29 */
30 class CompressionOptions {
31 /**
32 * Default WebSocket Compression options.
33 * Compression will be enabled with the following options:
34 * clientNoContextTakeover: false
35 * serverNoContextTakeover: false
36 * clientMaxWindowBits: 15
37 * serverMaxWindowBits: 15
38 */
39 static const CompressionOptions DEFAULT = const CompressionOptions();
40
41 /**
42 * Disables WebSocket Compression.
43 */
44 static const CompressionOptions OFF =
45 const CompressionOptions(enabled: false);
46
47 /**
48 * Control whether the client will reuse it's compression instances.
49 */
50 final bool clientNoContextTakeover;
51
52 /**
53 * Control whether the server will reuse it's compression instances.
54 */
55 final bool serverNoContextTakeover;
56
57 /**
58 * Sets the Max Window Bits for the Client.
59 */
60 final int clientMaxWindowBits;
61
62 /**
63 * Sets the Max Window Bits for the Server.
64 */
65 final int serverMaxWindowBits;
66
67 /**
68 * Enables or disables WebSocket compression.
69 */
70 final bool enabled;
71
72 const CompressionOptions(
73 {this.clientNoContextTakeover: false,
74 this.serverNoContextTakeover: false,
75 this.clientMaxWindowBits,
Søren Gjesse 2015/10/19 16:53:20 Assign default value _WebSocketImpl.DEFAULT_WINDOW
butlermatt 2015/10/22 19:36:08 Done.
76 this.serverMaxWindowBits,
77 this.enabled: true});
78
79 /// Parses list of requested server headers to return server compression
80 /// response headers. Uses [serverMaxWindowBits] value if set, otherwise will
81 /// attempt to use value from headers. Defaults to
82 /// [WebSocket.DEFAULT_WINDOW_BITS]
83 List _createServerResponseHeader(HeaderValue requested) {
84 var info = new List(2);
85
86 if (requested.parameters["server_max_window_bits"] != null) {
Søren Gjesse 2015/10/19 16:53:19 Please make the values "server_no_context_takeover
butlermatt 2015/10/22 19:36:08 Done.
87 var part = requested.parameters["server_max_window_bits"];
Søren Gjesse 2015/10/19 16:53:19 Move this 'var part ...' up before the if, and tes
butlermatt 2015/10/22 19:36:08 Done.
88 var mwb = serverMaxWindowBits == null
89 ? int.parse(part,
Søren Gjesse 2015/10/19 16:53:19 According to https://tools.ietf.org/html/draft-iet
butlermatt 2015/10/22 19:36:08 Done.
90 onError: (source) => _WebSocketImpl.DEFAULT_WINDOW_BITS)
Søren Gjesse 2015/10/19 16:53:20 Please indent with 4 - or all the way to align wit
butlermatt 2015/10/22 19:36:08 Done.
91 : serverMaxWindowBits;
92 info[0] = "; server_max_window_bits=${mwb}";
93 info[1] = mwb;
94 } else {
95 info[1] = _WebSocketImpl.DEFAULT_WINDOW_BITS;
96 }
97 return info;
98 }
99
100 /// Returns default values for client compression request headers.
101 List _createClientRequestHeader(HeaderValue requested) {
102 var info = new List(2);
103
104 info[1] = _WebSocketImpl.DEFAULT_WINDOW_BITS;
105 if (requested != null &&
106 requested.parameters["client_max_window_bits"] != null) {
107 info[0] = "; client_max_window_bits=${info[1]}";
108 } else {
109 info[0] = "; client_max_window_bits";
110 }
111
112 return info;
113 }
114
115 /// Create a Compression Header. If [requested] is null or contains
116 /// client request headers, returns Client compression request headers.
117 /// If [requested] contains server response headers this method returns
118 /// a Server compression response header.
119 List _createHeader([HeaderValue requested]) {
120 if (!enabled) {
121 return ["", 0];
122 }
123
124 var info = new List(2);
125 var header = _WebSocketImpl.PER_MESSAGE_DEFLATE;
126
127 if (clientNoContextTakeover &&
128 (requested != null &&
129 requested.parameters.containsKey("client_no_context_takeover"))) {
130 header += "; client_no_context_takeover";
131 }
132
133 if (serverNoContextTakeover &&
134 (requested != null &&
135 requested.parameters.containsKey("server_no_context_takeover"))) {
136 header += "; server_no_context_takeover";
137 }
138
139 if (requested == null ||
140 requested.parameters.containsKey("client_max_window_bits")) {
141 var clientList = _createClientRequestHeader(requested);
142 header += clientList[0];
143 info[1] = clientList[1];
144 } else {
145 var headerList = _createServerResponseHeader(requested);
146 header += headerList[0];
147 info[1] = headerList[1];
148 }
149
150 info[0] = header;
151
152 return info;
153 }
154 }
155
156 /**
27 * The [WebSocketTransformer] provides the ability to upgrade a 157 * The [WebSocketTransformer] provides the ability to upgrade a
28 * [HttpRequest] to a [WebSocket] connection. It supports both 158 * [HttpRequest] to a [WebSocket] connection. It supports both
29 * upgrading a single [HttpRequest] and upgrading a stream of 159 * upgrading a single [HttpRequest] and upgrading a stream of
30 * [HttpRequest]s. 160 * [HttpRequest]s.
31 * 161 *
32 * To upgrade a single [HttpRequest] use the static [upgrade] method. 162 * To upgrade a single [HttpRequest] use the static [upgrade] method.
33 * 163 *
34 * HttpServer server; 164 * HttpServer server;
35 * server.listen((request) { 165 * server.listen((request) {
36 * if (...) { 166 * if (...) {
37 * WebSocketTransformer.upgrade(request).then((websocket) { 167 * WebSocketTransformer.upgrade(request).then((websocket) {
38 * ... 168 * ...
39 * }); 169 * });
40 * } else { 170 * } else {
41 * // Do normal HTTP request processing. 171 * // Do normal HTTP request processing.
42 * } 172 * }
43 * }); 173 * });
44 * 174 *
45 * To transform a stream of [HttpRequest] events as it implements a 175 * To transform a stream of [HttpRequest] events as it implements a
46 * stream transformer that transforms a stream of HttpRequest into a 176 * stream transformer that transforms a stream of HttpRequest into a
47 * stream of WebSockets by upgrading each HttpRequest from the HTTP or 177 * stream of WebSockets by upgrading each HttpRequest from the HTTP or
48 * HTTPS server, to the WebSocket protocol. 178 * HTTPS server, to the WebSocket protocol.
49 * 179 *
50 * server.transform(new WebSocketTransformer()).listen((webSocket) => ...); 180 * server.transform(new WebSocketTransformer()).listen((webSocket) => ...);
51 * 181 *
52 * This transformer strives to implement WebSockets as specified by RFC6455. 182 * This transformer strives to implement WebSockets as specified by RFC6455.
53 */ 183 */
54 abstract class WebSocketTransformer 184 abstract class WebSocketTransformer
55 implements StreamTransformer<HttpRequest, WebSocket> { 185 implements StreamTransformer<HttpRequest, WebSocket> {
56
57 /** 186 /**
58 * Create a new [WebSocketTransformer]. 187 * Create a new [WebSocketTransformer].
59 * 188 *
60 * If [protocolSelector] is provided, [protocolSelector] will be called to 189 * If [protocolSelector] is provided, [protocolSelector] will be called to
61 * select what protocol to use, if any were provided by the client. 190 * select what protocol to use, if any were provided by the client.
62 * [protocolSelector] is should return either a [String] or a [Future] 191 * [protocolSelector] is should return either a [String] or a [Future]
63 * completing with a [String]. The [String] must exist in the list of 192 * completing with a [String]. The [String] must exist in the list of
64 * protocols. 193 * protocols.
Søren Gjesse 2015/10/19 16:53:20 Please update the dartdoc comment here with inform
butlermatt 2015/10/22 19:36:08 Done.
65 */ 194 */
66 factory WebSocketTransformer({protocolSelector(List<String> protocols)}) 195 factory WebSocketTransformer(
67 => new _WebSocketTransformerImpl(protocolSelector); 196 {protocolSelector(List<String> protocols),
197 CompressionOptions compression: CompressionOptions.DEFAULT}) =>
198 new _WebSocketTransformerImpl(protocolSelector, compression);
68 199
69 /** 200 /**
70 * Upgrades a [HttpRequest] to a [WebSocket] connection. If the 201 * Upgrades a [HttpRequest] to a [WebSocket] connection. If the
71 * request is not a valid WebSocket upgrade request an HTTP response 202 * request is not a valid WebSocket upgrade request an HTTP response
72 * with status code 500 will be returned. Otherwise the returned 203 * with status code 500 will be returned. Otherwise the returned
73 * future will complete with the [WebSocket] when the upgrade pocess 204 * future will complete with the [WebSocket] when the upgrade pocess
74 * is complete. 205 * is complete.
75 * 206 *
76 * If [protocolSelector] is provided, [protocolSelector] will be called to 207 * If [protocolSelector] is provided, [protocolSelector] will be called to
77 * select what protocol to use, if any were provided by the client. 208 * select what protocol to use, if any were provided by the client.
78 * [protocolSelector] is should return either a [String] or a [Future] 209 * [protocolSelector] is should return either a [String] or a [Future]
79 * completing with a [String]. The [String] must exist in the list of 210 * completing with a [String]. The [String] must exist in the list of
80 * protocols. 211 * protocols.
Søren Gjesse 2015/10/19 16:53:19 ditto.
butlermatt 2015/10/22 19:36:08 Done.
81 */ 212 */
82 static Future<WebSocket> upgrade(HttpRequest request, 213 static Future<WebSocket> upgrade(HttpRequest request,
83 {protocolSelector(List<String> protocols)}) { 214 {protocolSelector(List<String> protocols),
84 return _WebSocketTransformerImpl._upgrade(request, protocolSelector); 215 CompressionOptions compression: CompressionOptions.DEFAULT}) {
216 return _WebSocketTransformerImpl._upgrade(
217 request, protocolSelector, compression);
85 } 218 }
86 219
87 /** 220 /**
88 * Checks whether the request is a valid WebSocket upgrade request. 221 * Checks whether the request is a valid WebSocket upgrade request.
89 */ 222 */
90 static bool isUpgradeRequest(HttpRequest request) { 223 static bool isUpgradeRequest(HttpRequest request) {
91 return _WebSocketTransformerImpl._isUpgradeRequest(request); 224 return _WebSocketTransformerImpl._isUpgradeRequest(request);
92 } 225 }
93 } 226 }
94 227
95
96 /** 228 /**
97 * A two-way HTTP communication object for client or server applications. 229 * A two-way HTTP communication object for client or server applications.
98 * 230 *
99 * The stream exposes the messages received. A text message will be of type 231 * The stream exposes the messages received. A text message will be of type
100 * [:String:] and a binary message will be of type [:List<int>:]. 232 * [:String:] and a binary message will be of type [:List<int>:].
101 */ 233 */
102 abstract class WebSocket implements Stream, StreamSink { 234 abstract class WebSocket implements Stream, StreamSink {
103 /** 235 /**
104 * Possible states of the connection. 236 * Possible states of the connection.
105 */ 237 */
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 * - `sec-websocket-protocol` 277 * - `sec-websocket-protocol`
146 * - `sec-websocket-version` 278 * - `sec-websocket-version`
147 * - `upgrade` 279 * - `upgrade`
148 * 280 *
149 * If any of these are passed in the `headers` map they will be ignored. 281 * If any of these are passed in the `headers` map they will be ignored.
150 * 282 *
151 * If the `url` contains user information this will be passed as basic 283 * If the `url` contains user information this will be passed as basic
152 * authentication when setting up the connection. 284 * authentication when setting up the connection.
153 */ 285 */
154 static Future<WebSocket> connect(String url, 286 static Future<WebSocket> connect(String url,
155 {Iterable<String> protocols, 287 {Iterable<String> protocols,
156 Map<String, dynamic> headers}) => 288 Map<String, dynamic> headers,
157 _WebSocketImpl.connect(url, protocols, headers); 289 CompressionOptions compression: CompressionOptions.DEFAULT}) =>
290 _WebSocketImpl.connect(url, protocols, headers, compression: compression);
158 291
159 @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`' 292 @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`'
160 ' instead of `extends` if implementing this abstract class.') 293 ' instead of `extends` if implementing this abstract class.')
161 WebSocket(); 294 WebSocket();
162 295
163 /** 296 /**
164 * Creates a WebSocket from an already-upgraded socket. 297 * Creates a WebSocket from an already-upgraded socket.
165 * 298 *
166 * The initial WebSocket handshake must have occurred prior to this call. A 299 * The initial WebSocket handshake must have occurred prior to this call. A
167 * WebSocket client can automatically perform the handshake using 300 * WebSocket client can automatically perform the handshake using
168 * [WebSocket.connect], while a server can do so using 301 * [WebSocket.connect], while a server can do so using
169 * [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest], 302 * [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest],
170 * [HttpRequest.detachSocket] may be called. 303 * [HttpRequest.detachSocket] may be called.
171 * 304 *
172 * [protocol] should be the protocol negotiated by this handshake, if any. 305 * [protocol] should be the protocol negotiated by this handshake, if any.
173 * 306 *
174 * [serverSide] must be passed explicitly. If it's `false`, the WebSocket will 307 * [serverSide] must be passed explicitly. If it's `false`, the WebSocket will
175 * act as the client and mask the messages it sends. If it's `true`, it will 308 * act as the client and mask the messages it sends. If it's `true`, it will
176 * act as the server and will not mask its messages. 309 * act as the server and will not mask its messages.
Søren Gjesse 2015/10/19 16:53:20 ditto.
butlermatt 2015/10/22 19:36:08 Done.
177 */ 310 */
178 factory WebSocket.fromUpgradedSocket(Socket socket, {String protocol, 311 factory WebSocket.fromUpgradedSocket(Socket socket,
179 bool serverSide}) { 312 {String protocol,
313 bool serverSide,
314 CompressionOptions compression: CompressionOptions.DEFAULT}) {
180 if (serverSide == null) { 315 if (serverSide == null) {
181 throw new ArgumentError("The serverSide argument must be passed " 316 throw new ArgumentError("The serverSide argument must be passed "
182 "explicitly to WebSocket.fromUpgradedSocket."); 317 "explicitly to WebSocket.fromUpgradedSocket.");
183 } 318 }
184 return new _WebSocketImpl._fromSocket(socket, protocol, serverSide); 319 return new _WebSocketImpl._fromSocket(
320 socket, protocol, compression, serverSide);
185 } 321 }
186 322
187 /** 323 /**
188 * Returns the current state of the connection. 324 * Returns the current state of the connection.
189 */ 325 */
190 int get readyState; 326 int get readyState;
191 327
192 /** 328 /**
193 * The extensions property is initially the empty string. After the 329 * The extensions property is initially the empty string. After the
194 * WebSocket connection is established this string reflects the 330 * WebSocket connection is established this string reflects the
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 void add(data); 367 void add(data);
232 368
233 /** 369 /**
234 * Sends data from a stream on WebSocket connection. Each data event from 370 * Sends data from a stream on WebSocket connection. Each data event from
235 * [stream] will be send as a single WebSocket frame. The data from [stream] 371 * [stream] will be send as a single WebSocket frame. The data from [stream]
236 * must be either [:String:]s, or [:List<int>:]s holding bytes. 372 * must be either [:String:]s, or [:List<int>:]s holding bytes.
237 */ 373 */
238 Future addStream(Stream stream); 374 Future addStream(Stream stream);
239 } 375 }
240 376
241
242 class WebSocketException implements IOException { 377 class WebSocketException implements IOException {
243 final String message; 378 final String message;
379
244 const WebSocketException([this.message = ""]); 380 const WebSocketException([this.message = ""]);
381
245 String toString() => "WebSocketException: $message"; 382 String toString() => "WebSocketException: $message";
246 } 383 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698