Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Unified Diff: pkg/dev_compiler/tool/input_sdk/lib/io/secure_socket.dart

Issue 2698353003: unfork DDC's copy of most SDK libraries (Closed)
Patch Set: revert core_patch Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/dev_compiler/tool/input_sdk/lib/io/secure_socket.dart
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/io/secure_socket.dart b/pkg/dev_compiler/tool/input_sdk/lib/io/secure_socket.dart
deleted file mode 100644
index 380a8c466abd282facda77184ed96728b4e0003b..0000000000000000000000000000000000000000
--- a/pkg/dev_compiler/tool/input_sdk/lib/io/secure_socket.dart
+++ /dev/null
@@ -1,1263 +0,0 @@
-// Copyright (c) 2013, 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.
-
-part of dart.io;
-
-/**
- * A high-level class for communicating securely over a TCP socket, using
- * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an
- * [IOSink] interface, making it ideal for using together with
- * other [Stream]s.
- */
-abstract class SecureSocket implements Socket {
- external factory SecureSocket._(RawSecureSocket rawSocket);
-
- /**
- * Constructs a new secure client socket and connects it to the given
- * [host] on port [port]. The returned Future will complete with a
- * [SecureSocket] that is connected and ready for subscription.
- *
- * The certificate provided by the server is checked
- * using the trusted certificates set in the SecurityContext object.
- * The default SecurityContext object contains a built-in set of trusted
- * root certificates for well-known certificate authorities.
- *
- * [onBadCertificate] is an optional handler for unverifiable certificates.
- * The handler receives the [X509Certificate], and can inspect it and
- * decide (or let the user decide) whether to accept
- * the connection or not. The handler should return true
- * to continue the [SecureSocket] connection.
- */
- static Future<SecureSocket> connect(
- host,
- int port,
- {SecurityContext context,
- bool onBadCertificate(X509Certificate certificate),
- List<String> supportedProtocols}) {
- return RawSecureSocket.connect(host,
- port,
- context: context,
- onBadCertificate: onBadCertificate,
- supportedProtocols: supportedProtocols)
- .then((rawSocket) => new SecureSocket._(rawSocket));
- }
-
- /**
- * Takes an already connected [socket] and starts client side TLS
- * handshake to make the communication secure. When the returned
- * future completes the [SecureSocket] has completed the TLS
- * handshake. Using this function requires that the other end of the
- * connection is prepared for TLS handshake.
- *
- * If the [socket] already has a subscription, this subscription
- * will no longer receive and events. In most cases calling
- * `pause` on this subscription before starting TLS handshake is
- * the right thing to do.
- *
- * If the [host] argument is passed it will be used as the host name
- * for the TLS handshake. If [host] is not passed the host name from
- * the [socket] will be used. The [host] can be either a [String] or
- * an [InternetAddress].
- *
- * Calling this function will _not_ cause a DNS host lookup. If the
- * [host] passed is a [String] the [InternetAddress] for the
- * resulting [SecureSocket] will have the passed in [host] as its
- * host value and the internet address of the already connected
- * socket as its address value.
- *
- * See [connect] for more information on the arguments.
- *
- */
- static Future<SecureSocket> secure(
- Socket socket,
- {host,
- SecurityContext context,
- bool onBadCertificate(X509Certificate certificate)}) {
- var completer = new Completer();
- (socket as dynamic)._detachRaw()
- .then((detachedRaw) {
- return RawSecureSocket.secure(
- detachedRaw[0],
- subscription: detachedRaw[1],
- host: host,
- context: context,
- onBadCertificate: onBadCertificate);
- })
- .then((raw) {
- completer.complete(new SecureSocket._(raw));
- });
- return completer.future;
- }
-
- /**
- * Takes an already connected [socket] and starts server side TLS
- * handshake to make the communication secure. When the returned
- * future completes the [SecureSocket] has completed the TLS
- * handshake. Using this function requires that the other end of the
- * connection is going to start the TLS handshake.
- *
- * If the [socket] already has a subscription, this subscription
- * will no longer receive and events. In most cases calling
- * [:pause:] on this subscription before starting TLS handshake is
- * the right thing to do.
- *
- * If some of the data of the TLS handshake has already been read
- * from the socket this data can be passed in the [bufferedData]
- * parameter. This data will be processed before any other data
- * available on the socket.
- *
- * See [SecureServerSocket.bind] for more information on the
- * arguments.
- *
- */
- static Future<SecureSocket> secureServer(
- Socket socket,
- SecurityContext context,
- {List<int> bufferedData,
- bool requestClientCertificate: false,
- bool requireClientCertificate: false,
- List<String> supportedProtocols}) {
- var completer = new Completer();
- (socket as dynamic)._detachRaw()
- .then((detachedRaw) {
- return RawSecureSocket.secureServer(
- detachedRaw[0],
- context,
- subscription: detachedRaw[1],
- bufferedData: bufferedData,
- requestClientCertificate: requestClientCertificate,
- requireClientCertificate: requireClientCertificate,
- supportedProtocols: supportedProtocols);
- })
- .then((raw) {
- completer.complete(new SecureSocket._(raw));
- });
- return completer.future;
- }
-
- /**
- * Get the peer certificate for a connected SecureSocket. If this
- * SecureSocket is the server end of a secure socket connection,
- * [peerCertificate] will return the client certificate, or null, if no
- * client certificate was received. If it is the client end,
- * [peerCertificate] will return the server's certificate.
- */
- 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.
- *
- * This repeats the SSL or TLS handshake, with options that allow clearing
- * the session cache and requesting a client certificate.
- */
- void renegotiate({bool useSessionCache: true,
- bool requestClientCertificate: false,
- bool requireClientCertificate: false});
-}
-
-
-/**
- * RawSecureSocket provides a secure (SSL or TLS) network connection.
- * Client connections to a server are provided by calling
- * RawSecureSocket.connect. A secure server, created with
- * [RawSecureServerSocket], also returns RawSecureSocket objects representing
- * the server end of a secure connection.
- * The certificate provided by the server is checked
- * using the trusted certificates set in the SecurityContext object.
- * The default [SecurityContext] object contains a built-in set of trusted
- * root certificates for well-known certificate authorities.
- */
-abstract class RawSecureSocket implements RawSocket {
- /**
- * Constructs a new secure client socket and connect it to the given
- * host on the given port. The returned [Future] is completed with the
- * RawSecureSocket when it is connected and ready for subscription.
- *
- * The certificate provided by the server is checked using the trusted
- * certificates set in the SecurityContext object If a certificate and key are
- * set on the client, using [SecurityContext.useCertificateChain] and
- * [SecurityContext.usePrivateKey], and the server asks for a client
- * certificate, then that client certificate is sent to the server.
- *
- * [onBadCertificate] is an optional handler for unverifiable certificates.
- * The handler receives the [X509Certificate], and can inspect it and
- * decide (or let the user decide) whether to accept
- * the connection or not. The handler should return true
- * to continue the [RawSecureSocket] connection.
- */
- static Future<RawSecureSocket> connect(
- host,
- int port,
- {SecurityContext context,
- bool onBadCertificate(X509Certificate certificate),
- List<String> supportedProtocols}) {
- _RawSecureSocket._verifyFields(
- host,
- port,
- false,
- false,
- false,
- onBadCertificate);
- return RawSocket.connect(host, port)
- .then((socket) {
- return secure(socket,
- context: context,
- onBadCertificate: onBadCertificate,
- supportedProtocols: supportedProtocols);
- });
- }
-
- /**
- * Takes an already connected [socket] and starts client side TLS
- * handshake to make the communication secure. When the returned
- * future completes the [RawSecureSocket] has completed the TLS
- * handshake. Using this function requires that the other end of the
- * connection is prepared for TLS handshake.
- *
- * If the [socket] already has a subscription, pass the existing
- * subscription in the [subscription] parameter. The [secure]
- * operation will take over the subscription by replacing the
- * handlers with it own secure processing. The caller must not touch
- * this subscription anymore. Passing a paused subscription is an
- * error.
- *
- * If the [host] argument is passed it will be used as the host name
- * for the TLS handshake. If [host] is not passed the host name from
- * the [socket] will be used. The [host] can be either a [String] or
- * an [InternetAddress].
- *
- * Calling this function will _not_ cause a DNS host lookup. If the
- * [host] passed is a [String] the [InternetAddress] for the
- * resulting [SecureSocket] will have this passed in [host] as its
- * host value and the internet address of the already connected
- * socket as its address value.
- *
- * See [connect] for more information on the arguments.
- *
- */
- static Future<RawSecureSocket> secure(
- RawSocket socket,
- {StreamSubscription subscription,
- host,
- SecurityContext context,
- bool onBadCertificate(X509Certificate certificate),
- List<String> supportedProtocols}) {
- socket.readEventsEnabled = false;
- socket.writeEventsEnabled = false;
- return _RawSecureSocket.connect(
- host != null ? host : socket.address.host,
- socket.port,
- is_server: false,
- socket: socket,
- subscription: subscription,
- context: context,
- onBadCertificate: onBadCertificate,
- supportedProtocols: supportedProtocols);
- }
-
- /**
- * Takes an already connected [socket] and starts server side TLS
- * handshake to make the communication secure. When the returned
- * future completes the [RawSecureSocket] has completed the TLS
- * handshake. Using this function requires that the other end of the
- * connection is going to start the TLS handshake.
- *
- * If the [socket] already has a subscription, pass the existing
- * subscription in the [subscription] parameter. The [secureServer]
- * operation will take over the subscription by replacing the
- * handlers with it own secure processing. The caller must not touch
- * this subscription anymore. Passing a paused subscription is an
- * error.
- *
- * If some of the data of the TLS handshake has already been read
- * from the socket this data can be passed in the [bufferedData]
- * parameter. This data will be processed before any other data
- * available on the socket.
- *
- * See [RawSecureServerSocket.bind] for more information on the
- * arguments.
- *
- */
- static Future<RawSecureSocket> secureServer(
- RawSocket socket,
- SecurityContext context,
- {StreamSubscription subscription,
- List<int> bufferedData,
- bool requestClientCertificate: false,
- bool requireClientCertificate: false,
- List<String> supportedProtocols}) {
- socket.readEventsEnabled = false;
- socket.writeEventsEnabled = false;
- return _RawSecureSocket.connect(
- socket.address,
- socket.remotePort,
- context: context,
- is_server: true,
- socket: socket,
- subscription: subscription,
- bufferedData: bufferedData,
- requestClientCertificate: requestClientCertificate,
- requireClientCertificate: requireClientCertificate,
- supportedProtocols: supportedProtocols);
- }
-
- /**
- * Renegotiate an existing secure connection, renewing the session keys
- * and possibly changing the connection properties.
- *
- * This repeats the SSL or TLS handshake, with options that allow clearing
- * the session cache and requesting a client certificate.
- */
- void renegotiate({bool useSessionCache: true,
- bool requestClientCertificate: false,
- bool requireClientCertificate: false});
-
- /**
- * Get the peer certificate for a connected RawSecureSocket. If this
- * RawSecureSocket is the server end of a secure socket connection,
- * [peerCertificate] will return the client certificate, or null, if no
- * client certificate was received. If it is the client end,
- * [peerCertificate] will return the server's certificate.
- */
- X509Certificate get peerCertificate;
-
- /**
- * Get the protocol which was selected during protocol negotiation.
- */
- String get selectedProtocol;
-}
-
-
-/**
- * X509Certificate represents an SSL certificate, with accessors to
- * get the fields of the certificate.
- */
-abstract class X509Certificate {
- external factory X509Certificate._();
-
- String get subject;
- String get issuer;
- DateTime get startValidity;
- DateTime get endValidity;
-}
-
-
-class _FilterStatus {
- bool progress = false; // The filter read or wrote data to the buffers.
- bool readEmpty = true; // The read buffers and decryption filter are empty.
- bool writeEmpty = true; // The write buffers and encryption filter are empty.
- // These are set if a buffer changes state from empty or full.
- bool readPlaintextNoLongerEmpty = false;
- bool writePlaintextNoLongerFull = false;
- bool readEncryptedNoLongerFull = false;
- bool writeEncryptedNoLongerEmpty = false;
-
- _FilterStatus();
-}
-
-
-class _RawSecureSocket extends Stream<RawSocketEvent>
- implements RawSecureSocket {
- // Status states
- static final int HANDSHAKE = 201;
- static final int CONNECTED = 202;
- static final int CLOSED = 203;
-
- // Buffer identifiers.
- // These must agree with those in the native C++ implementation.
- static final int READ_PLAINTEXT = 0;
- static final int WRITE_PLAINTEXT = 1;
- static final int READ_ENCRYPTED = 2;
- static final int WRITE_ENCRYPTED = 3;
- static final int NUM_BUFFERS = 4;
-
- // Is a buffer identifier for an encrypted buffer?
- static bool _isBufferEncrypted(int identifier) => identifier >= READ_ENCRYPTED;
-
- RawSocket _socket;
- final Completer<_RawSecureSocket> _handshakeComplete =
- new Completer<_RawSecureSocket>();
- StreamController<RawSocketEvent> _controller;
- Stream<RawSocketEvent> _stream;
- StreamSubscription<RawSocketEvent> _socketSubscription;
- List<int> _bufferedData;
- int _bufferedDataIndex = 0;
- final InternetAddress address;
- final bool is_server;
- SecurityContext context;
- final bool requestClientCertificate;
- final bool requireClientCertificate;
- final Function onBadCertificate;
-
- var _status = HANDSHAKE;
- bool _writeEventsEnabled = true;
- bool _readEventsEnabled = true;
- int _pauseCount = 0;
- bool _pendingReadEvent = false;
- bool _socketClosedRead = false; // The network socket is closed for reading.
- bool _socketClosedWrite = false; // The network socket is closed for writing.
- bool _closedRead = false; // The secure socket has fired an onClosed event.
- bool _closedWrite = false; // The secure socket has been closed for writing.
- Completer _closeCompleter = new Completer(); // The network socket is gone.
- _FilterStatus _filterStatus = new _FilterStatus();
- bool _connectPending = true;
- bool _filterPending = false;
- bool _filterActive = false;
-
- _SecureFilter _secureFilter = new _SecureFilter();
- String _selectedProtocol;
-
- static Future<_RawSecureSocket> connect(
- dynamic/*String|InternetAddress*/ host,
- int requestedPort,
- {bool is_server,
- SecurityContext context,
- RawSocket socket,
- StreamSubscription subscription,
- List<int> bufferedData,
- bool requestClientCertificate: false,
- bool requireClientCertificate: false,
- bool onBadCertificate(X509Certificate certificate),
- List<String> supportedProtocols}) {
- _verifyFields(host, requestedPort, is_server,
- requestClientCertificate, requireClientCertificate,
- onBadCertificate);
- if (host is InternetAddress) host = host.host;
- InternetAddress address = socket.address;
- if (host != null) {
- address = InternetAddress._cloneWithNewHost(address, host);
- }
- return new _RawSecureSocket(address,
- requestedPort,
- is_server,
- context,
- socket,
- subscription,
- bufferedData,
- requestClientCertificate,
- requireClientCertificate,
- onBadCertificate,
- supportedProtocols)
- ._handshakeComplete.future;
- }
-
- _RawSecureSocket(
- this.address,
- int requestedPort,
- this.is_server,
- this.context,
- RawSocket this._socket,
- this._socketSubscription,
- this._bufferedData,
- this.requestClientCertificate,
- this.requireClientCertificate,
- this.onBadCertificate(X509Certificate certificate),
- List<String> supportedProtocols) {
- if (context == null) {
- context = SecurityContext.defaultContext;
- }
- _controller = new StreamController<RawSocketEvent>(
- sync: true,
- onListen: _onSubscriptionStateChange,
- onPause: _onPauseStateChange,
- onResume: _onPauseStateChange,
- onCancel: _onSubscriptionStateChange);
- _stream = _controller.stream;
- // Throw an ArgumentError if any field is invalid. After this, all
- // errors will be reported through the future or the stream.
- _secureFilter.init();
- _secureFilter.registerHandshakeCompleteCallback(
- _secureHandshakeCompleteHandler);
- if (onBadCertificate != null) {
- _secureFilter.registerBadCertificateCallback(_onBadCertificateWrapper);
- }
- _socket.readEventsEnabled = true;
- _socket.writeEventsEnabled = false;
- if (_socketSubscription == null) {
- // If a current subscription is provided use this otherwise
- // create a new one.
- _socketSubscription = _socket.listen(_eventDispatcher,
- onError: _reportError,
- onDone: _doneHandler);
- } else {
- if (_socketSubscription.isPaused) {
- _socket.close();
- throw new ArgumentError(
- "Subscription passed to TLS upgrade is paused");
- }
- // If we are upgrading a socket that is already closed for read,
- // report an error as if we received READ_CLOSED during the handshake.
- dynamic s = _socket; // Cast to dynamic to avoid warning.
- if (s._socket.closedReadEventSent) {
- _eventDispatcher(RawSocketEvent.READ_CLOSED);
- }
- _socketSubscription
- ..onData(_eventDispatcher)
- ..onError(_reportError)
- ..onDone(_doneHandler);
- }
- try {
- var encodedProtocols =
- SecurityContext._protocolsToLengthEncoding(supportedProtocols);
- _secureFilter.connect(address.host,
- context,
- is_server,
- requestClientCertificate ||
- requireClientCertificate,
- requireClientCertificate,
- encodedProtocols);
- _secureHandshake();
- } catch (e, s) {
- _reportError(e, s);
- }
- }
-
- StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data),
- {Function onError,
- void onDone(),
- bool cancelOnError}) {
- _sendWriteEvent();
- return _stream.listen(onData,
- onError: onError,
- onDone: onDone,
- cancelOnError: cancelOnError);
- }
-
- static void _verifyFields(host,
- int requestedPort,
- bool is_server,
- bool requestClientCertificate,
- bool requireClientCertificate,
- Function onBadCertificate) {
- if (host is! String && host is! InternetAddress) {
- throw new ArgumentError("host is not a String or an InternetAddress");
- }
- if (requestedPort is! int) {
- throw new ArgumentError("requestedPort is not an int");
- }
- if (requestedPort < 0 || requestedPort > 65535) {
- throw new ArgumentError("requestedPort is not in the range 0..65535");
- }
- if (requestClientCertificate is! bool) {
- throw new ArgumentError("requestClientCertificate is not a bool");
- }
- if (requireClientCertificate is! bool) {
- throw new ArgumentError("requireClientCertificate is not a bool");
- }
- if (onBadCertificate != null && onBadCertificate is! Function) {
- throw new ArgumentError("onBadCertificate is not null or a Function");
- }
- }
-
- int get port => _socket.port;
-
- InternetAddress get remoteAddress => _socket.remoteAddress;
-
- int get remotePort => _socket.remotePort;
-
- void set _owner(owner) {
- (_socket as dynamic)._owner = owner;
- }
-
- int available() {
- return _status != CONNECTED ? 0
- : _secureFilter.buffers[READ_PLAINTEXT].length;
- }
-
- Future<RawSecureSocket> close() {
- shutdown(SocketDirection.BOTH);
- return _closeCompleter.future;
- }
-
- void _completeCloseCompleter([dummy]) {
- if (!_closeCompleter.isCompleted) _closeCompleter.complete(this);
- }
-
- void _close() {
- _closedWrite = true;
- _closedRead = true;
- if (_socket != null) {
- _socket.close().then(_completeCloseCompleter);
- } else {
- _completeCloseCompleter();
- }
- _socketClosedWrite = true;
- _socketClosedRead = true;
- if (!_filterActive && _secureFilter != null) {
- _secureFilter.destroy();
- _secureFilter = null;
- }
- if (_socketSubscription != null) {
- _socketSubscription.cancel();
- }
- _controller.close();
- _status = CLOSED;
- }
-
- void shutdown(SocketDirection direction) {
- if (direction == SocketDirection.SEND ||
- direction == SocketDirection.BOTH) {
- _closedWrite = true;
- if (_filterStatus.writeEmpty) {
- _socket.shutdown(SocketDirection.SEND);
- _socketClosedWrite = true;
- if (_closedRead) {
- _close();
- }
- }
- }
- if (direction == SocketDirection.RECEIVE ||
- direction == SocketDirection.BOTH) {
- _closedRead = true;
- _socketClosedRead = true;
- _socket.shutdown(SocketDirection.RECEIVE);
- if (_socketClosedWrite) {
- _close();
- }
- }
- }
-
- bool get writeEventsEnabled => _writeEventsEnabled;
-
- void set writeEventsEnabled(bool value) {
- _writeEventsEnabled = value;
- if (value) {
- Timer.run(() => _sendWriteEvent());
- }
- }
-
- bool get readEventsEnabled => _readEventsEnabled;
-
- void set readEventsEnabled(bool value) {
- _readEventsEnabled = value;
- _scheduleReadEvent();
- }
-
- List<int> read([int length]) {
- if (length != null && (length is! int || length < 0)) {
- throw new ArgumentError(
- "Invalid length parameter in SecureSocket.read (length: $length)");
- }
- if (_closedRead) {
- throw new SocketException("Reading from a closed socket");
- }
- if (_status != CONNECTED) {
- return null;
- }
- var result = _secureFilter.buffers[READ_PLAINTEXT].read(length);
- _scheduleFilter();
- return result;
- }
-
- // Write the data to the socket, and schedule the filter to encrypt it.
- int write(List<int> data, [int offset, int bytes]) {
- if (bytes != null && (bytes is! int || bytes < 0)) {
- throw new ArgumentError(
- "Invalid bytes parameter in SecureSocket.read (bytes: $bytes)");
- }
- if (offset != null && (offset is! int || offset < 0)) {
- throw new ArgumentError(
- "Invalid offset parameter in SecureSocket.read (offset: $offset)");
- }
- if (_closedWrite) {
- _controller.addError(new SocketException("Writing to a closed socket"));
- return 0;
- }
- if (_status != CONNECTED) return 0;
- if (offset == null) offset = 0;
- if (bytes == null) bytes = data.length - offset;
-
- int written =
- _secureFilter.buffers[WRITE_PLAINTEXT].write(data, offset, bytes);
- if (written > 0) {
- _filterStatus.writeEmpty = false;
- }
- _scheduleFilter();
- return written;
- }
-
- X509Certificate get peerCertificate => _secureFilter.peerCertificate;
-
- String get selectedProtocol => _selectedProtocol;
-
- bool _onBadCertificateWrapper(X509Certificate certificate) {
- if (onBadCertificate == null) return false;
- var result = onBadCertificate(certificate);
- if (result is bool) return result;
- throw new HandshakeException(
- "onBadCertificate callback returned non-boolean $result");
- }
-
- bool setOption(SocketOption option, bool enabled) {
- if (_socket == null) return false;
- return _socket.setOption(option, enabled);
- }
-
- void _eventDispatcher(RawSocketEvent event) {
- try {
- if (event == RawSocketEvent.READ) {
- _readHandler();
- } else if (event == RawSocketEvent.WRITE) {
- _writeHandler();
- } else if (event == RawSocketEvent.READ_CLOSED) {
- _closeHandler();
- }
- } catch (e, stackTrace) {
- _reportError(e, stackTrace);
- }
- }
-
- void _readHandler() {
- _readSocket();
- _scheduleFilter();
- }
-
- void _writeHandler() {
- _writeSocket();
- _scheduleFilter();
- }
-
- void _doneHandler() {
- if (_filterStatus.readEmpty) {
- _close();
- }
- }
-
- void _reportError(e, [StackTrace stackTrace]) {
- if (_status == CLOSED) {
- return;
- } else if (_connectPending) {
- // _connectPending is true until the handshake has completed, and the
- // _handshakeComplete future returned from SecureSocket.connect has
- // completed. Before this point, we must complete it with an error.
- _handshakeComplete.completeError(e, stackTrace);
- } else {
- _controller.addError(e, stackTrace);
- }
- _close();
- }
-
- void _closeHandler() {
- if (_status == CONNECTED) {
- if (_closedRead) return;
- _socketClosedRead = true;
- if (_filterStatus.readEmpty) {
- _closedRead = true;
- _controller.add(RawSocketEvent.READ_CLOSED);
- if (_socketClosedWrite) {
- _close();
- }
- } else {
- _scheduleFilter();
- }
- } else if (_status == HANDSHAKE) {
- _socketClosedRead = true;
- if (_filterStatus.readEmpty) {
- _reportError(
- new HandshakeException('Connection terminated during handshake'),
- null);
- } else {
- _secureHandshake();
- }
- }
- }
-
- void _secureHandshake() {
- try {
- _secureFilter.handshake();
- _filterStatus.writeEmpty = false;
- _readSocket();
- _writeSocket();
- _scheduleFilter();
- } catch (e, stackTrace) {
- _reportError(e, stackTrace);
- }
- }
-
- void renegotiate({bool useSessionCache: true,
- bool requestClientCertificate: false,
- bool requireClientCertificate: false}) {
- if (_status != CONNECTED) {
- throw new HandshakeException(
- "Called renegotiate on a non-connected socket");
- }
- _secureFilter.renegotiate(useSessionCache,
- requestClientCertificate,
- requireClientCertificate);
- _status = HANDSHAKE;
- _filterStatus.writeEmpty = false;
- _scheduleFilter();
- }
-
- void _secureHandshakeCompleteHandler() {
- _status = CONNECTED;
- if (_connectPending) {
- _connectPending = false;
- 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);
- }
- }
- }
-
- void _onPauseStateChange() {
- if (_controller.isPaused) {
- _pauseCount++;
- } else {
- _pauseCount--;
- if (_pauseCount == 0) {
- _scheduleReadEvent();
- _sendWriteEvent(); // Can send event synchronously.
- }
- }
-
- if (!_socketClosedRead || !_socketClosedWrite) {
- if (_controller.isPaused) {
- _socketSubscription.pause();
- } else {
- _socketSubscription.resume();
- }
- }
- }
-
- void _onSubscriptionStateChange() {
- if (_controller.hasListener) {
- // TODO(ajohnsen): Do something here?
- }
- }
-
- void _scheduleFilter() {
- _filterPending = true;
- _tryFilter();
- }
-
- void _tryFilter() {
- if (_status == CLOSED) {
- return;
- }
- if (_filterPending && !_filterActive) {
- _filterActive = true;
- _filterPending = false;
- _pushAllFilterStages().then((status) {
- _filterStatus = status;
- _filterActive = false;
- if (_status == CLOSED) {
- _secureFilter.destroy();
- _secureFilter = null;
- return;
- }
- _socket.readEventsEnabled = true;
- if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
- // Checks for and handles all cases of partially closed sockets.
- shutdown(SocketDirection.SEND);
- if (_status == CLOSED) {
- return;
- }
- }
- if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
- if (_status == HANDSHAKE) {
- _secureFilter.handshake();
- if (_status == HANDSHAKE) {
- throw new HandshakeException(
- 'Connection terminated during handshake');
- }
- }
- _closeHandler();
- }
- if (_status == CLOSED) {
- return;
- }
- if (_filterStatus.progress) {
- _filterPending = true;
- if (_filterStatus.writeEncryptedNoLongerEmpty) {
- _writeSocket();
- }
- if (_filterStatus.writePlaintextNoLongerFull) {
- _sendWriteEvent();
- }
- if (_filterStatus.readEncryptedNoLongerFull) {
- _readSocket();
- }
- if (_filterStatus.readPlaintextNoLongerEmpty) {
- _scheduleReadEvent();
- }
- if (_status == HANDSHAKE) {
- _secureHandshake();
- }
- }
- _tryFilter();
- }).catchError(_reportError);
- }
- }
-
- List<int> _readSocketOrBufferedData(int bytes) {
- if (_bufferedData != null) {
- if (bytes > _bufferedData.length - _bufferedDataIndex) {
- bytes = _bufferedData.length - _bufferedDataIndex;
- }
- var result = _bufferedData.sublist(_bufferedDataIndex,
- _bufferedDataIndex + bytes);
- _bufferedDataIndex += bytes;
- if (_bufferedData.length == _bufferedDataIndex) {
- _bufferedData = null;
- }
- return result;
- } else if (!_socketClosedRead) {
- return _socket.read(bytes);
- } else {
- return null;
- }
- }
-
- void _readSocket() {
- if (_status == CLOSED) return;
- var buffer = _secureFilter.buffers[READ_ENCRYPTED];
- if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) {
- _filterStatus.readEmpty = false;
- } else {
- _socket.readEventsEnabled = false;
- }
- }
-
- void _writeSocket() {
- if (_socketClosedWrite) return;
- var buffer = _secureFilter.buffers[WRITE_ENCRYPTED];
- if (buffer.readToSocket(_socket)) { // Returns true if blocked
- _socket.writeEventsEnabled = true;
- }
- }
-
- // If a read event should be sent, add it to the controller.
- _scheduleReadEvent() {
- if (!_pendingReadEvent &&
- _readEventsEnabled &&
- _pauseCount == 0 &&
- _secureFilter != null &&
- !_secureFilter.buffers[READ_PLAINTEXT].isEmpty) {
- _pendingReadEvent = true;
- Timer.run(_sendReadEvent);
- }
- }
-
- _sendReadEvent() {
- _pendingReadEvent = false;
- if (_status != CLOSED &&
- _readEventsEnabled &&
- _pauseCount == 0 &&
- _secureFilter != null &&
- !_secureFilter.buffers[READ_PLAINTEXT].isEmpty) {
- _controller.add(RawSocketEvent.READ);
- _scheduleReadEvent();
- }
- }
-
- // If a write event should be sent, add it to the controller.
- _sendWriteEvent() {
- if (!_closedWrite &&
- _writeEventsEnabled &&
- _pauseCount == 0 &&
- _secureFilter != null &&
- _secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
- _writeEventsEnabled = false;
- _controller.add(RawSocketEvent.WRITE);
- }
- }
-
- Future<_FilterStatus> _pushAllFilterStages() {
- bool wasInHandshake = _status != CONNECTED;
- List args = new List(2 + NUM_BUFFERS * 2);
- args[0] = _secureFilter._pointer();
- args[1] = wasInHandshake;
- var bufs = _secureFilter.buffers;
- for (var i = 0; i < NUM_BUFFERS; ++i) {
- args[2 * i + 2] = bufs[i].start;
- args[2 * i + 3] = bufs[i].end;
- }
-
- return _IOService._dispatch(_SSL_PROCESS_FILTER, args).then((response) {
- if (response.length == 2) {
- if (wasInHandshake) {
- // If we're in handshake, throw a handshake error.
- _reportError(
- new HandshakeException('${response[1]} error ${response[0]}'),
- null);
- } else {
- // If we're connected, throw a TLS error.
- _reportError(new TlsException('${response[1]} error ${response[0]}'),
- null);
- }
- }
- int start(int index) => response[2 * index];
- int end(int index) => response[2 * index + 1];
-
- _FilterStatus status = new _FilterStatus();
- // Compute writeEmpty as "write plaintext buffer and write encrypted
- // buffer were empty when we started and are empty now".
- status.writeEmpty = bufs[WRITE_PLAINTEXT].isEmpty &&
- start(WRITE_ENCRYPTED) == end(WRITE_ENCRYPTED);
- // If we were in handshake when this started, _writeEmpty may be false
- // because the handshake wrote data after we checked.
- if (wasInHandshake) status.writeEmpty = false;
-
- // Compute readEmpty as "both read buffers were empty when we started
- // and are empty now".
- status.readEmpty = bufs[READ_ENCRYPTED].isEmpty &&
- start(READ_PLAINTEXT) == end(READ_PLAINTEXT);
-
- _ExternalBuffer buffer = bufs[WRITE_PLAINTEXT];
- int new_start = start(WRITE_PLAINTEXT);
- if (new_start != buffer.start) {
- status.progress = true;
- if (buffer.free == 0) {
- status.writePlaintextNoLongerFull = true;
- }
- buffer.start = new_start;
- }
- buffer = bufs[READ_ENCRYPTED];
- new_start = start(READ_ENCRYPTED);
- if (new_start != buffer.start) {
- status.progress = true;
- if (buffer.free == 0) {
- status.readEncryptedNoLongerFull = true;
- }
- buffer.start = new_start;
- }
- buffer = bufs[WRITE_ENCRYPTED];
- int new_end = end(WRITE_ENCRYPTED);
- if (new_end != buffer.end) {
- status.progress = true;
- if (buffer.length == 0) {
- status.writeEncryptedNoLongerEmpty = true;
- }
- buffer.end = new_end;
- }
- buffer = bufs[READ_PLAINTEXT];
- new_end = end(READ_PLAINTEXT);
- if (new_end != buffer.end) {
- status.progress = true;
- if (buffer.length == 0) {
- status.readPlaintextNoLongerEmpty = true;
- }
- buffer.end = new_end;
- }
- return status;
- });
- }
-}
-
-
-/**
- * A circular buffer backed by an external byte array. Accessed from
- * both C++ and Dart code in an unsynchronized way, with one reading
- * and one writing. All updates to start and end are done by Dart code.
- */
-class _ExternalBuffer {
- List data; // This will be a ExternalByteArray, backed by C allocated data.
- int start;
- int end;
- final size;
-
- _ExternalBuffer(this.size) {
- start = end = size ~/ 2;
- }
-
- void advanceStart(int bytes) {
- assert(start > end || start + bytes <= end);
- start += bytes;
- if (start >= size) {
- start -= size;
- assert(start <= end);
- assert(start < size);
- }
- }
-
- void advanceEnd(int bytes) {
- assert(start <= end || start > end + bytes);
- end += bytes;
- if (end >= size) {
- end -= size;
- assert(end < start);
- assert(end < size);
- }
- }
-
- bool get isEmpty => end == start;
-
- int get length =>
- start > end ? size + end - start : end - start;
-
- int get linearLength =>
- start > end ? size - start : end - start;
-
- int get free =>
- start > end ? start - end - 1 : size + start - end - 1;
-
- int get linearFree {
- if (start > end) return start - end - 1;
- if (start == 0) return size - end - 1;
- return size - end;
- }
-
- List<int> read(int bytes) {
- if (bytes == null) {
- bytes = length;
- } else {
- bytes = min(bytes, length);
- }
- if (bytes == 0) return null;
- List<int> result = new Uint8List(bytes);
- int bytesRead = 0;
- // Loop over zero, one, or two linear data ranges.
- while (bytesRead < bytes) {
- int toRead = min(bytes - bytesRead, linearLength);
- result.setRange(bytesRead,
- bytesRead + toRead,
- data,
- start);
- advanceStart(toRead);
- bytesRead += toRead;
- }
- return result;
- }
-
- int write(List<int> inputData, int offset, int bytes) {
- if (bytes > free) {
- bytes = free;
- }
- int written = 0;
- int toWrite = min(bytes, linearFree);
- // Loop over zero, one, or two linear data ranges.
- while (toWrite > 0) {
- data.setRange(end, end + toWrite, inputData, offset);
- advanceEnd(toWrite);
- offset += toWrite;
- written += toWrite;
- toWrite = min(bytes - written, linearFree);
- }
- return written;
- }
-
- int writeFromSource(List<int> getData(int requested)) {
- int written = 0;
- int toWrite = linearFree;
- // Loop over zero, one, or two linear data ranges.
- while (toWrite > 0) {
- // Source returns at most toWrite bytes, and it returns null when empty.
- var inputData = getData(toWrite);
- if (inputData == null || inputData.length == 0) break;
- var len = inputData.length;
- data.setRange(end, end + len, inputData);
- advanceEnd(len);
- written += len;
- toWrite = linearFree;
- }
- return written;
- }
-
- bool readToSocket(RawSocket socket) {
- // Loop over zero, one, or two linear data ranges.
- while (true) {
- var toWrite = linearLength;
- if (toWrite == 0) return false;
- int bytes = socket.write(data, start, toWrite);
- advanceStart(bytes);
- if (bytes < toWrite) {
- // The socket has blocked while we have data to write.
- return true;
- }
- }
- }
-}
-
-
-abstract class _SecureFilter {
- external factory _SecureFilter();
-
- void connect(String hostName,
- SecurityContext context,
- bool is_server,
- bool requestClientCertificate,
- bool requireClientCertificate,
- Uint8List protocols);
- void destroy();
- void handshake();
- String selectedProtocol();
- void rehandshake();
- void renegotiate(bool useSessionCache,
- bool requestClientCertificate,
- bool requireClientCertificate);
- void init();
- X509Certificate get peerCertificate;
- int processBuffer(int bufferIndex);
- void registerBadCertificateCallback(Function callback);
- void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
-
- // This call may cause a reference counted pointer in the native
- // implementation to be retained. It should only be called when the resulting
- // value is passed to the IO service through a call to dispatch().
- int _pointer();
-
- List<_ExternalBuffer> get buffers;
-}
-
-/** A secure networking exception caused by a failure in the
- * TLS/SSL protocol.
- */
-class TlsException implements IOException {
- final String type;
- final String message;
- final OSError osError;
-
- const TlsException([String message = "",
- OSError osError = null])
- : this._("TlsException", message, osError);
-
- const TlsException._(this.type, this.message, this.osError);
-
- String toString() {
- StringBuffer sb = new StringBuffer();
- sb.write(type);
- if (!message.isEmpty) {
- sb.write(": $message");
- if (osError != null) {
- sb.write(" ($osError)");
- }
- } else if (osError != null) {
- sb.write(": $osError");
- }
- return sb.toString();
- }
-}
-
-
-/**
- * An exception that happens in the handshake phase of establishing
- * a secure network connection.
- */
-class HandshakeException extends TlsException {
- const HandshakeException([String message = "",
- OSError osError = null])
- : super._("HandshakeException", message, osError);
-}
-
-
-/**
- * An exception that happens in the handshake phase of establishing
- * a secure network connection, when looking up or verifying a
- * certificate.
- */
-class CertificateException extends TlsException {
- const CertificateException([String message = "",
- OSError osError = null])
- : super._("CertificateException", message, osError);
-}

Powered by Google App Engine
This is Rietveld 408576698