| Index: sdk/lib/io/http_impl.dart
|
| diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
|
| index b2d63b6a393a235fb017ba160bef1ed609b04a8e..1afbb43bdfdcab2087628ce3def5d9645a5ec65f 100644
|
| --- a/sdk/lib/io/http_impl.dart
|
| +++ b/sdk/lib/io/http_impl.dart
|
| @@ -1071,6 +1071,7 @@ class _HttpClientConnection {
|
| StreamSubscription _subscription;
|
| final _HttpClient _httpClient;
|
| bool _dispose = false;
|
| + Timer _idleTimer;
|
| bool closed = false;
|
|
|
| Completer<_HttpIncoming> _nextResponseCompleter;
|
| @@ -1285,6 +1286,22 @@ class _HttpClientConnection {
|
| return isSecure ? "ssh:$host:$port" : "$host:$port";
|
| }
|
|
|
| + void stopTimer() {
|
| + if (_idleTimer != null) {
|
| + _idleTimer.cancel();
|
| + _idleTimer = null;
|
| + }
|
| + }
|
| +
|
| + void startTimer() {
|
| + assert(_idleTimer == null);
|
| + _idleTimer = new Timer(
|
| + _httpClient.idleTimeout,
|
| + () {
|
| + _idleTimer = null;
|
| + close();
|
| + });
|
| + }
|
| }
|
|
|
| class _ConnnectionInfo {
|
| @@ -1296,7 +1313,6 @@ class _ConnnectionInfo {
|
|
|
| class _HttpClient implements HttpClient {
|
| // TODO(ajohnsen): Use eviction timeout.
|
| - static const int DEFAULT_EVICTION_TIMEOUT = 60000;
|
| bool _closing = false;
|
|
|
| final Map<String, Set<_HttpClientConnection>> _idleConnections
|
| @@ -1308,6 +1324,21 @@ class _HttpClient implements HttpClient {
|
| Function _authenticate;
|
| Function _authenticateProxy;
|
| Function _findProxy = HttpClient.findProxyFromEnvironment;
|
| + Duration _idleTimeout = const Duration(seconds: 15);
|
| +
|
| + Timer _noActiveTimer;
|
| +
|
| + Duration get idleTimeout => _idleTimeout;
|
| +
|
| + void set idleTimeout(Duration timeout) {
|
| + _idleTimeout = timeout;
|
| + var idle = _idleConnections.values.forEach(
|
| + (l) => l.forEach((c) {
|
| + // Reset timer. This is fine, as it's not happening often.
|
| + c.stopTimer();
|
| + c.startTimer();
|
| + }));
|
| + }
|
|
|
| Future<HttpClientRequest> open(String method,
|
| String host,
|
| @@ -1485,15 +1516,17 @@ class _HttpClient implements HttpClient {
|
| connection.close();
|
| return;
|
| }
|
| - // TODO(ajohnsen): Listen for socket close events.
|
| if (!_idleConnections.containsKey(connection.key)) {
|
| _idleConnections[connection.key] = new LinkedHashSet();
|
| }
|
| _idleConnections[connection.key].add(connection);
|
| + connection.startTimer();
|
| + _updateTimers();
|
| }
|
|
|
| // Remove a closed connnection from the active set.
|
| void _connectionClosed(_HttpClientConnection connection) {
|
| + connection.stopTimer();
|
| _activeConnections.remove(connection);
|
| if (_idleConnections.containsKey(connection.key)) {
|
| _idleConnections[connection.key].remove(connection);
|
| @@ -1501,6 +1534,24 @@ class _HttpClient implements HttpClient {
|
| _idleConnections.remove(connection.key);
|
| }
|
| }
|
| + _updateTimers();
|
| + }
|
| +
|
| + void _updateTimers() {
|
| + if (_activeConnections.isEmpty) {
|
| + if (!_idleConnections.isEmpty && _noActiveTimer == null) {
|
| + _noActiveTimer = new Timer(const Duration(milliseconds: 100), () {
|
| + _noActiveTimer = null;
|
| + if (_activeConnections.isEmpty) {
|
| + close();
|
| + _closing = false;
|
| + }
|
| + });
|
| + }
|
| + } else if (_noActiveTimer != null) {
|
| + _noActiveTimer.cancel();
|
| + _noActiveTimer = null;
|
| + }
|
| }
|
|
|
| // Get a new _HttpClientConnection, either from the idle pool or created from
|
| @@ -1523,7 +1574,9 @@ class _HttpClient implements HttpClient {
|
| if (_idleConnections[key].isEmpty) {
|
| _idleConnections.remove(key);
|
| }
|
| + connection.stopTimer();
|
| _activeConnections.add(connection);
|
| + _updateTimers();
|
| return new Future.value(new _ConnnectionInfo(connection, proxy));
|
| }
|
| return (isSecure && proxy.isDirect
|
|
|