 Chromium Code Reviews
 Chromium Code Reviews| Index: sdk/lib/io/websocket.dart | 
| diff --git a/sdk/lib/io/websocket.dart b/sdk/lib/io/websocket.dart | 
| index 599e295c60ac92923dc620303830b986b8522f96..41be2b2af11b4954086b59af503121496d8be3d4 100644 | 
| --- a/sdk/lib/io/websocket.dart | 
| +++ b/sdk/lib/io/websocket.dart | 
| @@ -12,7 +12,7 @@ abstract class WebSocketStatus { | 
| static const int GOING_AWAY = 1001; | 
| static const int PROTOCOL_ERROR = 1002; | 
| static const int UNSUPPORTED_DATA = 1003; | 
| - static const int RESERVED_1004 = 1004; | 
| + static const int RESERVED_1004 = 1004; | 
| static const int NO_STATUS_RECEIVED = 1005; | 
| static const int ABNORMAL_CLOSURE = 1006; | 
| static const int INVALID_FRAME_PAYLOAD_DATA = 1007; | 
| @@ -24,6 +24,113 @@ abstract class WebSocketStatus { | 
| } | 
| /** | 
| + * The [CompressionOptions] class allows you to control | 
| + * the options of WebSocket compression. | 
| + */ | 
| +class CompressionOptions { | 
| + /** | 
| + * Default WebSocket Compression options. | 
| + * Compression will be enabled with the following options: | 
| + * clientNoContextTakeover: false | 
| + * serverNoContextTakeover: false | 
| + * clientMaxWindowBits: 15 | 
| + * serverMaxWindowBits: 15 | 
| + */ | 
| + static const CompressionOptions DEFAULT = const CompressionOptions(); | 
| + | 
| + /** | 
| + * Disables WebSocket Compression. | 
| + */ | 
| + static const CompressionOptions OFF = | 
| + const CompressionOptions(enabled: false); | 
| + | 
| + /** | 
| + * Control whether the client will reuse it's compression instances. | 
| + */ | 
| + final bool clientNoContextTakeover; | 
| + | 
| + /** | 
| + * Control whether the server will reuse it's compression instances. | 
| + */ | 
| + final bool serverNoContextTakeover; | 
| + | 
| + /** | 
| + * Sets the Max Window Bits for the Client. | 
| + */ | 
| + final int clientMaxWindowBits; | 
| + | 
| + /** | 
| + * Sets the Max Window Bits for the Server. | 
| + */ | 
| + final int serverMaxWindowBits; | 
| + | 
| + /** | 
| + * Enables or disables WebSocket compression. | 
| + */ | 
| + final bool enabled; | 
| + | 
| + const CompressionOptions( | 
| + {this.clientNoContextTakeover: false, | 
| + this.serverNoContextTakeover: false, | 
| + this.clientMaxWindowBits, | 
| + this.serverMaxWindowBits, | 
| + this.enabled: true}); | 
| + | 
| + /** | 
| + * Create a Compression Header | 
| 
Søren Gjesse
2015/08/24 08:21:50
Please add more documentation here on what request
 | 
| + */ | 
| + List _createHeader([List<String> requested]) { | 
| 
Søren Gjesse
2015/08/24 08:21:50
Pass HeaderValue here and use its parameters (see
 | 
| + if (!enabled) { | 
| + return ["", 0]; | 
| + } | 
| + | 
| + var info = new List(2); | 
| + | 
| + var header = _WebSocketImpl.PER_MESSAGE_DEFLATE; | 
| + | 
| + if (clientNoContextTakeover && | 
| + (requested != null && | 
| + requested.contains("client_no_context_takeover"))) { | 
| 
Søren Gjesse
2015/08/24 08:21:50
Please make the values "server_no_context_takeover
 | 
| + header += "; client_no_context_takeover"; | 
| + } | 
| + | 
| + if (serverNoContextTakeover && | 
| + (requested != null && | 
| + requested.contains("server_no_context_takeover"))) { | 
| + header += "; server_no_context_takeover"; | 
| + } | 
| + | 
| + if (requested != null && | 
| + requested.any((x) => x.startsWith("server_max_window_bits="))) { | 
| 
Søren Gjesse
2015/08/24 08:21:50
This check is fragile, there can be WS on both sid
 | 
| + var part = requested | 
| + .firstWhere((x) => x.startsWith("server_max_window_bits=")) | 
| + .substring(23); | 
| + var mwb = serverMaxWindowBits == null | 
| + ? int.parse(part, | 
| 
Søren Gjesse
2015/08/24 08:21:50
According to https://tools.ietf.org/html/draft-iet
 | 
| + onError: (source) => _WebSocketImpl.DEFAULT_WINDOW_BITS) | 
| + : serverMaxWindowBits; | 
| 
Søren Gjesse
2015/08/24 08:21:50
You also need to check for the allowed range 8-15.
 | 
| + header += "; server_max_window_bits=${mwb}"; | 
| + info[1] = mwb; | 
| + } else { | 
| + info[1] = _WebSocketImpl.DEFAULT_WINDOW_BITS; | 
| + } | 
| + | 
| + if (requested == null) { | 
| + header += "; client_max_window_bits"; | 
| + } else { | 
| + if (requested.contains("client_max_window_bits")) { | 
| + var myMaxWindowBits = info[1]; | 
| + header += "; client_max_window_bits=${myMaxWindowBits}"; | 
| + } | 
| + } | 
| + | 
| + info[0] = header; | 
| + | 
| + return info; | 
| + } | 
| +} | 
| + | 
| +/** | 
| * The [WebSocketTransformer] provides the ability to upgrade a | 
| * [HttpRequest] to a [WebSocket] connection. It supports both | 
| * upgrading a single [HttpRequest] and upgrading a stream of | 
| @@ -53,7 +160,6 @@ abstract class WebSocketStatus { | 
| */ | 
| abstract class WebSocketTransformer | 
| implements StreamTransformer<HttpRequest, WebSocket> { | 
| - | 
| /** | 
| * Create a new [WebSocketTransformer]. | 
| * | 
| @@ -63,8 +169,10 @@ abstract class WebSocketTransformer | 
| * completing with a [String]. The [String] must exist in the list of | 
| * protocols. | 
| */ | 
| - factory WebSocketTransformer({protocolSelector(List<String> protocols)}) | 
| - => new _WebSocketTransformerImpl(protocolSelector); | 
| + factory WebSocketTransformer( | 
| + {protocolSelector(List<String> protocols), | 
| + CompressionOptions compression: CompressionOptions.DEFAULT}) => | 
| + new _WebSocketTransformerImpl(protocolSelector, compression); | 
| /** | 
| * Upgrades a [HttpRequest] to a [WebSocket] connection. If the | 
| @@ -80,8 +188,10 @@ abstract class WebSocketTransformer | 
| * protocols. | 
| */ | 
| static Future<WebSocket> upgrade(HttpRequest request, | 
| - {protocolSelector(List<String> protocols)}) { | 
| - return _WebSocketTransformerImpl._upgrade(request, protocolSelector); | 
| + {protocolSelector(List<String> protocols), | 
| + CompressionOptions compression: CompressionOptions.DEFAULT}) { | 
| + return _WebSocketTransformerImpl._upgrade( | 
| + request, protocolSelector, compression); | 
| } | 
| /** | 
| @@ -92,7 +202,6 @@ abstract class WebSocketTransformer | 
| } | 
| } | 
| - | 
| /** | 
| * A two-way HTTP communication object for client or server applications. | 
| * | 
| @@ -152,9 +261,10 @@ abstract class WebSocket implements Stream, StreamSink { | 
| * authentication when setting up the connection. | 
| */ | 
| static Future<WebSocket> connect(String url, | 
| - {Iterable<String> protocols, | 
| - Map<String, dynamic> headers}) => | 
| - _WebSocketImpl.connect(url, protocols, headers); | 
| + {Iterable<String> protocols, | 
| + Map<String, dynamic> headers, | 
| + CompressionOptions compression: CompressionOptions.DEFAULT}) => | 
| + _WebSocketImpl.connect(url, protocols, headers, compression: compression); | 
| @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`' | 
| ' instead of `extends` if implementing this abstract class.') | 
| @@ -175,13 +285,16 @@ abstract class WebSocket implements Stream, StreamSink { | 
| * act as the client and mask the messages it sends. If it's `true`, it will | 
| * act as the server and will not mask its messages. | 
| */ | 
| - factory WebSocket.fromUpgradedSocket(Socket socket, {String protocol, | 
| - bool serverSide}) { | 
| + factory WebSocket.fromUpgradedSocket(Socket socket, | 
| + {String protocol, | 
| + bool serverSide, | 
| + CompressionOptions compression: CompressionOptions.DEFAULT}) { | 
| if (serverSide == null) { | 
| throw new ArgumentError("The serverSide argument must be passed " | 
| "explicitly to WebSocket.fromUpgradedSocket."); | 
| } | 
| - return new _WebSocketImpl._fromSocket(socket, protocol, serverSide); | 
| + return new _WebSocketImpl._fromSocket( | 
| + socket, protocol, compression, serverSide); | 
| } | 
| /** | 
| @@ -238,9 +351,10 @@ abstract class WebSocket implements Stream, StreamSink { | 
| Future addStream(Stream stream); | 
| } | 
| - | 
| class WebSocketException implements IOException { | 
| final String message; | 
| + | 
| const WebSocketException([this.message = ""]); | 
| + | 
| String toString() => "WebSocketException: $message"; | 
| } |