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

Unified Diff: sdk/lib/io/websocket_impl.dart

Issue 1208473005: WebSocket Compression (Closed) Base URL: https://github.com/dart-lang/sdk.git
Patch Set: Take Suggestions Created 5 years, 6 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 side-by-side diff with in-line comments
Download patch
« sdk/lib/io/websocket.dart ('K') | « sdk/lib/io/websocket.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/io/websocket_impl.dart
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 183500c6510808ffda8144d58c3fe99a8cd6a72a..5b73c98025477e7f3b033ee9180391c0e6343089 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -51,6 +51,11 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
static const int PAYLOAD = 4;
static const int CLOSED = 5;
static const int FAILURE = 6;
+ static const int FIN = 0x80;
+ static const int RSV1 = 0x40;
+ static const int RSV2 = 0x20;
+ static const int RSV3 = 0x10;
+ static const int OPCODE = 0xF;
int _state = START;
bool _fin = false;
@@ -109,18 +114,18 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
int byte = buffer[index];
if (_state <= LEN_REST) {
if (_state == START) {
- _fin = (byte & 0x80) != 0;
+ _fin = (byte & FIN) != 0;
- if ((byte & 0x40) != 0) {
+ if ((byte & RSV1) != 0) {
_compressed = true;
}
- if ((byte & 0x20) != 0 || (byte & 0x10) != 0) {
+ if ((byte & RSV2) != 0 || (byte & RSV3) != 0) {
// The RSV2 and RSV3 bits must be all zero.
throw new WebSocketException("Protocol error");
}
- _opcode = (byte & 0xF);
+ _opcode = (byte & OPCODE);
if (_opcode <= _WebSocketOpcode.BINARY) {
if (_opcode == _WebSocketOpcode.CONTINUATION) {
@@ -421,23 +426,12 @@ class _WebSocketTransformerImpl implements WebSocketTransformer {
response.headers.add("Sec-WebSocket-Protocol", protocol);
}
- var extensionHeader = request.headers.value("Sec-WebSocket-Extensions");
-
- if (extensionHeader == null) {
- extensionHeader = "";
- }
-
- Iterable<List<String>> extensions = extensionHeader.split(",").map((it) => it.split("; "));
-
- if (compression.enabled && extensions.any((x) => x[0] == "permessage-deflate")) {
- var opts = extensions.firstWhere((x) => x[0] == "permessage-deflate");
- response.headers.add("Sec-WebSocket-Extensions", compression._createHeader(opts));
- }
+ var deflate = _negotiateCompression(request, response, compression);
response.headers.contentLength = 0;
return response.detachSocket()
.then((socket) => new _WebSocketImpl._fromSocket(
- socket, protocol, compression, true));
+ socket, protocol, compression, true, deflate));
}
var protocols = request.headers['Sec-WebSocket-Protocol'];
@@ -466,6 +460,31 @@ class _WebSocketTransformerImpl implements WebSocketTransformer {
}
}
+ static _WebSocketPerMessageDeflate _negotiateCompression(HttpRequest request,
+ HttpResponse response,
+ CompressionOptions compression) {
+ var extensionHeader = request.headers.value("Sec-WebSocket-Extensions");
+
+ if (extensionHeader == null) {
+ extensionHeader = "";
+ }
+
+ Iterable<List<String>> extensions = extensionHeader.split(",").map((it) => it.split("; "));
Søren Gjesse 2015/07/03 13:14:54 Long line (more below).
+
+ if (compression.enabled && extensions.any((x) => x[0] == "permessage-deflate")) {
+ var opts = extensions.firstWhere((x) => x[0] == "permessage-deflate");
+ response.headers.add("Sec-WebSocket-Extensions", compression._createHeader(opts));
Søren Gjesse 2015/07/03 13:14:55 Wouldnt it be better here to take the extenstion (
+ var noContextTakeover = opts.contains("server_no_context_takeover");
+ var deflate = new _WebSocketPerMessageDeflate(
+ noContextTakeover: noContextTakeover,
+ serverSide: true);
+
+ return deflate;
+ }
+
+ return null;
+ }
+
static bool _isUpgradeRequest(HttpRequest request) {
if (request.method != "GET") {
return false;
@@ -504,14 +523,15 @@ class _WebSocketPerMessageDeflate {
ZLibEncoder encoder;
_WebSocketPerMessageDeflate({this.clientMaxWindowBits,
- this.serverMaxWindowBits, this.noContextTakeover,
+ this.serverMaxWindowBits,
+ this.noContextTakeover,
this.serverSide: false}) {
if (clientMaxWindowBits == null) {
- clientMaxWindowBits = 15;
+ clientMaxWindowBits = _WebSocketImpl.DEFAULT_WINDOW_BITS;
}
if (serverMaxWindowBits == null) {
- serverMaxWindowBits = 15;
+ serverMaxWindowBits = _WebSocketImpl.DEFAULT_WINDOW_BITS;
}
}
@@ -534,13 +554,22 @@ class _WebSocketPerMessageDeflate {
var builder = new BytesBuilder();
builder.add(msg);
builder.add(const [0x00, 0x00, 0xff, 0xff]);
- return decoder.convert(builder.takeBytes());
+ var result = decoder.convert(builder.takeBytes());
+ if (noContextTakeover) {
+ decoder = null;
+ }
+ print(result);
+ return result;
}
List<int> processOutgoingMessage(List<int> msg) {
_ensureEncoder();
var c = encoder.convert(msg);
c = c.sublist(0, c.length - 4);
+ if (noContextTakeover) {
+ encoder = null;
+ }
+ print(c);
return c;
}
}
@@ -581,20 +610,12 @@ class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink {
if (message is String) {
opcode = _WebSocketOpcode.TEXT;
data = UTF8.encode(message);
-
- if (_deflateHelper != null) {
- data = _deflateHelper.processOutgoingMessage(data);
- }
} else {
if (message is !List<int>) {
throw new ArgumentError(message);
}
opcode = _WebSocketOpcode.BINARY;
data = message;
-
- if (_deflateHelper != null) {
- data = _deflateHelper.processOutgoingMessage(data);
- }
}
if (_deflateHelper != null) {
@@ -626,7 +647,7 @@ class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink {
}
void addFrame(int opcode, List<int> data) =>
- createFrame(opcode, data, webSocket._serverSide, webSocket._deflate != null)
+ createFrame(opcode, data, webSocket._serverSide, _deflateHelper != null)
.forEach((e) {
_eventSink.add(e);
});
@@ -852,6 +873,7 @@ class _WebSocketConsumer implements StreamConsumer {
class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
// Use default Map so we keep order.
static Map<int, _WebSocketImpl> _webSockets = new Map<int, _WebSocketImpl>();
+ static const int DEFAULT_WINDOW_BITS = 15;
final String protocol;
@@ -917,8 +939,7 @@ class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
..set(HttpHeaders.UPGRADE, "websocket")
..set("Sec-WebSocket-Key", nonce)
..set("Cache-Control", "no-cache")
- ..set("Sec-WebSocket-Version", "13")
- ..set("Sec-WebSocket-Extensions", "permessage-deflate");
+ ..set("Sec-WebSocket-Version", "13");
if (protocols != null) {
request.headers.add("Sec-WebSocket-Protocol", protocols.toList());
}
@@ -961,50 +982,57 @@ class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
}
var protocol = response.headers.value('Sec-WebSocket-Protocol');
- String extensionHeader = response.headers.value('Sec-WebSocket-Extensions');
+ _WebSocketPerMessageDeflate deflate =
+ negotiateClientCompression(response, compression);
- if (extensionHeader == null) {
- extensionHeader = "";
- }
-
- Iterable<List<String>> extensions = extensionHeader
- .split(", ")
- .map((it) => it.split("; "));
+ return response.detachSocket()
+ .then((socket) => new _WebSocketImpl._fromSocket(socket, protocol,
+ compression, false, deflate));
+ });
+ }
- _WebSocketPerMessageDeflate deflate;
+ static _WebSocketPerMessageDeflate negotiateClientCompression(
+ HttpClientResponse response,
+ CompressionOptions compression) {
+ String extensionHeader = response.headers.value('Sec-WebSocket-Extensions');
- if (compression.enabled && extensions.any((x) => x[0] == "permessage-deflate")) {
- var opts = extensions.firstWhere((x) => x[0] == "permessage-deflate");
- var noContextTakeover = opts.contains("client_no_context_takeover");
+ if (extensionHeader == null) {
+ extensionHeader = "";
+ }
- int getWindowBits(String type) {
- var o = opts.firstWhere((x) =>
- x.startsWith("${type}_max_window_bits="), orElse: () => null);
+ Iterable<List<String>> extensions = extensionHeader
+ .split(", ")
+ .map((it) => it.split("; "));
- if (o == null) {
- return 15;
- }
+ if (compression.enabled && extensions.any((x) => x[0] == "permessage-deflate")) {
+ var opts = extensions.firstWhere((x) => x[0] == "permessage-deflate");
Søren Gjesse 2015/07/03 13:14:55 As mentioned above parsing "opts" int a Compressio
+ var noContextTakeover = opts.contains("client_no_context_takeover");
- try {
- o = o.substring("client_max_window_bits=".length);
- o = int.parse(o);
- } catch (e) {
- return 15;
- }
+ int getWindowBits(String type) {
+ var o = opts.firstWhere((x) =>
+ x.startsWith("${type}_max_window_bits="), orElse: () => null);
- return o;
- }
+ if (o == null) {
+ return DEFAULT_WINDOW_BITS;
+ }
- deflate = new _WebSocketPerMessageDeflate(
- clientMaxWindowBits: getWindowBits("client"),
- serverMaxWindowBits: getWindowBits("server"),
- noContextTakeover: noContextTakeover);
+ try {
+ o = o.substring("${type}_max_window_bits=".length);
+ o = int.parse(o);
+ } catch (e) {
+ return DEFAULT_WINDOW_BITS;
}
- return response.detachSocket()
- .then((socket) => new _WebSocketImpl._fromSocket(socket, protocol,
- compression, false, deflate));
- });
+ return o;
+ }
+
+ return new _WebSocketPerMessageDeflate(
+ clientMaxWindowBits: getWindowBits("client"),
+ serverMaxWindowBits: getWindowBits("server"),
+ noContextTakeover: noContextTakeover);
+ }
+
+ return null;
}
_WebSocketImpl._fromSocket(this._socket, this.protocol,
« sdk/lib/io/websocket.dart ('K') | « sdk/lib/io/websocket.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698