| 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..0da50b2dfaa6116bcf850c17f690ec0a30255881 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,43 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
|
| }
|
| }
|
|
|
| + void _unmask(int index, int length, Uint8List buffer) {
|
| + const int BLOCK_SIZE = 16;
|
| + // Skip Int32x4-version if message is small.
|
| + if (length >= BLOCK_SIZE) {
|
| + // Start by aligning to 16 bytes.
|
| + final int startOffset = BLOCK_SIZE - (index & 15);
|
| + final int end = index + startOffset;
|
| + for (int i = index; i < end; i++) {
|
| + buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
|
| + }
|
| + index += startOffset;
|
| + length -= startOffset;
|
| + final int blockCount = length ~/ BLOCK_SIZE;
|
| + if (blockCount > 0) {
|
| + // Create mask block.
|
| + int mask = 0;
|
| + for (int i = 3; i >= 0; i--) {
|
| + 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;
|
| + length -= bytes;
|
| + }
|
| + }
|
| + // Handle end.
|
| + final int end = index + length;
|
| + for (int i = index; i < end; i++) {
|
| + buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
|
| + }
|
| + }
|
| +
|
| void _lengthDone() {
|
| if (_masked) {
|
| if (!_serverSide) {
|
| @@ -530,28 +565,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;
|
| }
|
| }
|
|
|