| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #source("../../../../runtime/bin/websocket.dart"); | |
| 6 #source("../../../../runtime/bin/websocket_impl.dart"); | |
| 7 | |
| 8 class WebSocketFrame { | |
| 9 WebSocketFrame(int opcode, List<int> data); | |
| 10 } | |
| 11 | |
| 12 // Class that when hooked up to the web socket protocol processor will | |
| 13 // collect the message and expect it to be equal to the | |
| 14 // expectedMessage field when fully received. | |
| 15 class WebSocketMessageCollector { | |
| 16 WebSocketMessageCollector(_WebSocketProtocolProcessor this.processor, | |
| 17 [List<int> this.expectedMessage = null]) { | |
| 18 processor.onMessageStart = onMessageStart; | |
| 19 processor.onMessageData = onMessageData; | |
| 20 processor.onMessageEnd = onMessageEnd; | |
| 21 processor.onClosed = onClosed; | |
| 22 } | |
| 23 | |
| 24 void onMessageStart(int type) { | |
| 25 data = new List<int>(); | |
| 26 } | |
| 27 | |
| 28 void onMessageData(List<int> buffer, int index, int count) { | |
| 29 data.addAll(buffer.getRange(index, count)); | |
| 30 } | |
| 31 | |
| 32 void onMessageEnd() { | |
| 33 messageCount++; | |
| 34 Expect.listEquals(expectedMessage, data); | |
| 35 data = null; | |
| 36 } | |
| 37 | |
| 38 void onClosed(int status, String reason) { | |
| 39 closeCount++; | |
| 40 } | |
| 41 | |
| 42 void onError(e) { | |
| 43 Expect.fail("Unexpected error $e"); | |
| 44 } | |
| 45 | |
| 46 _WebSocketProtocolProcessor processor; | |
| 47 List<int> expectedMessage; | |
| 48 | |
| 49 List<int> data; | |
| 50 int messageCount = 0; | |
| 51 int closeCount = 0; | |
| 52 } | |
| 53 | |
| 54 | |
| 55 // Web socket constants. | |
| 56 final int FRAME_OPCODE_TEXT = 1; | |
| 57 final int FRAME_OPCODE_BINARY = 2; | |
| 58 | |
| 59 | |
| 60 // Function for building a web socket frame. | |
| 61 List<int> createFrame(bool fin, | |
| 62 int opcode, | |
| 63 int maskingKey, | |
| 64 List<int> data, | |
| 65 int offset, | |
| 66 int count) { | |
| 67 int frameSize = 2; | |
| 68 if (count > 125) frameSize += 2; | |
| 69 if (count > 65535) frameSize += 6; | |
| 70 frameSize += count; | |
| 71 // No masking. | |
| 72 assert(maskingKey == null); | |
| 73 List<int> frame = new List<int>(frameSize); | |
| 74 int frameIndex = 0; | |
| 75 frame[frameIndex++] = (fin ? 0x80 : 0x00) | opcode; | |
| 76 if (count < 126) { | |
| 77 frame[frameIndex++] = count; | |
| 78 } else if (count < 65536) { | |
| 79 frame[frameIndex++] = 126; | |
| 80 frame[frameIndex++] = count >> 8; | |
| 81 frame[frameIndex++] = count & 0xFF; | |
| 82 } else { | |
| 83 frame[frameIndex++] = 127; | |
| 84 for (int i = 0; i < 8; i++) { | |
| 85 frame[frameIndex++] = count >> ((7 - i) * 8) & 0xFF; | |
| 86 } | |
| 87 } | |
| 88 frame.setRange(frameIndex, count, data, offset); | |
| 89 return frame; | |
| 90 } | |
| 91 | |
| 92 | |
| 93 // Test processing messages which are sent in a single frame. | |
| 94 void testFullMessages() { | |
| 95 // Use the same web socket protocol processor for all frames. | |
| 96 _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); | |
| 97 WebSocketMessageCollector mc = new WebSocketMessageCollector(processor); | |
| 98 | |
| 99 int messageCount = 0; | |
| 100 | |
| 101 void testMessage(int opcode, List<int> message) { | |
| 102 mc.expectedMessage = message; | |
| 103 List<int> frame = createFrame( | |
| 104 true, opcode, null, message, 0, message.length); | |
| 105 | |
| 106 // Update the processor with one big chunk. | |
| 107 messageCount++; | |
| 108 processor.update(frame, 0, frame.length); | |
| 109 Expect.isNull(mc.data); | |
| 110 Expect.equals(0, processor._state); | |
| 111 | |
| 112 // Only run this part on small messages. | |
| 113 if (message.length < 1000) { | |
| 114 // Update the processor one byte at the time. | |
| 115 messageCount++; | |
| 116 for (int i = 0; i < frame.length; i++) { | |
| 117 processor.update(frame, i, 1); | |
| 118 } | |
| 119 Expect.equals(0, processor._state); | |
| 120 Expect.isNull(mc.data); | |
| 121 | |
| 122 // Update the processor two bytes at the time. | |
| 123 messageCount++; | |
| 124 for (int i = 0; i < frame.length; i += 2) { | |
| 125 processor.update(frame, i, i + 1 < frame.length ? 2 : 1); | |
| 126 } | |
| 127 Expect.equals(0, processor._state); | |
| 128 Expect.isNull(mc.data); | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 void runTest(int from, int to, int step) { | |
| 133 for (int messageLength = from; messageLength < to; messageLength += step) { | |
| 134 List<int> message = new List<int>(messageLength); | |
| 135 for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF; | |
| 136 testMessage(FRAME_OPCODE_TEXT, message); | |
| 137 testMessage(FRAME_OPCODE_BINARY, message); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 // Test different message sizes. | |
| 142 runTest(0, 10, 1); | |
| 143 runTest(120, 130, 1); | |
| 144 runTest(0, 1000, 100); | |
| 145 runTest(65534, 65537, 1); | |
| 146 print("Messages test, messages $messageCount"); | |
| 147 Expect.equals(messageCount, mc.messageCount); | |
| 148 Expect.equals(0, mc.closeCount); | |
| 149 } | |
| 150 | |
| 151 | |
| 152 // Test processing of frames which are split into fragments. | |
| 153 void testFragmentedMessages() { | |
| 154 // Use the same web socket protocol processor for all frames. | |
| 155 _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); | |
| 156 WebSocketMessageCollector mc = new WebSocketMessageCollector(processor); | |
| 157 | |
| 158 int messageCount = 0; | |
| 159 int frameCount = 0; | |
| 160 | |
| 161 void testFragmentMessage(int opcode, List<int> message, int fragmentSize) { | |
| 162 messageCount++; | |
| 163 int messageIndex = 0; | |
| 164 int remaining = message.length; | |
| 165 bool firstFrame = true; | |
| 166 bool lastFrame = false; | |
| 167 while (!lastFrame) { | |
| 168 int payloadSize = Math.min(fragmentSize, remaining); | |
| 169 lastFrame = payloadSize == remaining; | |
| 170 List<int> frame = createFrame(lastFrame, | |
| 171 firstFrame ? opcode : 0x00, | |
| 172 null, | |
| 173 message, | |
| 174 messageIndex, | |
| 175 payloadSize); | |
| 176 frameCount++; | |
| 177 messageIndex += payloadSize; | |
| 178 processor.update(frame, 0, frame.length); | |
| 179 remaining -= payloadSize; | |
| 180 firstFrame = false; | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 void testMessageFragmentation(int opcode, List<int> message) { | |
| 185 mc.expectedMessage = message; | |
| 186 | |
| 187 // Test with fragmenting the message in different fragment sizes. | |
| 188 if (message.length <= 10) { | |
| 189 for (int i = 1; i < 10; i++) { | |
| 190 testFragmentMessage(opcode, message, i); | |
| 191 } | |
| 192 } else { | |
| 193 testFragmentMessage(opcode, message, 10); | |
| 194 testFragmentMessage(opcode, message, 100); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 void runTest(int from, int to, int step) { | |
| 199 for (int messageLength = from; messageLength < to; messageLength += step) { | |
| 200 List<int> message = new List<int>(messageLength); | |
| 201 for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF; | |
| 202 testMessageFragmentation(FRAME_OPCODE_TEXT, message); | |
| 203 testMessageFragmentation(FRAME_OPCODE_BINARY, message); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 // Test different message sizes. | |
| 208 runTest(0, 10, 1); | |
| 209 runTest(120, 130, 1); | |
| 210 runTest(0, 1000, 100); | |
| 211 runTest(65534, 65537, 1); | |
| 212 print("Fragment messages test, messages $messageCount, frames $frameCount"); | |
| 213 Expect.equals(messageCount, mc.messageCount); | |
| 214 Expect.equals(0, mc.closeCount); | |
| 215 } | |
| 216 | |
| 217 void main() { | |
| 218 testFullMessages(); | |
| 219 testFragmentedMessages(); | |
| 220 } | |
| OLD | NEW |