Index: sdk/lib/io/websocket_impl.dart |
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart |
index 69a7f0eb69f36793cff1db27e937694c2ec5d299..4fc5b72631b57af9460728a56b3f80355e2fc1ba 100644 |
--- a/sdk/lib/io/websocket_impl.dart |
+++ b/sdk/lib/io/websocket_impl.dart |
@@ -169,17 +169,15 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink { |
} else { |
assert(_state == PAYLOAD); |
// The payload is not handled one byte at a time but in blocks. |
- int payload = min(lastIndex - index, _remainingPayloadBytes); |
- _remainingPayloadBytes -= payload; |
+ int payloadLength = min(lastIndex - index, _remainingPayloadBytes); |
+ _remainingPayloadBytes -= payloadLength; |
// Unmask payload if masked. |
if (_masked) { |
- for (int i = index; i < index + payload; i++) { |
- buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3]; |
- } |
+ _unmask(index, payloadLength, buffer); |
} |
// Control frame and data frame share _payload builder. |
- _payload.add(new Uint8List.view(buffer.buffer, index, payload)); |
- index += payload; |
+ _payload.add(new Uint8List.view(buffer.buffer, index, payloadLength)); |
+ index += payloadLength; |
if (_isControlFrame()) { |
if (_remainingPayloadBytes == 0) _controlFrameEnd(); |
} else { |
@@ -200,6 +198,40 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink { |
} |
} |
+ void _unmask(int index, int payload, Uint8List buffer) { |
kasperl
2014/01/29 09:47:37
payload -> length
Anders Johnsen
2014/01/29 10:19:04
Done.
|
+ const int BLOCK_SIZE = 16; |
+ // Start by alligning to 16 bytes. |
kasperl
2014/01/29 09:47:37
alligning -> aligning
Anders Johnsen
2014/01/29 10:19:04
Done.
|
+ final int startOffset = min(BLOCK_SIZE - (index & 15), payload); |
kasperl
2014/01/29 09:47:37
Maybe replace this whole min computation by checki
Anders Johnsen
2014/01/29 10:19:04
Done.
|
+ int end = index + startOffset; |
+ for (int i = index; i < end; i++) { |
+ buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3]; |
+ } |
+ index += startOffset; |
+ payload -= startOffset; |
+ final int blockCount = payload ~/ BLOCK_SIZE; |
+ if (blockCount > 0) { |
+ // Create mask block. |
+ int mask = 0; |
+ for (int i = 3; i >= 0; i--) { |
kasperl
2014/01/29 09:47:37
Here's an idea: Why don't you turn masking bytes i
Anders Johnsen
2014/01/29 10:19:04
While the idea is very cool, I'm afraid the build-
|
+ mask = (mask << 8) | _maskingBytes[(_unmaskingIndex + i) & 3]; |
+ } |
+ Int32x4 blockMask = new Int32x4(mask, mask, mask, mask); |
+ Int32x4List blockBuffer = new Int32x4List.view( |
+ buffer.buffer, index, blockCount); |
+ for (int i = 0; i < blockBuffer.length; i++) { |
+ blockBuffer[i] ^= blockMask; |
+ } |
+ final int bytes = blockCount * BLOCK_SIZE; |
+ index += bytes; |
+ payload -= bytes; |
+ } |
+ // Handle end. |
+ end = index + payload; |
+ for (int i = index; i < end; i++) { |
+ buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3]; |
+ } |
+ } |
+ |
void _lengthDone() { |
if (_masked) { |
if (!_serverSide) { |
@@ -530,28 +562,45 @@ class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink { |
header.setRange(index, index + 4, maskBytes); |
index += 4; |
if (data != null) { |
- var list; |
+ Uint8List list; |
// If this is a text message just do the masking inside the |
// encoded data. |
- if (opcode == _WebSocketOpcode.TEXT) { |
+ if (opcode == _WebSocketOpcode.TEXT && data is Uint8List) { |
list = data; |
} else { |
- list = new Uint8List(data.length); |
+ if (data is Uint8List) { |
+ list = new Uint8List.fromList(data); |
+ } else { |
+ list = new Uint8List(data.length); |
+ for (int i = 0; i < data.length; i++) { |
+ if (data[i] < 0 || 255 < data[i]) { |
+ throw new ArgumentError( |
+ "List element is not a byte value " |
+ "(value ${data[i]} at index $i)"); |
+ } |
+ list[i] = data[i]; |
+ } |
+ } |
} |
- if (data is Uint8List) { |
- for (int i = 0; i < data.length; i++) { |
- list[i] = data[i] ^ maskBytes[i & 3]; |
+ const int BLOCK_SIZE = 16; |
+ int blockCount = list.length ~/ BLOCK_SIZE; |
+ if (blockCount > 0) { |
+ // Create mask block. |
+ int mask = 0; |
+ for (int i = 3; i >= 0; i--) { |
+ mask = (mask << 8) | maskBytes[i]; |
} |
- } else { |
- for (int i = 0; i < data.length; i++) { |
- if (data[i] < 0 || 255 < data[i]) { |
- throw new ArgumentError( |
- "List element is not a byte value " |
- "(value ${data[i]} at index $i)"); |
- } |
- list[i] = data[i] ^ maskBytes[i & 3]; |
+ Int32x4 blockMask = new Int32x4(mask, mask, mask, mask); |
+ Int32x4List blockBuffer = new Int32x4List.view( |
+ list.buffer, 0, blockCount); |
+ for (int i = 0; i < blockBuffer.length; i++) { |
+ blockBuffer[i] ^= blockMask; |
} |
} |
+ // Handle end. |
+ for (int i = blockCount * BLOCK_SIZE; i < list.length; i++) { |
+ list[i] ^= maskBytes[i & 3]; |
+ } |
data = list; |
} |
} |