Chromium Code Reviews| Index: dart/sdk/lib/io/secure_socket.dart |
| diff --git a/dart/sdk/lib/io/secure_socket.dart b/dart/sdk/lib/io/secure_socket.dart |
| index f11355ae5a2dd5fb5c5e3213c207bbcc5eabe29f..494500987ee88606e685a9fdb94591759f8b9970 100644 |
| --- a/dart/sdk/lib/io/secure_socket.dart |
| +++ b/dart/sdk/lib/io/secure_socket.dart |
| @@ -39,12 +39,14 @@ abstract class SecureSocket implements Socket { |
| int port, |
| {bool sendClientCertificate: false, |
| String certificateName, |
| - bool onBadCertificate(X509Certificate certificate)}) { |
| + bool onBadCertificate(X509Certificate certificate), |
| + List<String> supportedProtocols}) { |
| return RawSecureSocket.connect(host, |
| port, |
| sendClientCertificate: sendClientCertificate, |
| certificateName: certificateName, |
| - onBadCertificate: onBadCertificate) |
| + onBadCertificate: onBadCertificate, |
| + supportedProtocols: supportedProtocols) |
| .then((rawSocket) => new SecureSocket._(rawSocket)); |
| } |
| @@ -122,7 +124,8 @@ abstract class SecureSocket implements Socket { |
| String certificateName, |
| {List<int> bufferedData, |
| bool requestClientCertificate: false, |
| - bool requireClientCertificate: false}) { |
| + bool requireClientCertificate: false, |
| + List<String> supportedProtocols}) { |
| var completer = new Completer(); |
| (socket as dynamic)._detachRaw() |
| .then((detachedRaw) { |
| @@ -132,7 +135,8 @@ abstract class SecureSocket implements Socket { |
| subscription: detachedRaw[1], |
| bufferedData: bufferedData, |
| requestClientCertificate: requestClientCertificate, |
| - requireClientCertificate: requireClientCertificate); |
| + requireClientCertificate: requireClientCertificate, |
| + supportedProtocols: supportedProtocols); |
| }) |
| .then((raw) { |
| completer.complete(new SecureSocket._(raw)); |
| @@ -150,6 +154,11 @@ abstract class SecureSocket implements Socket { |
| X509Certificate get peerCertificate; |
| /** |
| + * Get the protocol which was selected during protocol negotiation. |
| + */ |
| + String get selectedProtocol; |
| + |
| + /** |
| * Renegotiate an existing secure connection, renewing the session keys |
| * and possibly changing the connection properties. |
| * |
| @@ -245,7 +254,8 @@ abstract class RawSecureSocket implements RawSocket { |
| int port, |
| {bool sendClientCertificate: false, |
| String certificateName, |
| - bool onBadCertificate(X509Certificate certificate)}) { |
| + bool onBadCertificate(X509Certificate certificate), |
| + List<String> supportedProtocols}) { |
| _RawSecureSocket._verifyFields( |
| host, |
| port, |
| @@ -260,7 +270,8 @@ abstract class RawSecureSocket implements RawSocket { |
| return secure(socket, |
| sendClientCertificate: sendClientCertificate, |
| certificateName: certificateName, |
| - onBadCertificate: onBadCertificate); |
| + onBadCertificate: onBadCertificate, |
| + supportedProtocols: supportedProtocols); |
| }); |
| } |
| @@ -298,7 +309,8 @@ abstract class RawSecureSocket implements RawSocket { |
| host, |
| bool sendClientCertificate: false, |
| String certificateName, |
| - bool onBadCertificate(X509Certificate certificate)}) { |
| + bool onBadCertificate(X509Certificate certificate), |
| + List<String> supportedProtocols}) { |
| socket.readEventsEnabled = false; |
| socket.writeEventsEnabled = false; |
| return _RawSecureSocket.connect( |
| @@ -309,7 +321,8 @@ abstract class RawSecureSocket implements RawSocket { |
| socket: socket, |
| subscription: subscription, |
| sendClientCertificate: sendClientCertificate, |
| - onBadCertificate: onBadCertificate); |
| + onBadCertificate: onBadCertificate, |
| + supportedProtocols: supportedProtocols); |
| } |
| /** |
| @@ -341,7 +354,8 @@ abstract class RawSecureSocket implements RawSocket { |
| {StreamSubscription subscription, |
| List<int> bufferedData, |
| bool requestClientCertificate: false, |
| - bool requireClientCertificate: false}) { |
| + bool requireClientCertificate: false, |
| + List<String> supportedProtocols}) { |
| socket.readEventsEnabled = false; |
| socket.writeEventsEnabled = false; |
| return _RawSecureSocket.connect( |
| @@ -353,7 +367,8 @@ abstract class RawSecureSocket implements RawSocket { |
| subscription: subscription, |
| bufferedData: bufferedData, |
| requestClientCertificate: requestClientCertificate, |
| - requireClientCertificate: requireClientCertificate); |
| + requireClientCertificate: requireClientCertificate, |
| + supportedProtocols: supportedProtocols); |
| } |
| /** |
| @@ -375,6 +390,11 @@ abstract class RawSecureSocket implements RawSocket { |
| * [peerCertificate] will return the server's certificate. |
| */ |
| X509Certificate get peerCertificate; |
| + |
| + /** |
| + * Get the protocol which was selected during protocol negotiation. |
| + */ |
| + String get selectedProtocol; |
| } |
| @@ -459,6 +479,7 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| _SecureFilter _secureFilter = new _SecureFilter(); |
| int _filterPointer; |
| + String _selectedProtocol; |
| static Future<_RawSecureSocket> connect( |
| host, |
| @@ -471,7 +492,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| bool requestClientCertificate: false, |
| bool requireClientCertificate: false, |
| bool sendClientCertificate: false, |
| - bool onBadCertificate(X509Certificate certificate)}) { |
| + bool onBadCertificate(X509Certificate certificate), |
| + List<String> supportedProtocols}) { |
| _verifyFields(host, requestedPort, certificateName, is_server, |
| requestClientCertificate, requireClientCertificate, |
| sendClientCertificate, onBadCertificate); |
| @@ -488,7 +510,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| requestClientCertificate, |
| requireClientCertificate, |
| sendClientCertificate, |
| - onBadCertificate) |
| + onBadCertificate, |
| + supportedProtocols) |
| ._handshakeComplete.future; |
| } |
| @@ -503,7 +526,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| this.requestClientCertificate, |
| this.requireClientCertificate, |
| this.sendClientCertificate, |
| - this.onBadCertificate(X509Certificate certificate)) { |
| + this.onBadCertificate(X509Certificate certificate), |
| + List<String> supportedProtocols) { |
| _controller = new StreamController<RawSocketEvent>( |
| sync: true, |
| onListen: _onSubscriptionStateChange, |
| @@ -548,13 +572,44 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| requestClientCertificate || |
| requireClientCertificate, |
| requireClientCertificate, |
| - sendClientCertificate); |
| + sendClientCertificate, |
| + _protocolsToLengthEncoding(supportedProtocols)); |
| _secureHandshake(); |
| } catch (e, s) { |
| _reportError(e, s); |
| } |
| } |
| + Uint8List _protocolsToLengthEncoding(List<String> protocols) { |
| + if (protocols == null || protocols.length == 0) { |
| + return new Uint8List(0); |
| + } |
| + |
| + // NOTE: The NSS library will treat the first protocol as the fallback |
| + // protocol. The remaining ones are sorted in priority order. |
| + // We therefore put the protocol least desired at the front, to make it the |
| + // default. |
| + List<int> bytes = []; |
|
Søren Gjesse
2014/10/03 15:47:04
You could allocate a 255 byte Uint8List here and r
kustermann
2014/11/07 16:20:03
Did something similar. Had some discussions with L
|
| + _addProtocolBytes(bytes, protocols.last); |
| + for (var i = 0; i < protocols.length -1; i++) { |
| + _addProtocolBytes(bytes, protocols[i]); |
| + } |
| + |
| + return new Uint8List.fromList(bytes); |
| + } |
| + |
| + void _addProtocolBytes(List<int> outBytes, String protocol) { |
| + var protocolBytes = UTF8.encode(protocol); |
| + var len = protocolBytes.length; |
| + |
| + if (len > 255) { |
| + throw new ArgumentError( |
| + 'Cannot support protocols with more than 255 characters'); |
| + } |
| + outBytes.add(len); |
| + outBytes.addAll(protocolBytes); |
| + } |
| + |
| StreamSubscription listen(void onData(RawSocketEvent data), |
| {Function onError, |
| void onDone(), |
| @@ -732,6 +787,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| X509Certificate get peerCertificate => _secureFilter.peerCertificate; |
| + String get selectedProtocol => _selectedProtocol; |
| + |
| bool _onBadCertificateWrapper(X509Certificate certificate) { |
| if (onBadCertificate == null) return false; |
| var result = onBadCertificate(certificate); |
| @@ -845,8 +902,13 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| _status = CONNECTED; |
| if (_connectPending) { |
| _connectPending = false; |
| - // We don't want user code to run synchronously in this callback. |
| - Timer.run(() => _handshakeComplete.complete(this)); |
| + try { |
| + _selectedProtocol = _secureFilter.selectedProtocol(); |
| + // We don't want user code to run synchronously in this callback. |
| + Timer.run(() => _handshakeComplete.complete(this)); |
| + } catch (error, stack) { |
| + _handshakeComplete.completeError(error, stack); |
| + } |
| } |
| } |
| @@ -905,7 +967,7 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
| _secureFilter.handshake(); |
| if (_status == HANDSHAKE) { |
| throw new HandshakeException( |
| - 'Connection terminated during handshake'); |
| + 'xConnection terminated during handshake'); |
|
Søren Gjesse
2014/10/03 15:47:04
Accidental edit.
kustermann
2014/11/07 16:20:03
Done.
|
| } |
| } |
| _closeHandler(); |
| @@ -1206,7 +1268,8 @@ abstract class _SecureFilter { |
| String certificateName, |
| bool requestClientCertificate, |
| bool requireClientCertificate, |
| - bool sendClientCertificate); |
| + bool sendClientCertificate, |
| + Uint8List protocols); |
| void destroy(); |
| void handshake(); |
| void rehandshake(); |