Index: dart/tests/standalone/io/secure_socket_alpn_test.dart |
diff --git a/dart/tests/standalone/io/secure_socket_alpn_test.dart b/dart/tests/standalone/io/secure_socket_alpn_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..963fb74e20be1b7d96f2a2696f5d39489080a9c7 |
--- /dev/null |
+++ b/dart/tests/standalone/io/secure_socket_alpn_test.dart |
@@ -0,0 +1,214 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+import 'dart:io'; |
+import 'dart:convert'; |
+ |
+import 'package:expect/expect.dart'; |
+import 'package:async_helper/async_helper.dart'; |
+ |
+const String MAX_LEN_ERROR = |
+ 'Length of protocol must be between 1 and 255'; |
+ |
+const String MAX_MSG_LEN_ERROR = |
+ 'The maximum message length supported is 2^15-1'; |
+ |
+void InitializeSSL() { |
+ var testPkcertDatabase = Platform.script.resolve('pkcert').toFilePath(); |
+ SecureSocket.initialize(database: testPkcertDatabase, |
+ password: 'dartdart'); |
+} |
+ |
+// Tests that client/server with same protocol can securly establish a |
+// connection, negogiate the protocol and can send data to each other. |
+void testSuccessfulAlpnNegogiationConnection(List<String> clientProtocols, |
+ List<String> serverProtocols, |
+ String selectedProtocol) { |
+ asyncStart(); |
+ SecureServerSocket.bind('localhost', 0, 'localhost_cert', |
+ supportedProtocols: serverProtocols).then((SecureServerSocket server) { |
+ |
+ asyncStart(); |
+ server.first.then((SecureSocket socket) { |
+ Expect.equals(selectedProtocol, socket.selectedProtocol); |
+ socket..write('server message')..close(); |
+ socket.transform(ASCII.decoder).join('').then((String s) { |
+ Expect.equals('client message', s); |
+ asyncEnd(); |
+ }); |
+ }); |
+ |
+ asyncStart(); |
+ SecureSocket.connect('localhost', server.port, |
+ supportedProtocols: clientProtocols).then((socket) { |
+ Expect.equals(selectedProtocol, socket.selectedProtocol); |
+ socket..write('client message')..close(); |
+ socket.transform(ASCII.decoder).join('').then((String s) { |
+ Expect.equals('server message', s); |
+ server.close(); |
+ asyncEnd(); |
+ }); |
+ }); |
+ |
+ asyncEnd(); |
+ }); |
+} |
+ |
+void testFailedAlpnNegogiationConnection(List<String> clientProtocols, |
+ List<String> serverProtocols) { |
+ asyncStart(); |
+ SecureServerSocket.bind('localhost', 0, 'localhost_cert', |
+ supportedProtocols: serverProtocols).then((SecureServerSocket server) { |
+ |
+ asyncStart(); |
+ server.first.catchError((error, stack) { |
+ Expect.isTrue(error is HandshakeException); |
+ asyncEnd(); |
+ }); |
+ |
+ asyncStart(); |
+ SecureSocket.connect('localhost', |
+ server.port, |
+ supportedProtocols: clientProtocols) |
+ .catchError((error, stack) { |
+ Expect.isTrue(error is HandshakeException); |
+ asyncEnd(); |
+ }); |
+ |
+ asyncEnd(); |
+ }); |
+} |
+ |
+void testInvalidArgumentsLongName(List<String> protocols, |
+ bool isLenError, |
+ bool isMsgLenError) { |
+ asyncStart(); |
+ SecureServerSocket.bind('localhost', 0, 'localhost_cert', |
+ supportedProtocols: protocols).then((SecureServerSocket server) { |
+ |
+ asyncStart(); |
+ server.first.catchError((error, stack) { |
+ String errorString = '${(error as ArgumentError)}'; |
+ if (isLenError) { |
+ Expect.isTrue(errorString.contains(MAX_LEN_ERROR)); |
+ } else if (isMsgLenError) { |
+ Expect.isTrue(errorString.contains(MAX_MSG_LEN_ERROR)); |
+ } else { |
+ throw 'unreachable'; |
+ } |
+ asyncEnd(); |
+ }); |
+ |
+ asyncStart(); |
+ SecureSocket.connect('localhost', |
+ server.port, |
+ supportedProtocols: protocols) |
+ .catchError((error, stack) { |
+ String errorString = '${(error as ArgumentError)}'; |
+ if (isLenError) { |
+ Expect.isTrue(errorString.contains(MAX_LEN_ERROR)); |
+ } else if (isMsgLenError) { |
+ Expect.isTrue(errorString.contains(MAX_MSG_LEN_ERROR)); |
+ } else { |
+ throw 'unreachable'; |
+ } |
+ asyncEnd(); |
+ }); |
+ |
+ asyncEnd(); |
+ }); |
+} |
+ |
+main() { |
+ InitializeSSL(); |
+ final longname256 = 'p' * 256; |
+ final String longname255 = 'p' * 255; |
+ final String strangelongname255 = 'ø' + 'p' * 253; |
+ final String strangelongname256 = 'ø' + 'p' * 254; |
+ |
+ // This produces a message of (1 << 15)-2 bytes (1 length and 1 ascii byte). |
+ final List<String> allProtocols = new Iterable.generate( |
+ (1 << 14) - 1, (i) => '0').toList(); |
+ |
+ // This produces a message of (1 << 15) bytes (1 length and 1 ascii byte). |
+ final List<String> allProtocolsPlusOne = new Iterable.generate( |
+ (1 << 14), (i) => '0').toList(); |
+ |
+ // Protocols are in order of decreasing priority. First matching protocol |
+ // will be taken. |
+ |
+ // Test successfull negotiation, including priority. |
+ testSuccessfulAlpnNegogiationConnection(['a'], |
+ ['a'], |
+ 'a'); |
+ |
+ testSuccessfulAlpnNegogiationConnection([longname255], |
+ [longname255], |
+ longname255); |
+ |
+ testSuccessfulAlpnNegogiationConnection([strangelongname255], |
+ [strangelongname255], |
+ strangelongname255); |
+ |
+ testSuccessfulAlpnNegogiationConnection(allProtocols, |
+ allProtocols, |
+ '0'); |
+ |
+ testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'], |
+ ['a', 'b', 'c'], |
+ 'a'); |
+ |
+ testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'], |
+ ['c'], |
+ 'c'); |
+ |
+ // Server precedence. |
+ testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'], |
+ ['c', 'b', 'a'], |
+ 'a'); |
+ |
+ testSuccessfulAlpnNegogiationConnection(['c'], |
+ ['a', 'b', 'c'], |
+ 'c'); |
+ |
+ testSuccessfulAlpnNegogiationConnection(['s1', 'b', 'e1'], |
+ ['s2', 'b', 'e2'], |
+ 'b'); |
+ |
+ // Test no protocol negotiation support |
+ testSuccessfulAlpnNegogiationConnection(null, |
+ null, |
+ null); |
+ |
+ testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'], |
+ null, |
+ null); |
+ |
+ testSuccessfulAlpnNegogiationConnection(null, |
+ ['a', 'b', 'c'], |
+ null); |
+ |
+ testSuccessfulAlpnNegogiationConnection([], |
+ [], |
+ null); |
+ |
+ testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'], |
+ [], |
+ null); |
+ |
+ testSuccessfulAlpnNegogiationConnection([], |
+ ['a', 'b', 'c'], |
+ null); |
+ |
+ // Test non-overlapping protocols. |
+ testFailedAlpnNegogiationConnection(['a'], ['b']); |
+ |
+ |
+ // Test too short / too long protocol names. |
+ testInvalidArgumentsLongName([longname256], true, false); |
+ testInvalidArgumentsLongName([strangelongname256], true, false); |
+ testInvalidArgumentsLongName([''], true, false); |
+ testInvalidArgumentsLongName(allProtocolsPlusOne, false, true); |
+ testInvalidArgumentsLongName(allProtocolsPlusOne, false, true); |
+} |