OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 // | 4 // |
5 | 5 // VMOptions= |
6 import "dart:async"; | 6 // VMOptions=--short_socket_read |
| 7 // VMOptions=--short_socket_write |
| 8 // VMOptions=--short_socket_read --short_socket_write |
| 9 |
7 import "dart:io"; | 10 import "dart:io"; |
8 import "dart:isolate"; | 11 import "dart:isolate"; |
9 import "dart:scalarlist"; | 12 import "dart:scalarlist"; |
10 import "dart:uri"; | 13 |
11 | 14 void testRequestResponseClientCloses( |
12 const SERVER_ADDRESS = "127.0.0.1"; | 15 int totalConnections, int closeStatus, String closeReason) { |
13 const HOST_NAME = "localhost"; | 16 HttpServer.bind().then((server) { |
14 | 17 |
15 | 18 server.transform(new WebSocketTransformer()).listen((webSocket) { |
16 class WebSocketInfo { | 19 webSocket.listen((event) { |
17 int messageCount = 0; | 20 if (event is MessageEvent) { |
18 } | 21 webSocket.send(event.data); |
19 | 22 } else if (event is CloseEvent) { |
20 | 23 Expect.equals(closeStatus == null |
21 /** | 24 ? WebSocketStatus.NO_STATUS_RECEIVED |
22 * A SecurityConfiguration lets us run the tests over HTTP or HTTPS. | 25 : closeStatus, event.code); |
23 */ | 26 Expect.equals(closeReason == null ? "" : closeReason, event.reason); |
24 class SecurityConfiguration { | 27 } |
25 final bool secure; | 28 }); |
26 HttpClient client; | 29 }); |
27 | |
28 SecurityConfiguration({bool this.secure}) : client = new HttpClient(); | |
29 | |
30 HttpServer createServer({int backlog}) { | |
31 HttpServer server = secure ? new HttpsServer() : new HttpServer(); | |
32 server.listen(SERVER_ADDRESS, | |
33 0, | |
34 backlog: backlog, | |
35 certificate_name: "CN=$HOST_NAME"); | |
36 return server; | |
37 } | |
38 | |
39 WebSocketClientConnection createClient(int port, | |
40 {bool followRedirects, | |
41 String method: "GET"}) { | |
42 HttpClientConnection conn = client.openUrl(method, Uri.parse( | |
43 '${secure ? "https" : "http"}://$HOST_NAME:$port/')); | |
44 if (followRedirects != null) { | |
45 conn.followRedirects = followRedirects; | |
46 } | |
47 return new WebSocketClientConnection(conn); | |
48 } | |
49 | |
50 void testRequestResponseClientCloses( | |
51 int totalConnections, int closeStatus, String closeReason) { | |
52 HttpServer server = createServer(backlog: totalConnections); | |
53 HttpClient client = new HttpClient(); | |
54 | |
55 // Make a web socket handler and set it as the HTTP server default handler. | |
56 WebSocketHandler wsHandler = new WebSocketHandler(); | |
57 wsHandler.onOpen = (WebSocketConnection conn) { | |
58 var count = 0; | |
59 conn.onMessage = (Object message) => conn.send(message); | |
60 conn.onClosed = (status, reason) { | |
61 Expect.equals(closeStatus == null | |
62 ? WebSocketStatus.NO_STATUS_RECEIVED | |
63 : closeStatus, status); | |
64 Expect.equals(closeReason == null ? "" : closeReason, reason); | |
65 }; | |
66 }; | |
67 server.defaultRequestHandler = wsHandler.onRequest; | |
68 | 30 |
69 int closeCount = 0; | 31 int closeCount = 0; |
70 String messageText = "Hello, world!"; | 32 String messageText = "Hello, world!"; |
71 for (int i = 0; i < totalConnections; i++) { | 33 for (int i = 0; i < totalConnections; i++) { |
72 int messageCount = 0; | 34 int messageCount = 0; |
73 WebSocketClientConnection wsconn = createClient(server.port); | 35 WebSocket.connect("ws://127.0.0.1:${server.port}/") |
74 wsconn.onOpen = () => wsconn.send(messageText); | 36 .then((webSocket) { |
75 wsconn.onMessage = (message) { | 37 webSocket.send(messageText); |
76 messageCount++; | 38 webSocket.listen((event) { |
77 if (messageCount < 10) { | 39 if (event is MessageEvent) { |
78 Expect.equals(messageText, message); | 40 messageCount++; |
79 wsconn.send(message); | 41 if (messageCount < 1 ) { |
80 } else { | 42 Expect.equals(messageText, event.data); |
81 wsconn.close(closeStatus, closeReason); | 43 webSocket.send(event.data); |
82 } | 44 } else { |
83 }; | 45 webSocket.close(closeStatus, closeReason); |
84 wsconn.onClosed = (status, reason) { | 46 } |
85 Expect.equals(closeStatus == null | 47 } else if (event is CloseEvent) { |
86 ? WebSocketStatus.NO_STATUS_RECEIVED | 48 Expect.equals(closeStatus == null |
87 : closeStatus, status); | 49 ? WebSocketStatus.NO_STATUS_RECEIVED |
88 Expect.equals("", reason); | 50 : closeStatus, event.code); |
89 closeCount++; | 51 Expect.equals("", event.reason); |
90 if (closeCount == totalConnections) { | 52 closeCount++; |
91 client.shutdown(); | 53 if (closeCount == totalConnections) { |
92 server.close(); | 54 server.close(); |
93 } | 55 } |
94 }; | 56 } |
95 } | 57 }); |
96 } | 58 }); |
97 | 59 } |
98 | 60 |
99 void testRequestResponseServerCloses( | 61 }); |
100 int totalConnections, int closeStatus, String closeReason) { | 62 } |
101 ReceivePort keepAlive = new ReceivePort(); | 63 |
102 HttpServer server = createServer(backlog: totalConnections); | 64 |
103 | 65 void testRequestResponseServerCloses( |
104 // Create a web socket handler and set is as the HTTP server default | 66 int totalConnections, int closeStatus, String closeReason) { |
105 // handler. | 67 HttpServer.bind().then((server) { |
| 68 |
106 int closeCount = 0; | 69 int closeCount = 0; |
107 WebSocketHandler wsHandler = new WebSocketHandler(); | 70 server.transform(new WebSocketTransformer()).listen((webSocket) { |
108 wsHandler.onOpen = (WebSocketConnection conn) { | |
109 String messageText = "Hello, world!"; | 71 String messageText = "Hello, world!"; |
110 int messageCount = 0; | 72 int messageCount = 0; |
111 conn.onMessage = (Object message) { | 73 webSocket.listen((event) { |
112 messageCount++; | 74 if (event is MessageEvent) { |
113 if (messageCount < 10) { | 75 messageCount++; |
114 Expect.equals(messageText, message); | 76 if (messageCount < 10) { |
115 conn.send(message); | 77 Expect.equals(messageText, event.data); |
116 } else { | 78 webSocket.send(event.data); |
117 conn.close(closeStatus, closeReason); | 79 } else { |
118 } | 80 webSocket.close(closeStatus, closeReason); |
119 }; | 81 } |
120 conn.onClosed = (status, reason) { | 82 } else if (event is CloseEvent) { |
121 Expect.equals(closeStatus == null | 83 Expect.equals(closeStatus == null |
122 ? WebSocketStatus.NO_STATUS_RECEIVED | 84 ? WebSocketStatus.NO_STATUS_RECEIVED |
123 : closeStatus, status); | 85 : closeStatus, event.code); |
124 Expect.equals("", reason); | 86 Expect.equals("", event.reason); |
125 closeCount++; | 87 closeCount++; |
126 if (closeCount == totalConnections) { | 88 if (closeCount == totalConnections) { |
127 client.shutdown(); | 89 server.close(); |
128 server.close(); | 90 } |
129 keepAlive.close(); | 91 } |
130 } | 92 }); |
131 }; | 93 webSocket.send(messageText); |
132 conn.send(messageText); | 94 }); |
133 }; | |
134 server.defaultRequestHandler = wsHandler.onRequest; | |
135 | 95 |
136 for (int i = 0; i < totalConnections; i++) { | 96 for (int i = 0; i < totalConnections; i++) { |
137 WebSocketClientConnection wsconn = createClient(server.port); | 97 WebSocket.connect("ws://127.0.0.1:${server.port}/") |
138 wsconn.onMessage = (message) => wsconn.send(message); | 98 .then((webSocket) { |
139 wsconn.onClosed = (status, reason) { | 99 webSocket.listen((event) { |
140 Expect.equals(closeStatus == null | 100 if (event is MessageEvent) { |
141 ? WebSocketStatus.NO_STATUS_RECEIVED | 101 webSocket.send(event.data); |
142 : closeStatus, status); | 102 } else if (event is CloseEvent) { |
143 Expect.equals(closeReason == null ? "" : closeReason, reason); | 103 Expect.equals(closeStatus == null |
144 }; | 104 ? WebSocketStatus.NO_STATUS_RECEIVED |
145 } | 105 : closeStatus, event.code); |
146 } | 106 Expect.equals( |
147 | 107 closeReason == null ? "" : closeReason, event.reason); |
148 | 108 } |
149 void testMessageLength(int messageLength) { | 109 }); |
150 HttpServer server = createServer(backlog: 1); | 110 }); |
151 bool serverReceivedMessage = false; | 111 } |
152 bool clientReceivedMessage = false; | 112 |
153 | 113 }); |
154 // Create a web socket handler and set is as the HTTP server default | 114 } |
155 // handler. | 115 |
| 116 |
| 117 void testMessageLength(int messageLength) { |
| 118 HttpServer.bind().then((server) { |
| 119 |
156 Uint8List originalMessage = new Uint8List(messageLength); | 120 Uint8List originalMessage = new Uint8List(messageLength); |
157 WebSocketHandler wsHandler = new WebSocketHandler(); | 121 server.transform(new WebSocketTransformer()).listen((webSocket) { |
158 wsHandler.onOpen = (WebSocketConnection conn) { | 122 webSocket.listen((event) { |
159 conn.onMessage = (Object message) { | 123 if (event is MessageEvent) { |
160 serverReceivedMessage = true; | 124 Expect.listEquals(originalMessage, event.data); |
161 Expect.listEquals(originalMessage, message); | 125 webSocket.send(event.data); |
162 conn.send(message); | 126 } else if (event is CloseEvent) { |
163 }; | 127 } |
164 conn.onClosed = (status, reason) { | 128 }); |
165 }; | 129 }); |
166 }; | 130 |
167 server.defaultRequestHandler = wsHandler.onRequest; | 131 WebSocket.connect("ws://127.0.0.1:${server.port}/") |
168 | 132 .then((webSocket) { |
169 WebSocketClientConnection wsconn = createClient(server.port); | 133 webSocket.listen((event) { |
170 wsconn.onMessage = (message) { | 134 if (event is MessageEvent) { |
171 clientReceivedMessage = true; | 135 Expect.listEquals(originalMessage, event.data); |
172 Expect.listEquals(originalMessage, message); | 136 webSocket.close(); |
173 wsconn.close(); | 137 } else if (event is CloseEvent) { |
174 }; | 138 server.close(); |
175 wsconn.onClosed = (status, reason) { | 139 } |
176 Expect.isTrue(serverReceivedMessage); | 140 }); |
177 Expect.isTrue(clientReceivedMessage); | 141 webSocket.send(originalMessage); |
178 client.shutdown(); | 142 }); |
| 143 |
| 144 }); |
| 145 } |
| 146 |
| 147 |
| 148 void testNoUpgrade() { |
| 149 HttpServer.bind().then((server) { |
| 150 |
| 151 // Create a server which always responds with NOT_FOUND. |
| 152 server.listen((request) { |
| 153 request.response.statusCode = HttpStatus.NOT_FOUND; |
| 154 request.response.close(); |
| 155 }); |
| 156 |
| 157 WebSocket.connect("ws://127.0.0.1:${server.port}/").catchError((error) { |
179 server.close(); | 158 server.close(); |
180 }; | 159 }); |
181 wsconn.onOpen = () { | 160 |
182 wsconn.send(originalMessage); | 161 }); |
183 }; | 162 } |
184 } | 163 |
185 | 164 |
186 | 165 void testUsePOST() { |
187 void testNoUpgrade() { | 166 HttpServer.bind().then((server) { |
188 HttpServer server = createServer(backlog: 5); | 167 |
189 | 168 var errorPort = new ReceivePort(); |
190 // Create a server which always responds with a redirect. | 169 server.transform(new WebSocketTransformer()).listen((webSocket) { |
191 server.defaultRequestHandler = (request, response) { | 170 Expect.fail("No connection expected"); |
192 response.statusCode = HttpStatus.MOVED_PERMANENTLY; | 171 }, onError: (e) { |
193 response.outputStream.close(); | 172 errorPort.close(); |
194 }; | 173 }); |
195 | 174 |
196 WebSocketClientConnection wsconn = createClient(server.port, | 175 HttpClient client = new HttpClient(); |
197 followRedirects: false); | 176 client.post("127.0.0.1", server.port, "/") |
198 wsconn.onNoUpgrade = (response) { | 177 .then((request) => request.close()) |
199 Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode); | 178 .then((response) { |
200 client.shutdown(); | 179 Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode); |
201 server.close(); | 180 client.close(); |
202 }; | 181 server.close(); |
203 } | 182 }); |
204 | 183 |
205 | 184 }); |
206 void testUsePOST() { | 185 } |
207 HttpServer server = createServer(backlog: 5); | 186 |
208 | 187 |
209 // Create a web socket handler and set is as the HTTP server default | 188 class WebSocketInfo { |
210 // handler. | 189 int messageCount = 0; |
| 190 } |
| 191 |
| 192 |
| 193 void testW3CInterface( |
| 194 int totalConnections, int closeStatus, String closeReason) { |
| 195 HttpServer.bind().then((server) { |
| 196 |
211 int closeCount = 0; | 197 int closeCount = 0; |
212 WebSocketHandler wsHandler = new WebSocketHandler(); | 198 server.transform(new WebSocketTransformer()).listen((webSocket) { |
213 wsHandler.onOpen = (WebSocketConnection conn) { | |
214 Expect.fail("No connection expected"); | |
215 }; | |
216 server.defaultRequestHandler = wsHandler.onRequest; | |
217 | |
218 WebSocketClientConnection wsconn = createClient(server.port, | |
219 method: "POST"); | |
220 wsconn.onNoUpgrade = (response) { | |
221 Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode); | |
222 client.shutdown(); | |
223 server.close(); | |
224 }; | |
225 } | |
226 | |
227 | |
228 void testHashCode(int totalConnections) { | |
229 ReceivePort keepAlive = new ReceivePort(); | |
230 HttpServer server = createServer(backlog: totalConnections); | |
231 Map connections = new Map(); | |
232 | |
233 void handleMessage(conn, message) { | |
234 var info = connections[conn]; | |
235 Expect.isNotNull(info); | |
236 info.messageCount++; | |
237 if (info.messageCount < 10) { | |
238 conn.send(message); | |
239 } else { | |
240 conn.close(); | |
241 } | |
242 } | |
243 | |
244 // Create a web socket handler and set is as the HTTP server default | |
245 // handler. | |
246 int closeCount = 0; | |
247 WebSocketHandler wsHandler = new WebSocketHandler(); | |
248 wsHandler.onOpen = (WebSocketConnection conn) { | |
249 connections[conn] = new WebSocketInfo(); | |
250 String messageText = "Hello, world!"; | |
251 conn.onMessage = (Object message) { | |
252 handleMessage(conn, message); | |
253 }; | |
254 conn.onClosed = (status, reason) { | |
255 closeCount++; | |
256 var info = connections[conn]; | |
257 Expect.equals(10, info.messageCount); | |
258 if (closeCount == totalConnections) { | |
259 client.shutdown(); | |
260 server.close(); | |
261 keepAlive.close(); | |
262 } | |
263 }; | |
264 conn.send(messageText); | |
265 }; | |
266 server.defaultRequestHandler = wsHandler.onRequest; | |
267 | |
268 for (int i = 0; i < totalConnections; i++) { | |
269 WebSocketClientConnection wsconn = createClient(server.port); | |
270 wsconn.onMessage = (message) => wsconn.send(message); | |
271 } | |
272 } | |
273 | |
274 | |
275 void testW3CInterface( | |
276 int totalConnections, int closeStatus, String closeReason) { | |
277 HttpServer server = createServer(backlog: totalConnections); | |
278 | |
279 // Create a web socket handler and set is as the HTTP server default | |
280 // handler. | |
281 int closeCount = 0; | |
282 WebSocketHandler wsHandler = new WebSocketHandler(); | |
283 wsHandler.onOpen = (WebSocketConnection conn) { | |
284 String messageText = "Hello, world!"; | 199 String messageText = "Hello, world!"; |
285 int messageCount = 0; | 200 int messageCount = 0; |
286 conn.onMessage = (Object message) { | 201 webSocket.listen((event) { |
287 messageCount++; | 202 if (event is MessageEvent) { |
288 if (messageCount < 10) { | 203 messageCount++; |
289 Expect.equals(messageText, message); | 204 if (messageCount < 10) { |
290 conn.send(message); | 205 Expect.equals(messageText, event.data); |
291 } else { | 206 webSocket.send(event.data); |
292 conn.close(closeStatus, closeReason); | 207 } else { |
293 } | 208 webSocket.close(closeStatus, closeReason); |
294 }; | 209 } |
295 conn.onClosed = (status, reason) { | 210 } else if (event is CloseEvent) { |
296 Expect.equals(closeStatus, status); | 211 Expect.equals(closeStatus, event.code); |
297 Expect.equals("", reason); | 212 Expect.equals("", event.reason); |
298 closeCount++; | 213 closeCount++; |
299 if (closeCount == totalConnections) { | 214 if (closeCount == totalConnections) { |
300 server.close(); | 215 server.close(); |
301 } | 216 } |
302 }; | 217 } |
303 conn.send(messageText); | 218 }); |
304 }; | 219 webSocket.send(messageText); |
305 server.defaultRequestHandler = wsHandler.onRequest; | 220 }); |
306 | 221 |
307 void webSocketConnection() { | 222 void webSocketConnection() { |
308 bool onopenCalled = false; | 223 bool onopenCalled = false; |
309 int onmessageCalled = 0; | 224 int onmessageCalled = 0; |
310 bool oncloseCalled = false; | 225 bool oncloseCalled = false; |
311 | 226 |
312 var websocket = | 227 WebSocket.connect("ws://127.0.0.1:${server.port}").then((webSocket) { |
313 new WebSocket('${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}'); | |
314 Expect.equals(WebSocket.CONNECTING, websocket.readyState); | |
315 websocket.onopen = () { | |
316 Expect.isFalse(onopenCalled); | 228 Expect.isFalse(onopenCalled); |
317 Expect.equals(0, onmessageCalled); | 229 Expect.equals(0, onmessageCalled); |
318 Expect.isFalse(oncloseCalled); | 230 Expect.isFalse(oncloseCalled); |
319 onopenCalled = true; | 231 onopenCalled = true; |
320 Expect.equals(WebSocket.OPEN, websocket.readyState); | 232 Expect.equals(WebSocket.OPEN, webSocket.readyState); |
321 }; | 233 webSocket.listen((event) { |
322 websocket.onmessage = (event) { | 234 if (event is MessageEvent) { |
323 onmessageCalled++; | 235 onmessageCalled++; |
324 Expect.isTrue(onopenCalled); | 236 Expect.isTrue(onopenCalled); |
325 Expect.isFalse(oncloseCalled); | 237 Expect.isFalse(oncloseCalled); |
326 Expect.equals(WebSocket.OPEN, websocket.readyState); | 238 Expect.equals(WebSocket.OPEN, webSocket.readyState); |
327 websocket.send(event.data); | 239 webSocket.send(event.data); |
328 }; | 240 } else if (event is CloseEvent) { |
329 websocket.onclose = (event) { | 241 Expect.isTrue(onopenCalled); |
330 Expect.isTrue(onopenCalled); | 242 Expect.equals(10, onmessageCalled); |
331 Expect.equals(10, onmessageCalled); | 243 Expect.isFalse(oncloseCalled); |
332 Expect.isFalse(oncloseCalled); | 244 oncloseCalled = true; |
333 oncloseCalled = true; | 245 Expect.isTrue(event.wasClean); |
334 Expect.isTrue(event.wasClean); | 246 Expect.equals(3002, event.code); |
335 Expect.equals(3002, event.code); | 247 Expect.equals("Got tired", event.reason); |
336 Expect.equals("Got tired", event.reason); | 248 Expect.equals(WebSocket.CLOSED, webSocket.readyState); |
337 Expect.equals(WebSocket.CLOSED, websocket.readyState); | 249 } |
338 }; | 250 }); |
| 251 }); |
339 } | 252 } |
340 | 253 |
341 for (int i = 0; i < totalConnections; i++) { | 254 for (int i = 0; i < totalConnections; i++) { |
342 webSocketConnection(); | 255 webSocketConnection(); |
343 } | 256 } |
344 } | 257 |
345 | 258 }); |
346 | |
347 runTests() { | |
348 testRequestResponseClientCloses(2, null, null); | |
349 testRequestResponseClientCloses(2, 3001, null); | |
350 testRequestResponseClientCloses(2, 3002, "Got tired"); | |
351 testRequestResponseServerCloses(2, null, null); | |
352 testRequestResponseServerCloses(2, 3001, null); | |
353 testRequestResponseServerCloses(2, 3002, "Got tired"); | |
354 testMessageLength(125); | |
355 testMessageLength(126); | |
356 testMessageLength(127); | |
357 testMessageLength(65535); | |
358 testMessageLength(65536); | |
359 testNoUpgrade(); | |
360 testUsePOST(); | |
361 testHashCode(2); | |
362 testW3CInterface(2, 3002, "Got tired"); | |
363 } | |
364 } | |
365 | |
366 | |
367 void initializeSSL() { | |
368 var testPkcertDatabase = | |
369 new Path(new Options().script).directoryPath.append("pkcert/"); | |
370 SecureSocket.initialize(database: testPkcertDatabase.toNativePath(), | |
371 password: "dartdart"); | |
372 } | 259 } |
373 | 260 |
374 | 261 |
375 main() { | 262 main() { |
376 new SecurityConfiguration(secure: false).runTests(); | 263 testRequestResponseClientCloses(2, null, null); |
377 initializeSSL(); | 264 testRequestResponseClientCloses(2, 3001, null); |
378 new SecurityConfiguration(secure: true).runTests(); | 265 testRequestResponseClientCloses(2, 3002, "Got tired"); |
379 } | 266 testRequestResponseServerCloses(2, null, null); |
| 267 testRequestResponseServerCloses(2, 3001, null); |
| 268 testRequestResponseServerCloses(2, 3002, "Got tired"); |
| 269 testMessageLength(125); |
| 270 testMessageLength(126); |
| 271 testMessageLength(127); |
| 272 testMessageLength(65535); |
| 273 testMessageLength(65536); |
| 274 testNoUpgrade(); |
| 275 testUsePOST(); |
| 276 |
| 277 testW3CInterface(2, 3002, "Got tired"); |
| 278 } |
OLD | NEW |