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 |