947177049c
This removes the need for Socket.available which is not implemented for SecureSocket. R=ager@google.com BUG= Review URL: https://codereview.chromium.org//11886038 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@17047 260f80e4-7a28-3924-810f-c04153c831b5
223 lines
6.6 KiB
Dart
223 lines
6.6 KiB
Dart
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import "dart:math";
|
|
|
|
part "../../../sdk/lib/io/websocket.dart";
|
|
part "../../../sdk/lib/io/websocket_impl.dart";
|
|
|
|
class WebSocketFrame {
|
|
WebSocketFrame(int opcode, List<int> data);
|
|
}
|
|
|
|
// Class that when hooked up to the web socket protocol processor will
|
|
// collect the message and expect it to be equal to the
|
|
// expectedMessage field when fully received.
|
|
class WebSocketMessageCollector {
|
|
WebSocketMessageCollector(_WebSocketProtocolProcessor this.processor,
|
|
[List<int> this.expectedMessage = null]) {
|
|
processor.onMessageStart = onMessageStart;
|
|
processor.onMessageData = onMessageData;
|
|
processor.onMessageEnd = onMessageEnd;
|
|
processor.onClosed = onClosed;
|
|
}
|
|
|
|
void onMessageStart(int type) {
|
|
data = new List<int>();
|
|
}
|
|
|
|
void onMessageData(List<int> buffer, int index, int count) {
|
|
data.addAll(buffer.getRange(index, count));
|
|
}
|
|
|
|
void onMessageEnd() {
|
|
messageCount++;
|
|
Expect.listEquals(expectedMessage, data);
|
|
data = null;
|
|
}
|
|
|
|
void onClosed(int status, String reason) {
|
|
closeCount++;
|
|
}
|
|
|
|
void onError(e) {
|
|
Expect.fail("Unexpected error $e");
|
|
}
|
|
|
|
_WebSocketProtocolProcessor processor;
|
|
List<int> expectedMessage;
|
|
|
|
List<int> data;
|
|
int messageCount = 0;
|
|
int closeCount = 0;
|
|
}
|
|
|
|
|
|
// Web socket constants.
|
|
const int FRAME_OPCODE_TEXT = 1;
|
|
const int FRAME_OPCODE_BINARY = 2;
|
|
|
|
|
|
// Function for building a web socket frame.
|
|
List<int> createFrame(bool fin,
|
|
int opcode,
|
|
int maskingKey,
|
|
List<int> data,
|
|
int offset,
|
|
int count) {
|
|
int frameSize = 2;
|
|
if (count > 125) frameSize += 2;
|
|
if (count > 65535) frameSize += 6;
|
|
frameSize += count;
|
|
// No masking.
|
|
assert(maskingKey == null);
|
|
List<int> frame = new List<int>.fixedLength(frameSize);
|
|
int frameIndex = 0;
|
|
frame[frameIndex++] = (fin ? 0x80 : 0x00) | opcode;
|
|
if (count < 126) {
|
|
frame[frameIndex++] = count;
|
|
} else if (count < 65536) {
|
|
frame[frameIndex++] = 126;
|
|
frame[frameIndex++] = count >> 8;
|
|
frame[frameIndex++] = count & 0xFF;
|
|
} else {
|
|
frame[frameIndex++] = 127;
|
|
for (int i = 0; i < 8; i++) {
|
|
frame[frameIndex++] = count >> ((7 - i) * 8) & 0xFF;
|
|
}
|
|
}
|
|
frame.setRange(frameIndex, count, data, offset);
|
|
return frame;
|
|
}
|
|
|
|
|
|
// Test processing messages which are sent in a single frame.
|
|
void testFullMessages() {
|
|
// Use the same web socket protocol processor for all frames.
|
|
_WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor();
|
|
WebSocketMessageCollector mc = new WebSocketMessageCollector(processor);
|
|
|
|
int messageCount = 0;
|
|
|
|
void testMessage(int opcode, List<int> message) {
|
|
mc.expectedMessage = message;
|
|
List<int> frame = createFrame(
|
|
true, opcode, null, message, 0, message.length);
|
|
|
|
// Update the processor with one big chunk.
|
|
messageCount++;
|
|
processor.update(frame);
|
|
Expect.isNull(mc.data);
|
|
Expect.equals(0, processor._state);
|
|
|
|
// Only run this part on small messages.
|
|
if (message.length < 1000) {
|
|
// Update the processor one byte at the time.
|
|
messageCount++;
|
|
for (int i = 0; i < frame.length; i++) {
|
|
processor.update(frame.getRange(i, 1));
|
|
}
|
|
Expect.equals(0, processor._state);
|
|
Expect.isNull(mc.data);
|
|
|
|
// Update the processor two bytes at the time.
|
|
messageCount++;
|
|
for (int i = 0; i < frame.length; i += 2) {
|
|
processor.update(frame.getRange(i, i + 1 < frame.length ? 2 : 1));
|
|
}
|
|
Expect.equals(0, processor._state);
|
|
Expect.isNull(mc.data);
|
|
}
|
|
}
|
|
|
|
void runTest(int from, int to, int step) {
|
|
for (int messageLength = from; messageLength < to; messageLength += step) {
|
|
List<int> message = new List<int>.fixedLength(messageLength);
|
|
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
|
testMessage(FRAME_OPCODE_TEXT, message);
|
|
testMessage(FRAME_OPCODE_BINARY, message);
|
|
}
|
|
}
|
|
|
|
// Test different message sizes.
|
|
runTest(0, 10, 1);
|
|
runTest(120, 130, 1);
|
|
runTest(0, 1000, 100);
|
|
runTest(65534, 65537, 1);
|
|
print("Messages test, messages $messageCount");
|
|
Expect.equals(messageCount, mc.messageCount);
|
|
Expect.equals(0, mc.closeCount);
|
|
}
|
|
|
|
|
|
// Test processing of frames which are split into fragments.
|
|
void testFragmentedMessages() {
|
|
// Use the same web socket protocol processor for all frames.
|
|
_WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor();
|
|
WebSocketMessageCollector mc = new WebSocketMessageCollector(processor);
|
|
|
|
int messageCount = 0;
|
|
int frameCount = 0;
|
|
|
|
void testFragmentMessage(int opcode, List<int> message, int fragmentSize) {
|
|
messageCount++;
|
|
int messageIndex = 0;
|
|
int remaining = message.length;
|
|
bool firstFrame = true;
|
|
bool lastFrame = false;
|
|
while (!lastFrame) {
|
|
int payloadSize = min(fragmentSize, remaining);
|
|
lastFrame = payloadSize == remaining;
|
|
List<int> frame = createFrame(lastFrame,
|
|
firstFrame ? opcode : 0x00,
|
|
null,
|
|
message,
|
|
messageIndex,
|
|
payloadSize);
|
|
frameCount++;
|
|
messageIndex += payloadSize;
|
|
processor.update(frame);
|
|
remaining -= payloadSize;
|
|
firstFrame = false;
|
|
}
|
|
}
|
|
|
|
void testMessageFragmentation(int opcode, List<int> message) {
|
|
mc.expectedMessage = message;
|
|
|
|
// Test with fragmenting the message in different fragment sizes.
|
|
if (message.length <= 10) {
|
|
for (int i = 1; i < 10; i++) {
|
|
testFragmentMessage(opcode, message, i);
|
|
}
|
|
} else {
|
|
testFragmentMessage(opcode, message, 10);
|
|
testFragmentMessage(opcode, message, 100);
|
|
}
|
|
}
|
|
|
|
void runTest(int from, int to, int step) {
|
|
for (int messageLength = from; messageLength < to; messageLength += step) {
|
|
List<int> message = new List<int>.fixedLength(messageLength);
|
|
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
|
testMessageFragmentation(FRAME_OPCODE_TEXT, message);
|
|
testMessageFragmentation(FRAME_OPCODE_BINARY, message);
|
|
}
|
|
}
|
|
|
|
// Test different message sizes.
|
|
runTest(0, 10, 1);
|
|
runTest(120, 130, 1);
|
|
runTest(0, 1000, 100);
|
|
runTest(65534, 65537, 1);
|
|
print("Fragment messages test, messages $messageCount, frames $frameCount");
|
|
Expect.equals(messageCount, mc.messageCount);
|
|
Expect.equals(0, mc.closeCount);
|
|
}
|
|
|
|
void main() {
|
|
testFullMessages();
|
|
testFragmentedMessages();
|
|
}
|