Chromium Code Reviews| 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; |
| } |
| } |