OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // |
| 5 // VMOptions= |
| 6 // VMOptions=--short_socket_read |
| 7 // VMOptions=--short_socket_write |
| 8 // VMOptions=--short_socket_read --short_socket_write |
| 9 |
| 10 import "dart:async"; |
| 11 import "dart:convert"; |
| 12 import "dart:io"; |
| 13 import "dart:typed_data"; |
| 14 |
| 15 import "package:async_helper/async_helper.dart"; |
| 16 import "package:crypto/crypto.dart"; |
| 17 import "package:expect/expect.dart"; |
| 18 import "package:path/path.dart"; |
| 19 |
| 20 const WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
| 21 |
| 22 const String HOST_NAME = 'localhost'; |
| 23 |
| 24 String localFile(path) => Platform.script.resolve(path).toFilePath(); |
| 25 |
| 26 SecurityContext serverContext = new SecurityContext() |
| 27 ..useCertificateChain(localFile('certificates/server_chain.pem')) |
| 28 ..usePrivateKey(localFile('certificates/server_key.pem'), |
| 29 password: 'dartdart'); |
| 30 |
| 31 class SecurityConfiguration { |
| 32 final bool secure; |
| 33 |
| 34 SecurityConfiguration({bool this.secure}); |
| 35 |
| 36 Future<HttpServer> createServer({int backlog: 0}) => |
| 37 secure ? HttpServer.bindSecure(HOST_NAME, |
| 38 0, |
| 39 serverContext, |
| 40 backlog: backlog) |
| 41 : HttpServer.bind(HOST_NAME, |
| 42 0, |
| 43 backlog: backlog); |
| 44 |
| 45 Future<WebSocket> createClient(int port) => |
| 46 // TODO(whesse): Add client context argument to WebSocket.connect |
| 47 WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/'); |
| 48 |
| 49 void testCompressionSupport({server: false, |
| 50 client: false, |
| 51 contextTakeover: false}) { |
| 52 asyncStart(); |
| 53 |
| 54 var clientOptions = new CompressionOptions( |
| 55 enabled: client, |
| 56 serverNoContextTakeover: contextTakeover, |
| 57 clientNoContextTakeover: contextTakeover); |
| 58 var serverOptions = new CompressionOptions( |
| 59 enabled: server, |
| 60 serverNoContextTakeover: contextTakeover, |
| 61 clientNoContextTakeover: contextTakeover); |
| 62 |
| 63 createServer().then((server) { |
| 64 server.listen((request) { |
| 65 Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request)); |
| 66 WebSocketTransformer.upgrade(request, compression: serverOptions) |
| 67 .then((webSocket) { |
| 68 webSocket.listen((message) { |
| 69 Expect.equals("Hello World", message); |
| 70 |
| 71 webSocket.add(message); |
| 72 webSocket.close(); |
| 73 }); |
| 74 webSocket.add("Hello World"); |
| 75 }); |
| 76 }); |
| 77 |
| 78 var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/'; |
| 79 WebSocket.connect(url, compression: clientOptions).then((websocket) { |
| 80 var future = websocket.listen((message) { |
| 81 Expect.equals("Hello World", message); |
| 82 }).asFuture(); |
| 83 websocket.add("Hello World"); |
| 84 return future; |
| 85 }).then((_) { |
| 86 server.close(); |
| 87 asyncEnd(); |
| 88 }); |
| 89 }); |
| 90 } |
| 91 |
| 92 void testCompressionHeaders() { |
| 93 asyncStart(); |
| 94 createServer().then((server) { |
| 95 server.listen((request) { |
| 96 Expect.equals('Upgrade', request.headers.value(HttpHeaders.CONNECTION)); |
| 97 Expect.equals('websocket', request.headers.value(HttpHeaders.UPGRADE)); |
| 98 |
| 99 var key = request.headers.value('Sec-WebSocket-Key'); |
| 100 var sha1 = new SHA1()..add("$key$WEB_SOCKET_GUID".codeUnits); |
| 101 var accept = CryptoUtils.bytesToBase64(sha1.close()); |
| 102 request.response |
| 103 ..statusCode = HttpStatus.SWITCHING_PROTOCOLS |
| 104 ..headers.add(HttpHeaders.CONNECTION, "Upgrade") |
| 105 ..headers.add(HttpHeaders.UPGRADE, "websocket") |
| 106 ..headers.add("Sec-WebSocket-Accept", accept) |
| 107 ..headers.add("Sec-WebSocket-Extensions", |
| 108 "permessage-deflate;" |
| 109 // Test quoted values and space padded = |
| 110 'server_max_window_bits="10"; client_max_window_bits = 12' |
| 111 'client_no_context_takeover; server_no_context_takeover'); |
| 112 request.response.contentLength = 0; |
| 113 request.response.detachSocket().then((socket) { |
| 114 return new WebSocket.fromUpgradedSocket(socket, serverSide: true); |
| 115 }).then((websocket) { |
| 116 websocket.add("Hello"); |
| 117 websocket.close(); |
| 118 asyncEnd(); |
| 119 }); |
| 120 }); |
| 121 |
| 122 var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/'; |
| 123 |
| 124 WebSocket.connect(url).then((websocket) { |
| 125 return websocket.listen((message) { |
| 126 Expect.equals("Hello", message); |
| 127 websocket.close(); |
| 128 }).asFuture(); |
| 129 }).then((_) => server.close()); |
| 130 }); |
| 131 } |
| 132 |
| 133 void runTests() { |
| 134 // No compression or takeover |
| 135 testCompressionSupport(); |
| 136 // compression no takeover |
| 137 testCompressionSupport(server: true, client: true); |
| 138 // compression and context takeover. |
| 139 testCompressionSupport(server: true, client: true, contextTakeover: true); |
| 140 // Compression on client but not server. No take over |
| 141 testCompressionSupport(client: true); |
| 142 // Compression on server but not client. |
| 143 testCompressionSupport(server: true); |
| 144 |
| 145 testCompressionHeaders(); |
| 146 } |
| 147 } |
| 148 |
| 149 main() { |
| 150 new SecurityConfiguration(secure: false).runTests(); |
| 151 // TODO(whesse): Make WebSocket.connect() take an optional context: parameter. |
| 152 // new SecurityConfiguration(secure: true).runTests(); |
| 153 } |
OLD | NEW |