Index: sdk/lib/io/http_impl.dart |
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart |
index 53159bbe3b7185a3ad175dc1939c6c99caeca2c5..5bc5b97cae902e5b01162391de71b196bc53bc52 100644 |
--- a/sdk/lib/io/http_impl.dart |
+++ b/sdk/lib/io/http_impl.dart |
@@ -1895,24 +1895,22 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> { |
static const _CLOSING = 2; |
static const _DETACHED = 3; |
- int _state = _IDLE; |
- |
final Socket _socket; |
final _HttpServer _httpServer; |
final _HttpParser _httpParser; |
+ int _state = _IDLE; |
StreamSubscription _subscription; |
Timer _idleTimer; |
final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE); |
- |
+ bool _idleMark = false; |
Future _streamFuture; |
_HttpConnection(this._socket, this._httpServer) |
: _httpParser = new _HttpParser.requestParser() { |
- _startTimeout(); |
_httpParser.listenToStream(_socket); |
_subscription = _httpParser.listen( |
(incoming) { |
- _stopTimeout(); |
+ _httpServer._markActive(this); |
// If the incoming was closed, close the connection. |
incoming.dataDone.then((closing) { |
if (closing) destroy(); |
@@ -1937,7 +1935,8 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> { |
!_httpParser.upgrade && |
!_httpServer.closed) { |
_state = _IDLE; |
- _startTimeout(); |
+ _idleMark = false; |
+ _httpServer._markIdle(this); |
// Resume the subscription for incoming requests as the |
// request is now processed. |
_subscription.resume(); |
@@ -1962,21 +1961,13 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> { |
}); |
} |
- void _startTimeout() { |
- assert(_state == _IDLE); |
- _stopTimeout(); |
- if (_httpServer.idleTimeout == null) return; |
- _idleTimer = new Timer(_httpServer.idleTimeout, () { |
- destroy(); |
- }); |
+ void markIdle() { |
+ _idleMark = true; |
} |
- void _stopTimeout() { |
- if (_idleTimer != null) _idleTimer.cancel(); |
- } |
+ bool get isMarkedIdle => _idleMark; |
void destroy() { |
- _stopTimeout(); |
if (_state == _CLOSING || _state == _DETACHED) return; |
_state = _CLOSING; |
_socket.destroy(); |
@@ -1984,7 +1975,6 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> { |
} |
Future<Socket> detachSocket() { |
- _stopTimeout(); |
_state = _DETACHED; |
// Remove connection from server. |
_httpServer._connectionClosed(this); |
@@ -2009,7 +1999,8 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> { |
class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
String serverHeader; |
- Duration idleTimeout = const Duration(seconds: 120); |
+ Duration _idleTimeout; |
+ Timer _idleTimer; |
static Future<HttpServer> bind(address, int port, int backlog) { |
return ServerSocket.bind(address, port, backlog: backlog).then((socket) { |
@@ -2036,11 +2027,34 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
_HttpServer._(this._serverSocket, this._closeServer) { |
_controller = new StreamController<HttpRequest>(sync: true, |
onCancel: close); |
+ idleTimeout = const Duration(seconds: 120); |
} |
_HttpServer.listenOn(this._serverSocket) : _closeServer = false { |
_controller = new StreamController<HttpRequest>(sync: true, |
onCancel: close); |
+ idleTimeout = const Duration(seconds: 120); |
+ } |
+ |
+ Duration get idleTimeout => _idleTimeout; |
+ |
+ void set idleTimeout(Duration duration) { |
+ if (_idleTimer != null) { |
+ _idleTimer.cancel(); |
+ _idleTimer = null; |
+ } |
+ _idleTimeout = duration; |
+ if (_idleTimeout != null) { |
+ _idleTimer = new Timer.periodic(_idleTimeout, (_) { |
+ for (var idle in _idleConnections.toList()) { |
+ if (idle.isMarkedIdle) { |
+ idle.destroy(); |
+ } else { |
+ idle.markIdle(); |
+ } |
+ } |
+ }); |
+ } |
} |
StreamSubscription<HttpRequest> listen(void onData(HttpRequest event), |
@@ -2052,7 +2066,7 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
socket.setOption(SocketOption.TCP_NODELAY, true); |
// Accept the client connection. |
_HttpConnection connection = new _HttpConnection(socket, this); |
- _connections.add(connection); |
+ _idleConnections.add(connection); |
}, |
onError: (error) { |
// Ignore HandshakeExceptions as they are bound to a single request, |
@@ -2076,15 +2090,15 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
} else { |
result = new Future.value(); |
} |
+ idleTimeout = null; |
if (force) { |
- for (var c in _connections.toList()) { |
- c.destroy(); |
- } |
- assert(_connections.isEmpty); |
- } else { |
- for (var c in _connections.where((c) => c._isIdle).toList()) { |
+ for (var c in _activeConnections.toList()) { |
c.destroy(); |
} |
+ assert(_activeConnections.isEmpty); |
+ } |
+ for (var c in _idleConnections.toList()) { |
+ c.destroy(); |
} |
_maybeCloseSessionManager(); |
return result; |
@@ -2092,7 +2106,8 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
void _maybeCloseSessionManager() { |
if (closed && |
- _connections.isEmpty && |
+ _idleConnections.isEmpty && |
+ _activeConnections.isEmpty && |
_sessionManagerInstance != null) { |
_sessionManagerInstance.close(); |
_sessionManagerInstance = null; |
@@ -2120,10 +2135,21 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
} |
void _connectionClosed(_HttpConnection connection) { |
- _connections.remove(connection); |
+ // Remove itself from either idle or active connections. |
+ connection.unlink(); |
_maybeCloseSessionManager(); |
} |
+ void _markIdle(_HttpConnection connection) { |
+ _activeConnections.remove(connection); |
+ _idleConnections.add(connection); |
+ } |
+ |
+ void _markActive(_HttpConnection connection) { |
+ _idleConnections.remove(connection); |
+ _activeConnections.add(connection); |
+ } |
+ |
_HttpSessionManager get _sessionManager { |
// Lazy init. |
if (_sessionManagerInstance == null) { |
@@ -2134,17 +2160,19 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
HttpConnectionsInfo connectionsInfo() { |
HttpConnectionsInfo result = new HttpConnectionsInfo(); |
- result.total = _connections.length; |
- _connections.forEach((_HttpConnection conn) { |
+ result.total = _activeConnections.length + _idleConnections.length; |
+ _activeConnections.forEach((_HttpConnection conn) { |
if (conn._isActive) { |
result.active++; |
- } else if (conn._isIdle) { |
- result.idle++; |
} else { |
assert(conn._isClosing); |
result.closing++; |
} |
}); |
+ _idleConnections.forEach((_HttpConnection conn) { |
+ result.idle++; |
+ assert(conn._isIdle); |
+ }); |
return result; |
} |
@@ -2159,10 +2187,11 @@ class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
final bool _closeServer; |
// Set of currently connected clients. |
- final LinkedList<_HttpConnection> _connections |
+ final LinkedList<_HttpConnection> _activeConnections |
+ = new LinkedList<_HttpConnection>(); |
+ final LinkedList<_HttpConnection> _idleConnections |
= new LinkedList<_HttpConnection>(); |
StreamController<HttpRequest> _controller; |
- // TODO(ajohnsen): Use close queue? |
} |