| Index: sdk/lib/io/http_impl.dart
|
| diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
|
| index 2af9f6cb9db19e754c6efb9b330c54fa2e40c827..5b991260bf79d6a5e8286244ec0efaf05cd3cc2a 100644
|
| --- a/sdk/lib/io/http_impl.dart
|
| +++ b/sdk/lib/io/http_impl.dart
|
| @@ -1494,27 +1494,31 @@ class _HttpClientConnection {
|
| }
|
| }
|
|
|
| -class _ConnnectionInfo {
|
| +class _ConnectionInfo {
|
| final _HttpClientConnection connection;
|
| final _Proxy proxy;
|
|
|
| - _ConnnectionInfo(this.connection, this.proxy);
|
| + _ConnectionInfo(this.connection, this.proxy);
|
| }
|
|
|
|
|
| class _ConnectionTarget {
|
| // Unique key for this connection target.
|
| final String key;
|
| + final String host;
|
| + final int port;
|
| + final bool isSecure;
|
| final Set<_HttpClientConnection> _idle = new HashSet();
|
| final Set<_HttpClientConnection> _active = new HashSet();
|
| + int _connecting = 0;
|
|
|
| - _ConnectionTarget(this.key);
|
| + _ConnectionTarget(this.key, this.host, this.port, this.isSecure);
|
|
|
| - bool get isEmpty => _idle.isEmpty && _active.isEmpty;
|
| + bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0;
|
|
|
| bool get hasIdle => _idle.isNotEmpty;
|
|
|
| - bool get hasActive => _active.isNotEmpty;
|
| + bool get hasActive => _active.isNotEmpty && _connecting > 0;
|
|
|
| _HttpClientConnection takeIdle() {
|
| assert(hasIdle);
|
| @@ -1551,6 +1555,45 @@ class _ConnectionTarget {
|
| }
|
| }
|
| }
|
| +
|
| + Future<_ConnectionInfo> connect(String uriHost,
|
| + int uriPort,
|
| + _Proxy proxy,
|
| + _HttpClient client) {
|
| + if (hasIdle) {
|
| + var connection = takeIdle();
|
| + client._updateTimers();
|
| + return new Future.value(new _ConnectionInfo(connection, proxy));
|
| + }
|
| + var currentBadCertificateCallback = client._badCertificateCallback;
|
| + bool callback(X509Certificate certificate) =>
|
| + currentBadCertificateCallback == null ? false :
|
| + currentBadCertificateCallback(certificate, uriHost, uriPort);
|
| + Future socketFuture = (isSecure && proxy.isDirect
|
| + ? SecureSocket.connect(host,
|
| + port,
|
| + sendClientCertificate: true,
|
| + onBadCertificate: callback)
|
| + : Socket.connect(host, port));
|
| + _connecting++;
|
| + return socketFuture.then((socket) {
|
| + _connecting--;
|
| + socket.setOption(SocketOption.TCP_NODELAY, true);
|
| + var connection = new _HttpClientConnection(key, socket, client);
|
| + if (isSecure && !proxy.isDirect) {
|
| + connection._dispose = true;
|
| + return connection.createProxyTunnel(uriHost, uriPort, proxy, callback)
|
| + .then((tunnel) {
|
| + client._getConnectionTarget(uriHost, uriPort, true)
|
| + .addNewActive(tunnel);
|
| + return new _ConnectionInfo(tunnel, proxy);
|
| + });
|
| + } else {
|
| + addNewActive(connection);
|
| + return new _ConnectionInfo(connection, proxy);
|
| + }
|
| + });
|
| + }
|
| }
|
|
|
|
|
| @@ -1776,60 +1819,28 @@ class _HttpClient implements HttpClient {
|
| }
|
| }
|
|
|
| - // Get a new _HttpClientConnection, either from the idle pool or created from
|
| - // a new Socket.
|
| - Future<_ConnnectionInfo> _getConnection(String uriHost,
|
| + _ConnectionTarget _getConnectionTarget(String host, int port, bool isSecure) {
|
| + String key = _HttpClientConnection.makeKey(isSecure, host, port);
|
| + return _connectionTargets.putIfAbsent(
|
| + key, () => new _ConnectionTarget(key, host, port, isSecure));
|
| + }
|
| +
|
| + // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
|
| + Future<_ConnectionInfo> _getConnection(String uriHost,
|
| int uriPort,
|
| _ProxyConfiguration proxyConf,
|
| bool isSecure) {
|
| Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
|
|
|
| - Future<_ConnnectionInfo> connect(error) {
|
| + Future<_ConnectionInfo> connect(error) {
|
| if (!proxies.moveNext()) return new Future.error(error);
|
| _Proxy proxy = proxies.current;
|
| String host = proxy.isDirect ? uriHost: proxy.host;
|
| int port = proxy.isDirect ? uriPort: proxy.port;
|
| - String key = _HttpClientConnection.makeKey(isSecure, host, port);
|
| - var connectionTarget = _connectionTargets[key];
|
| - if (connectionTarget != null && connectionTarget.hasIdle) {
|
| - var connection = connectionTarget.takeIdle();
|
| - _updateTimers();
|
| - return new Future.value(new _ConnnectionInfo(connection, proxy));
|
| - }
|
| - var currentBadCertificateCallback = _badCertificateCallback;
|
| - bool callback(X509Certificate certificate) =>
|
| - currentBadCertificateCallback == null ? false :
|
| - currentBadCertificateCallback(certificate, uriHost, uriPort);
|
| - Future socketFuture = (isSecure && proxy.isDirect
|
| - ? SecureSocket.connect(host,
|
| - port,
|
| - sendClientCertificate: true,
|
| - onBadCertificate: callback)
|
| - : Socket.connect(host, port));
|
| - return socketFuture.then((socket) {
|
| - socket.setOption(SocketOption.TCP_NODELAY, true);
|
| - var connection = new _HttpClientConnection(key, socket, this);
|
| - if (isSecure && !proxy.isDirect) {
|
| - connection._dispose = true;
|
| - return connection.createProxyTunnel(
|
| - uriHost, uriPort, proxy, callback)
|
| - .then((tunnel) {
|
| - var connectionTarget = _connectionTargets
|
| - .putIfAbsent(tunnel.key,
|
| - () => new _ConnectionTarget(tunnel.key));
|
| - connectionTarget.addNewActive(tunnel);
|
| - return new _ConnnectionInfo(tunnel, proxy);
|
| - });
|
| - } else {
|
| - var connectionTarget = _connectionTargets
|
| - .putIfAbsent(key, () => new _ConnectionTarget(key));
|
| - connectionTarget.addNewActive(connection);
|
| - return new _ConnnectionInfo(connection, proxy);
|
| - }
|
| - }, onError: (error) {
|
| - // Continue with next proxy.
|
| - return connect(error);
|
| - });
|
| + return _getConnectionTarget(host, port, isSecure)
|
| + .connect(uriHost, uriPort, proxy, this)
|
| + // On error, continue with next proxy.
|
| + .catchError(connect);
|
| }
|
| return connect(new HttpException("No proxies given"));
|
| }
|
|
|