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 |