| OLD | NEW |
| 1 // Copyright (c) 2013, 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 // VMOptions= | 5 // VMOptions= |
| 6 // VMOptions=--short_socket_read | 6 // VMOptions=--short_socket_read |
| 7 // VMOptions=--short_socket_write | 7 // VMOptions=--short_socket_write |
| 8 // VMOptions=--short_socket_read --short_socket_write | 8 // VMOptions=--short_socket_read --short_socket_write |
| 9 | 9 |
| 10 import "dart:async"; | 10 import "dart:async"; |
| 11 import "dart:convert"; | 11 import "dart:convert"; |
| 12 import "dart:io"; | 12 import "dart:io"; |
| 13 import "dart:typed_data"; | 13 import "dart:typed_data"; |
| 14 | 14 |
| 15 import "package:async_helper/async_helper.dart"; | 15 import "package:async_helper/async_helper.dart"; |
| 16 import "package:convert/convert.dart"; | 16 import "package:convert/convert.dart"; |
| 17 import "package:crypto/crypto.dart"; | 17 import "package:crypto/crypto.dart"; |
| 18 import "package:expect/expect.dart"; | 18 import "package:expect/expect.dart"; |
| 19 import "package:path/path.dart"; | 19 import "package:path/path.dart"; |
| 20 | 20 |
| 21 const WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 21 const WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
| 22 | 22 |
| 23 const String HOST_NAME = 'localhost'; | 23 const String HOST_NAME = 'localhost'; |
| 24 | 24 |
| 25 String localFile(path) => Platform.script.resolve(path).toFilePath(); | 25 String localFile(path) => Platform.script.resolve(path).toFilePath(); |
| 26 | 26 |
| 27 SecurityContext serverContext = new SecurityContext() | 27 SecurityContext serverContext = new SecurityContext() |
| 28 ..useCertificateChain(localFile('certificates/server_chain.pem')) | 28 ..useCertificateChain(localFile('certificates/server_chain.pem')) |
| 29 ..usePrivateKey(localFile('certificates/server_key.pem'), | 29 ..usePrivateKey(localFile('certificates/server_key.pem'), |
| 30 password: 'dartdart'); | 30 password: 'dartdart'); |
| 31 | 31 |
| 32 SecurityContext clientContext = new SecurityContext() | 32 SecurityContext clientContext = new SecurityContext() |
| 33 ..setTrustedCertificates(localFile('certificates/trusted_certs.pem')); | 33 ..setTrustedCertificates(localFile('certificates/trusted_certs.pem')); |
| 34 | 34 |
| 35 /** | 35 /** |
| 36 * A SecurityConfiguration lets us run the tests over HTTP or HTTPS. | 36 * A SecurityConfiguration lets us run the tests over HTTP or HTTPS. |
| 37 */ | 37 */ |
| 38 class SecurityConfiguration { | 38 class SecurityConfiguration { |
| 39 final bool secure; | 39 final bool secure; |
| 40 | 40 |
| 41 SecurityConfiguration({bool this.secure}); | 41 SecurityConfiguration({bool this.secure}); |
| 42 | 42 |
| 43 Future<HttpServer> createServer({int backlog: 0}) => | 43 Future<HttpServer> createServer({int backlog: 0}) => secure |
| 44 secure ? HttpServer.bindSecure(HOST_NAME, | 44 ? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog) |
| 45 0, | 45 : HttpServer.bind(HOST_NAME, 0, backlog: backlog); |
| 46 serverContext, | |
| 47 backlog: backlog) | |
| 48 : HttpServer.bind(HOST_NAME, | |
| 49 0, | |
| 50 backlog: backlog); | |
| 51 | 46 |
| 52 Future<WebSocket> createClient(int port) => | 47 Future<WebSocket> createClient(int port) => |
| 53 // TODO(whesse): Add client context argument to WebSocket.connect | 48 // TODO(whesse): Add client context argument to WebSocket.connect |
| 54 WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/'); | 49 WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/'); |
| 55 | 50 |
| 56 checkCloseStatus(webSocket, closeStatus, closeReason) { | 51 checkCloseStatus(webSocket, closeStatus, closeReason) { |
| 57 Expect.equals(closeStatus == null ? WebSocketStatus.NO_STATUS_RECEIVED | 52 Expect.equals( |
| 58 : closeStatus, webSocket.closeCode); | 53 closeStatus == null ? WebSocketStatus.NO_STATUS_RECEIVED : closeStatus, |
| 59 Expect.equals(closeReason == null ? "" | 54 webSocket.closeCode); |
| 60 : closeReason, webSocket.closeReason); | 55 Expect.equals( |
| 56 closeReason == null ? "" : closeReason, webSocket.closeReason); |
| 61 } | 57 } |
| 62 | 58 |
| 63 void testRequestResponseClientCloses(int totalConnections, | 59 void testRequestResponseClientCloses(int totalConnections, int closeStatus, |
| 64 int closeStatus, | 60 String closeReason, int numberOfMessages) { |
| 65 String closeReason, | 61 assert(numberOfMessages >= 1); |
| 66 int numberOfMessages) { | |
| 67 assert (numberOfMessages >= 1); | |
| 68 | 62 |
| 69 asyncStart(); | 63 asyncStart(); |
| 70 createServer().then((server) { | 64 createServer().then((server) { |
| 71 server.transform(new WebSocketTransformer()).listen((webSocket) { | 65 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 72 asyncStart(); | 66 asyncStart(); |
| 73 webSocket.listen( | 67 webSocket.listen(webSocket.add, onDone: () { |
| 74 webSocket.add, | 68 checkCloseStatus(webSocket, closeStatus, closeReason); |
| 75 onDone: () { | |
| 76 checkCloseStatus(webSocket, closeStatus, closeReason); | |
| 77 asyncEnd(); | |
| 78 }); | |
| 79 }, onDone: () { | |
| 80 asyncEnd(); | 69 asyncEnd(); |
| 81 }); | 70 }); |
| 71 }, onDone: () { |
| 72 asyncEnd(); |
| 73 }); |
| 82 | 74 |
| 83 int closeCount = 0; | 75 int closeCount = 0; |
| 84 String messageText = "Hello, world!"; | 76 String messageText = "Hello, world!"; |
| 85 for (int i = 0; i < totalConnections; i++) { | 77 for (int i = 0; i < totalConnections; i++) { |
| 86 asyncStart(); | 78 asyncStart(); |
| 87 createClient(server.port).then((webSocket) { | 79 createClient(server.port).then((webSocket) { |
| 88 webSocket.add(messageText); | 80 webSocket.add(messageText); |
| 89 webSocket.listen( | 81 webSocket.listen((message) { |
| 90 (message) { | 82 numberOfMessages--; |
| 91 numberOfMessages--; | 83 Expect.equals(messageText, message); |
| 92 Expect.equals(messageText, message); | |
| 93 | 84 |
| 94 if (numberOfMessages > 0) { | 85 if (numberOfMessages > 0) { |
| 95 webSocket.add(message); | 86 webSocket.add(message); |
| 96 } else { | 87 } else { |
| 97 webSocket.close(closeStatus, closeReason); | 88 webSocket.close(closeStatus, closeReason); |
| 98 } | 89 } |
| 99 }, | 90 }, onDone: () { |
| 100 onDone: () { | 91 checkCloseStatus(webSocket, closeStatus, closeReason); |
| 101 checkCloseStatus(webSocket, closeStatus, closeReason); | 92 closeCount++; |
| 102 closeCount++; | 93 if (closeCount == totalConnections) { |
| 103 if (closeCount == totalConnections) { | 94 server.close(); |
| 104 server.close(); | 95 } |
| 105 } | 96 asyncEnd(); |
| 106 asyncEnd(); | |
| 107 }); | |
| 108 }); | 97 }); |
| 98 }); |
| 109 } | 99 } |
| 110 }); | 100 }); |
| 111 } | 101 } |
| 112 | 102 |
| 113 void testRequestResponseServerCloses(int totalConnections, | 103 void testRequestResponseServerCloses( |
| 114 int closeStatus, | 104 int totalConnections, int closeStatus, String closeReason) { |
| 115 String closeReason) { | |
| 116 createServer().then((server) { | 105 createServer().then((server) { |
| 117 int closeCount = 0; | 106 int closeCount = 0; |
| 118 server.transform(new WebSocketTransformer()).listen((webSocket) { | 107 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 119 String messageText = "Hello, world!"; | 108 String messageText = "Hello, world!"; |
| 120 int messageCount = 0; | 109 int messageCount = 0; |
| 121 webSocket.listen( | 110 webSocket.listen((message) { |
| 122 (message) { | 111 messageCount++; |
| 123 messageCount++; | 112 if (messageCount < 10) { |
| 124 if (messageCount < 10) { | 113 Expect.equals(messageText, message); |
| 125 Expect.equals(messageText, message); | 114 webSocket.add(message); |
| 126 webSocket.add(message); | 115 } else { |
| 127 } else { | 116 webSocket.close(closeStatus, closeReason); |
| 128 webSocket.close(closeStatus, closeReason); | 117 } |
| 129 } | 118 }, onDone: () { |
| 130 }, | 119 checkCloseStatus(webSocket, closeStatus, closeReason); |
| 131 onDone: () { | 120 closeCount++; |
| 132 checkCloseStatus(webSocket, closeStatus, closeReason); | 121 if (closeCount == totalConnections) { |
| 133 closeCount++; | 122 server.close(); |
| 134 if (closeCount == totalConnections) { | 123 } |
| 135 server.close(); | 124 }); |
| 136 } | |
| 137 }); | |
| 138 webSocket.add(messageText); | 125 webSocket.add(messageText); |
| 139 }); | 126 }); |
| 140 | 127 |
| 141 for (int i = 0; i < totalConnections; i++) { | 128 for (int i = 0; i < totalConnections; i++) { |
| 142 createClient(server.port).then((webSocket) { | 129 createClient(server.port).then((webSocket) { |
| 143 webSocket.listen( | 130 webSocket.listen(webSocket.add, onDone: () { |
| 144 webSocket.add, | 131 checkCloseStatus(webSocket, closeStatus, closeReason); |
| 145 onDone: () { | 132 }); |
| 146 checkCloseStatus(webSocket, closeStatus, closeReason); | 133 }); |
| 147 }); | |
| 148 }); | |
| 149 } | 134 } |
| 150 }); | 135 }); |
| 151 } | 136 } |
| 152 | 137 |
| 153 | |
| 154 void testMessageLength(int messageLength) { | 138 void testMessageLength(int messageLength) { |
| 155 createServer().then((server) { | 139 createServer().then((server) { |
| 156 Uint8List originalMessage = new Uint8List(messageLength); | 140 Uint8List originalMessage = new Uint8List(messageLength); |
| 157 server.transform(new WebSocketTransformer()).listen((webSocket) { | 141 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 158 webSocket.listen( | 142 webSocket.listen((message) { |
| 159 (message) { | 143 Expect.listEquals(originalMessage, message); |
| 160 Expect.listEquals(originalMessage, message); | 144 webSocket.add(message); |
| 161 webSocket.add(message); | 145 }); |
| 162 }); | |
| 163 }); | 146 }); |
| 164 | 147 |
| 165 createClient(server.port).then((webSocket) { | 148 createClient(server.port).then((webSocket) { |
| 166 webSocket.listen( | 149 webSocket.listen((message) { |
| 167 (message) { | 150 Expect.listEquals(originalMessage, message); |
| 168 Expect.listEquals(originalMessage, message); | 151 webSocket.close(); |
| 169 webSocket.close(); | 152 }, onDone: server.close); |
| 170 }, | |
| 171 onDone: server.close); | |
| 172 webSocket.add(originalMessage); | 153 webSocket.add(originalMessage); |
| 173 }); | 154 }); |
| 174 }); | 155 }); |
| 175 } | 156 } |
| 176 | 157 |
| 177 | |
| 178 void testCloseNoListen() { | 158 void testCloseNoListen() { |
| 179 createServer().then((server) { | 159 createServer().then((server) { |
| 180 server.transform(new WebSocketTransformer()).listen((webSocket) { | 160 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 181 server.close(); | 161 server.close(); |
| 182 webSocket.close(); | 162 webSocket.close(); |
| 183 }); | 163 }); |
| 184 | 164 |
| 185 createClient(server.port).then((webSocket) { | 165 createClient(server.port).then((webSocket) { |
| 186 webSocket.close(); | 166 webSocket.close(); |
| 187 }); | 167 }); |
| 188 }); | 168 }); |
| 189 } | 169 } |
| 190 | 170 |
| 191 | |
| 192 void testCancelThenClose() { | 171 void testCancelThenClose() { |
| 193 createServer().then((server) { | 172 createServer().then((server) { |
| 194 server.transform(new WebSocketTransformer()).listen((webSocket) { | 173 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 195 webSocket.listen(null).cancel(); | 174 webSocket.listen(null).cancel(); |
| 196 webSocket.close(); | 175 webSocket.close(); |
| 197 server.close(); | 176 server.close(); |
| 198 }); | 177 }); |
| 199 | 178 |
| 200 createClient(server.port).then((webSocket) { | 179 createClient(server.port).then((webSocket) { |
| 201 webSocket.close(); | 180 webSocket.close(); |
| 202 }); | 181 }); |
| 203 }); | 182 }); |
| 204 } | 183 } |
| 205 | 184 |
| 206 void testCloseThenCancel() { | 185 void testCloseThenCancel() { |
| 207 createServer().then((server) { | 186 createServer().then((server) { |
| 208 server.transform(new WebSocketTransformer()).listen((webSocket) { | 187 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 209 var subscription = webSocket.listen(null); | 188 var subscription = webSocket.listen(null); |
| 210 webSocket.close(); | 189 webSocket.close(); |
| 211 subscription.cancel(); | 190 subscription.cancel(); |
| 212 server.close(); | 191 server.close(); |
| 213 }); | 192 }); |
| 214 | 193 |
| 215 createClient(server.port).then((webSocket) { | 194 createClient(server.port).then((webSocket) { |
| 216 webSocket.close(); | 195 webSocket.close(); |
| 217 }); | 196 }); |
| 218 }); | 197 }); |
| 219 } | 198 } |
| 220 | 199 |
| 221 | |
| 222 void testListenAfterClose() { | 200 void testListenAfterClose() { |
| 223 createServer().then((server) { | 201 createServer().then((server) { |
| 224 server.transform(new WebSocketTransformer()).listen((webSocket) { | 202 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 225 server.close(); | 203 server.close(); |
| 226 webSocket.close(); | 204 webSocket.close(); |
| 227 Expect.throws(() => webSocket.drain()); | 205 Expect.throws(() => webSocket.drain()); |
| 228 }); | 206 }); |
| 229 | 207 |
| 230 createClient(server.port).then((webSocket) { | 208 createClient(server.port).then((webSocket) { |
| 231 webSocket.close(); | 209 webSocket.close(); |
| 232 Expect.throws(() => webSocket.drain()); | 210 Expect.throws(() => webSocket.drain()); |
| 233 }); | 211 }); |
| 234 }); | 212 }); |
| 235 } | 213 } |
| 236 | 214 |
| 237 | |
| 238 void testDoubleCloseClient() { | 215 void testDoubleCloseClient() { |
| 239 createServer().then((server) { | 216 createServer().then((server) { |
| 240 server.transform(new WebSocketTransformer()).listen((webSocket) { | 217 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 241 server.close(); | 218 server.close(); |
| 242 webSocket.listen((_) { }, onDone: webSocket.close); | 219 webSocket.listen((_) {}, onDone: webSocket.close); |
| 243 }); | 220 }); |
| 244 | 221 |
| 245 createClient(server.port).then((webSocket) { | 222 createClient(server.port).then((webSocket) { |
| 246 webSocket.listen((_) { }, onDone: webSocket.close); | 223 webSocket.listen((_) {}, onDone: webSocket.close); |
| 247 webSocket.close(); | 224 webSocket.close(); |
| 248 }); | 225 }); |
| 249 }); | 226 }); |
| 250 } | 227 } |
| 251 | 228 |
| 252 | |
| 253 void testDoubleCloseServer() { | 229 void testDoubleCloseServer() { |
| 254 createServer().then((server) { | 230 createServer().then((server) { |
| 255 server.transform(new WebSocketTransformer()).listen((webSocket) { | 231 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 256 server.close(); | 232 server.close(); |
| 257 webSocket.listen((_) { }, onDone: webSocket.close); | 233 webSocket.listen((_) {}, onDone: webSocket.close); |
| 258 webSocket.close(); | 234 webSocket.close(); |
| 259 }); | 235 }); |
| 260 | 236 |
| 261 createClient(server.port).then((webSocket) { | 237 createClient(server.port).then((webSocket) { |
| 262 webSocket.listen((_) { }, onDone: webSocket.close); | 238 webSocket.listen((_) {}, onDone: webSocket.close); |
| 263 }); | 239 }); |
| 264 }); | 240 }); |
| 265 } | 241 } |
| 266 | 242 |
| 267 | |
| 268 void testImmediateCloseServer() { | 243 void testImmediateCloseServer() { |
| 269 createServer().then((server) { | 244 createServer().then((server) { |
| 270 server.listen((request) { | 245 server.listen((request) { |
| 271 WebSocketTransformer.upgrade(request) | 246 WebSocketTransformer.upgrade(request).then((webSocket) { |
| 272 .then((webSocket) { | 247 webSocket.listen((_) { |
| 273 webSocket.listen( | 248 Expect.fail("Unexpected message"); |
| 274 (_) { Expect.fail("Unexpected message"); }, | 249 }, onDone: server.close); |
| 275 onDone: server.close); | 250 webSocket.close(); |
| 276 webSocket.close(); | 251 }); |
| 277 }); | |
| 278 }); | 252 }); |
| 279 | 253 |
| 280 createClient(server.port).then((webSocket) { | 254 createClient(server.port).then((webSocket) { |
| 281 webSocket.listen( | 255 webSocket.listen((_) { |
| 282 (_) { Expect.fail("Unexpected message"); }, | 256 Expect.fail("Unexpected message"); |
| 283 onDone: webSocket.close); | 257 }, onDone: webSocket.close); |
| 284 }); | 258 }); |
| 285 }); | 259 }); |
| 286 } | 260 } |
| 287 | 261 |
| 288 | |
| 289 void testImmediateCloseClient() { | 262 void testImmediateCloseClient() { |
| 290 createServer().then((server) { | 263 createServer().then((server) { |
| 291 server.listen((request) { | 264 server.listen((request) { |
| 292 WebSocketTransformer.upgrade(request) | 265 WebSocketTransformer.upgrade(request).then((webSocket) { |
| 293 .then((webSocket) { | 266 webSocket.listen((_) { |
| 294 webSocket.listen( | 267 Expect.fail("Unexpected message"); |
| 295 (_) { Expect.fail("Unexpected message"); }, | 268 }, onDone: () { |
| 296 onDone: () { | 269 server.close(); |
| 297 server.close(); | 270 webSocket.close(); |
| 298 webSocket.close(); | 271 }); |
| 299 }); | 272 }); |
| 300 }); | |
| 301 }); | 273 }); |
| 302 | 274 |
| 303 createClient(server.port).then((webSocket) { | 275 createClient(server.port).then((webSocket) { |
| 304 webSocket.listen( | 276 webSocket.listen((_) { |
| 305 (_) { Expect.fail("Unexpected message"); }, | 277 Expect.fail("Unexpected message"); |
| 306 onDone: webSocket.close); | 278 }, onDone: webSocket.close); |
| 307 webSocket.close(); | 279 webSocket.close(); |
| 308 }); | 280 }); |
| 309 }); | 281 }); |
| 310 } | 282 } |
| 311 | 283 |
| 312 | |
| 313 void testNoUpgrade() { | 284 void testNoUpgrade() { |
| 314 createServer().then((server) { | 285 createServer().then((server) { |
| 315 // Create a server which always responds with NOT_FOUND. | 286 // Create a server which always responds with NOT_FOUND. |
| 316 server.listen((request) { | 287 server.listen((request) { |
| 317 request.response.statusCode = HttpStatus.NOT_FOUND; | 288 request.response.statusCode = HttpStatus.NOT_FOUND; |
| 318 request.response.close(); | 289 request.response.close(); |
| 319 }); | 290 }); |
| 320 | 291 |
| 321 createClient(server.port).catchError((error) { | 292 createClient(server.port).catchError((error) { |
| 322 server.close(); | 293 server.close(); |
| 323 }); | 294 }); |
| 324 }); | 295 }); |
| 325 } | 296 } |
| 326 | 297 |
| 327 | |
| 328 void testUsePOST() { | 298 void testUsePOST() { |
| 329 asyncStart(); | 299 asyncStart(); |
| 330 createServer().then((server) { | 300 createServer().then((server) { |
| 331 server.transform(new WebSocketTransformer()).listen((webSocket) { | 301 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 332 Expect.fail("No connection expected"); | 302 Expect.fail("No connection expected"); |
| 333 }, onError: (e) { | 303 }, onError: (e) { |
| 334 asyncEnd(); | 304 asyncEnd(); |
| 335 }); | 305 }); |
| 336 | 306 |
| 337 HttpClient client = new HttpClient(); | 307 HttpClient client = new HttpClient(); |
| 338 client.postUrl(Uri.parse( | 308 client |
| 339 "${secure ? 'https:' : 'http:'}//$HOST_NAME:${server.port}/")) | 309 .postUrl(Uri.parse( |
| 340 .then((request) => request.close()) | 310 "${secure ? 'https:' : 'http:'}//$HOST_NAME:${server.port}/")) |
| 341 .then((response) { | 311 .then((request) => request.close()) |
| 342 Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode); | 312 .then((response) { |
| 343 client.close(); | 313 Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode); |
| 344 server.close(); | 314 client.close(); |
| 345 }); | 315 server.close(); |
| 316 }); |
| 346 }); | 317 }); |
| 347 } | 318 } |
| 348 | 319 |
| 349 void testConnections(int totalConnections, | 320 void testConnections( |
| 350 int closeStatus, | 321 int totalConnections, int closeStatus, String closeReason) { |
| 351 String closeReason) { | |
| 352 createServer().then((server) { | 322 createServer().then((server) { |
| 353 int closeCount = 0; | 323 int closeCount = 0; |
| 354 server.transform(new WebSocketTransformer()).listen((webSocket) { | 324 server.transform(new WebSocketTransformer()).listen((webSocket) { |
| 355 String messageText = "Hello, world!"; | 325 String messageText = "Hello, world!"; |
| 356 int messageCount = 0; | 326 int messageCount = 0; |
| 357 webSocket.listen( | 327 webSocket.listen((message) { |
| 358 (message) { | 328 messageCount++; |
| 359 messageCount++; | 329 if (messageCount < 10) { |
| 360 if (messageCount < 10) { | 330 Expect.equals(messageText, message); |
| 361 Expect.equals(messageText, message); | 331 webSocket.add(message); |
| 362 webSocket.add(message); | 332 } else { |
| 363 } else { | 333 webSocket.close(closeStatus, closeReason); |
| 364 webSocket.close(closeStatus, closeReason); | 334 } |
| 365 } | 335 }, onDone: () { |
| 366 }, | 336 checkCloseStatus(webSocket, closeStatus, closeReason); |
| 367 onDone: () { | 337 closeCount++; |
| 368 checkCloseStatus(webSocket, closeStatus, closeReason); | 338 if (closeCount == totalConnections) { |
| 369 closeCount++; | 339 server.close(); |
| 370 if (closeCount == totalConnections) { | 340 } |
| 371 server.close(); | 341 }); |
| 372 } | |
| 373 }); | |
| 374 webSocket.add(messageText); | 342 webSocket.add(messageText); |
| 375 }); | 343 }); |
| 376 | 344 |
| 377 void webSocketConnection() { | 345 void webSocketConnection() { |
| 378 bool onopenCalled = false; | 346 bool onopenCalled = false; |
| 379 int onmessageCalled = 0; | 347 int onmessageCalled = 0; |
| 380 bool oncloseCalled = false; | 348 bool oncloseCalled = false; |
| 381 | 349 |
| 382 createClient(server.port).then((webSocket) { | 350 createClient(server.port).then((webSocket) { |
| 383 Expect.isFalse(onopenCalled); | 351 Expect.isFalse(onopenCalled); |
| 384 Expect.equals(0, onmessageCalled); | 352 Expect.equals(0, onmessageCalled); |
| 385 Expect.isFalse(oncloseCalled); | 353 Expect.isFalse(oncloseCalled); |
| 386 onopenCalled = true; | 354 onopenCalled = true; |
| 387 Expect.equals(WebSocket.OPEN, webSocket.readyState); | 355 Expect.equals(WebSocket.OPEN, webSocket.readyState); |
| 388 webSocket.listen( | 356 webSocket.listen((message) { |
| 389 (message) { | 357 onmessageCalled++; |
| 390 onmessageCalled++; | 358 Expect.isTrue(onopenCalled); |
| 391 Expect.isTrue(onopenCalled); | 359 Expect.isFalse(oncloseCalled); |
| 392 Expect.isFalse(oncloseCalled); | 360 Expect.equals(WebSocket.OPEN, webSocket.readyState); |
| 393 Expect.equals(WebSocket.OPEN, webSocket.readyState); | 361 webSocket.add(message); |
| 394 webSocket.add(message); | 362 }, onDone: () { |
| 395 }, | 363 Expect.isTrue(onopenCalled); |
| 396 onDone: () { | 364 Expect.equals(10, onmessageCalled); |
| 397 Expect.isTrue(onopenCalled); | 365 Expect.isFalse(oncloseCalled); |
| 398 Expect.equals(10, onmessageCalled); | 366 oncloseCalled = true; |
| 399 Expect.isFalse(oncloseCalled); | 367 Expect.equals(3002, webSocket.closeCode); |
| 400 oncloseCalled = true; | 368 Expect.equals("Got tired", webSocket.closeReason); |
| 401 Expect.equals(3002, webSocket.closeCode); | 369 Expect.equals(WebSocket.CLOSED, webSocket.readyState); |
| 402 Expect.equals("Got tired", webSocket.closeReason); | 370 }); |
| 403 Expect.equals(WebSocket.CLOSED, webSocket.readyState); | |
| 404 }); | |
| 405 }); | 371 }); |
| 406 } | 372 } |
| 407 | 373 |
| 408 for (int i = 0; i < totalConnections; i++) { | 374 for (int i = 0; i < totalConnections; i++) { |
| 409 webSocketConnection(); | 375 webSocketConnection(); |
| 410 } | 376 } |
| 411 }); | 377 }); |
| 412 } | 378 } |
| 413 | 379 |
| 414 testIndividualUpgrade(int connections) { | 380 testIndividualUpgrade(int connections) { |
| 415 asyncStart(); | 381 asyncStart(); |
| 416 createServer().then((server) { | 382 createServer().then((server) { |
| 417 server.listen((request) { | 383 server.listen((request) { |
| 418 if (WebSocketTransformer.isUpgradeRequest(request)) { | 384 if (WebSocketTransformer.isUpgradeRequest(request)) { |
| 419 WebSocketTransformer.upgrade(request).then((webSocket) { | 385 WebSocketTransformer.upgrade(request).then((webSocket) { |
| 420 webSocket.listen((_) { webSocket.close(); }); | 386 webSocket.listen((_) { |
| 421 webSocket.add("Hello"); | 387 webSocket.close(); |
| 422 }); | 388 }); |
| 423 } else { | 389 webSocket.add("Hello"); |
| 424 Expect.isFalse(WebSocketTransformer.isUpgradeRequest(request)); | 390 }); |
| 425 request.response.statusCode = HttpStatus.OK; | 391 } else { |
| 426 request.response.close(); | 392 Expect.isFalse(WebSocketTransformer.isUpgradeRequest(request)); |
| 427 } | 393 request.response.statusCode = HttpStatus.OK; |
| 394 request.response.close(); |
| 395 } |
| 428 }); | 396 }); |
| 429 | 397 |
| 430 var futures = []; | 398 var futures = []; |
| 431 | 399 |
| 432 var wsProtocol = '${secure ? "wss" : "ws"}'; | 400 var wsProtocol = '${secure ? "wss" : "ws"}'; |
| 433 var baseWsUrl = '$wsProtocol://$HOST_NAME:${server.port}/'; | 401 var baseWsUrl = '$wsProtocol://$HOST_NAME:${server.port}/'; |
| 434 var httpProtocol = '${secure ? "https" : "http"}'; | 402 var httpProtocol = '${secure ? "https" : "http"}'; |
| 435 var baseHttpUrl = '$httpProtocol://$HOST_NAME:${server.port}/'; | 403 var baseHttpUrl = '$httpProtocol://$HOST_NAME:${server.port}/'; |
| 436 HttpClient client = new HttpClient(); | 404 HttpClient client = new HttpClient(); |
| 437 | 405 |
| 438 for (int i = 0; i < connections; i++) { | 406 for (int i = 0; i < connections; i++) { |
| 439 var completer = new Completer(); | 407 var completer = new Completer(); |
| 440 futures.add(completer.future); | 408 futures.add(completer.future); |
| 441 WebSocket.connect('${baseWsUrl}') | 409 WebSocket.connect('${baseWsUrl}').then((websocket) { |
| 442 .then((websocket) { | 410 websocket.listen((_) { |
| 443 websocket.listen((_) { websocket.close(); }, | 411 websocket.close(); |
| 444 onDone: completer.complete); | 412 }, onDone: completer.complete); |
| 445 }); | 413 }); |
| 446 | 414 |
| 447 futures.add(client.openUrl("GET", Uri.parse('${baseHttpUrl}')) | 415 futures.add(client |
| 448 .then((request) => request.close()) | 416 .openUrl("GET", Uri.parse('${baseHttpUrl}')) |
| 449 .then((response) { | 417 .then((request) => request.close()) |
| 450 response.listen((_) { }); | 418 .then((response) { |
| 451 Expect.equals(HttpStatus.OK, response.statusCode); | 419 response.listen((_) {}); |
| 452 })); | 420 Expect.equals(HttpStatus.OK, response.statusCode); |
| 421 })); |
| 453 } | 422 } |
| 454 | 423 |
| 455 Future.wait(futures).then((_) { | 424 Future.wait(futures).then((_) { |
| 456 server.close(); | 425 server.close(); |
| 457 client.close(); | 426 client.close(); |
| 458 asyncEnd(); | 427 asyncEnd(); |
| 459 }); | 428 }); |
| 460 }); | 429 }); |
| 461 } | 430 } |
| 462 | 431 |
| 463 testFromUpgradedSocket() { | 432 testFromUpgradedSocket() { |
| 464 asyncStart(); | 433 asyncStart(); |
| 465 createServer().then((server) { | 434 createServer().then((server) { |
| 466 server.listen((request) { | 435 server.listen((request) { |
| 467 Expect.equals('Upgrade', request.headers.value(HttpHeaders.CONNECTION)); | 436 Expect.equals('Upgrade', request.headers.value(HttpHeaders.CONNECTION)); |
| 468 Expect.equals('websocket', request.headers.value(HttpHeaders.UPGRADE)); | 437 Expect.equals('websocket', request.headers.value(HttpHeaders.UPGRADE)); |
| 469 | 438 |
| 470 var key = request.headers.value('Sec-WebSocket-Key'); | 439 var key = request.headers.value('Sec-WebSocket-Key'); |
| 471 var digest = sha1.convert("$key$WEB_SOCKET_GUID".codeUnits); | 440 var digest = sha1.convert("$key$WEB_SOCKET_GUID".codeUnits); |
| 472 var accept = BASE64.encode(digest.bytes); | 441 var accept = BASE64.encode(digest.bytes); |
| 473 request.response | 442 request.response |
| 474 ..statusCode = HttpStatus.SWITCHING_PROTOCOLS | 443 ..statusCode = HttpStatus.SWITCHING_PROTOCOLS |
| 475 ..headers.add(HttpHeaders.CONNECTION, "Upgrade") | 444 ..headers.add(HttpHeaders.CONNECTION, "Upgrade") |
| 476 ..headers.add(HttpHeaders.UPGRADE, "websocket") | 445 ..headers.add(HttpHeaders.UPGRADE, "websocket") |
| 477 ..headers.add("Sec-WebSocket-Accept", accept); | 446 ..headers.add("Sec-WebSocket-Accept", accept); |
| 478 request.response.contentLength = 0; | 447 request.response.contentLength = 0; |
| 479 request.response.detachSocket().then((socket) { | 448 request.response.detachSocket().then((socket) { |
| 480 return new WebSocket.fromUpgradedSocket(socket, serverSide: true); | 449 return new WebSocket.fromUpgradedSocket(socket, serverSide: true); |
| 481 }).then((websocket) { | 450 }).then((websocket) { |
| 482 websocket.add("Hello"); | 451 websocket.add("Hello"); |
| 483 websocket.close(); | 452 websocket.close(); |
| 484 asyncEnd(); | 453 asyncEnd(); |
| 485 }); | 454 }); |
| 486 }); | 455 }); |
| 487 | 456 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 499 void testAdditionalHeaders() { | 468 void testAdditionalHeaders() { |
| 500 asyncStart(); | 469 asyncStart(); |
| 501 createServer().then((server) { | 470 createServer().then((server) { |
| 502 server.listen((request) { | 471 server.listen((request) { |
| 503 Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request)); | 472 Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request)); |
| 504 Expect.equals('my-value', request.headers['My-Header'][0]); | 473 Expect.equals('my-value', request.headers['My-Header'][0]); |
| 505 var header = request.headers['My-Header-Multiple']; | 474 var header = request.headers['My-Header-Multiple']; |
| 506 Expect.equals(1, header.length); | 475 Expect.equals(1, header.length); |
| 507 Expect.equals('my-value-1, my-value-2', header[0]); | 476 Expect.equals('my-value-1, my-value-2', header[0]); |
| 508 WebSocketTransformer.upgrade(request).then((webSocket) { | 477 WebSocketTransformer.upgrade(request).then((webSocket) { |
| 509 webSocket.listen((_) { webSocket.close(); }); | 478 webSocket.listen((_) { |
| 479 webSocket.close(); |
| 480 }); |
| 510 webSocket.add("Hello"); | 481 webSocket.add("Hello"); |
| 511 }); | 482 }); |
| 512 }); | 483 }); |
| 513 | 484 |
| 514 var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/'; | 485 var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/'; |
| 515 var headers = {'My-Header': 'my-value', | 486 var headers = { |
| 516 'My-Header-Multiple': ['my-value-1', 'my-value-2']}; | 487 'My-Header': 'my-value', |
| 488 'My-Header-Multiple': ['my-value-1', 'my-value-2'] |
| 489 }; |
| 517 WebSocket.connect(url, headers: headers).then((websocket) { | 490 WebSocket.connect(url, headers: headers).then((websocket) { |
| 518 return websocket.listen((message) { | 491 return websocket.listen((message) { |
| 519 Expect.equals("Hello", message); | 492 Expect.equals("Hello", message); |
| 520 websocket.close(); | 493 websocket.close(); |
| 521 }).asFuture(); | 494 }).asFuture(); |
| 522 }).then((_) { | 495 }).then((_) { |
| 523 server.close(); | 496 server.close(); |
| 524 asyncEnd(); | 497 asyncEnd(); |
| 525 }); | 498 }); |
| 526 }); | 499 }); |
| 527 } | 500 } |
| 528 | 501 |
| 529 | |
| 530 void testBasicAuthentication() { | 502 void testBasicAuthentication() { |
| 531 var userInfo = 'user:password'; | 503 var userInfo = 'user:password'; |
| 532 | 504 |
| 533 asyncStart(); | 505 asyncStart(); |
| 534 asyncStart(); | 506 asyncStart(); |
| 535 createServer().then((server) { | 507 createServer().then((server) { |
| 536 server.listen((request) { | 508 server.listen((request) { |
| 537 Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request)); | 509 Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request)); |
| 538 String auth = | 510 String auth = BASE64.encode(UTF8.encode(userInfo)); |
| 539 BASE64.encode(UTF8.encode(userInfo)); | |
| 540 Expect.equals('Basic $auth', request.headers['Authorization'][0]); | 511 Expect.equals('Basic $auth', request.headers['Authorization'][0]); |
| 541 Expect.equals(1, request.headers['Authorization'].length); | 512 Expect.equals(1, request.headers['Authorization'].length); |
| 542 WebSocketTransformer.upgrade(request).then((webSocket) { | 513 WebSocketTransformer.upgrade(request).then((webSocket) { |
| 543 webSocket.listen((_) { throw 'Unexpected'; }, | 514 webSocket.listen((_) { |
| 544 onDone: () { asyncEnd(); }); | 515 throw 'Unexpected'; |
| 516 }, onDone: () { |
| 517 asyncEnd(); |
| 518 }); |
| 545 webSocket.add("Hello"); | 519 webSocket.add("Hello"); |
| 546 }); | 520 }); |
| 547 }); | 521 }); |
| 548 | 522 |
| 549 var url = | 523 var url = |
| 550 '${secure ? "wss" : "ws"}://$userInfo@$HOST_NAME:${server.port}/'; | 524 '${secure ? "wss" : "ws"}://$userInfo@$HOST_NAME:${server.port}/'; |
| 551 WebSocket.connect(url).then((websocket) { | 525 WebSocket.connect(url).then((websocket) { |
| 552 return websocket.listen((message) { | 526 return websocket.listen((message) { |
| 553 Expect.equals("Hello", message); | 527 Expect.equals("Hello", message); |
| 554 return websocket.close(); | 528 return websocket.close(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 584 testNoUpgrade(); | 558 testNoUpgrade(); |
| 585 testUsePOST(); | 559 testUsePOST(); |
| 586 testConnections(10, 3002, "Got tired"); | 560 testConnections(10, 3002, "Got tired"); |
| 587 testIndividualUpgrade(5); | 561 testIndividualUpgrade(5); |
| 588 testFromUpgradedSocket(); | 562 testFromUpgradedSocket(); |
| 589 testAdditionalHeaders(); | 563 testAdditionalHeaders(); |
| 590 testBasicAuthentication(); | 564 testBasicAuthentication(); |
| 591 } | 565 } |
| 592 } | 566 } |
| 593 | 567 |
| 594 | |
| 595 main() { | 568 main() { |
| 596 new SecurityConfiguration(secure: false).runTests(); | 569 new SecurityConfiguration(secure: false).runTests(); |
| 597 // TODO(whesse): Make WebSocket.connect() take an optional context: parameter. | 570 // TODO(whesse): Make WebSocket.connect() take an optional context: parameter. |
| 598 // new SecurityConfiguration(secure: true).runTests(); | 571 // new SecurityConfiguration(secure: true).runTests(); |
| 599 } | 572 } |
| OLD | NEW |