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

Side by Side Diff: sdk/lib/io/http_impl.dart

Issue 176893003: Only use one timer to handle HttpServer::idleTimeout. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.io; 5 part of dart.io;
6 6
7 const int _HEADERS_BUFFER_SIZE = 8 * 1024; 7 const int _HEADERS_BUFFER_SIZE = 8 * 1024;
8 8
9 class _HttpIncoming extends Stream<List<int>> { 9 class _HttpIncoming extends Stream<List<int>> {
10 final int _transferLength; 10 final int _transferLength;
(...skipping 1884 matching lines...) Expand 10 before | Expand all | Expand 10 after
1895 static const _CLOSING = 2; 1895 static const _CLOSING = 2;
1896 static const _DETACHED = 3; 1896 static const _DETACHED = 3;
1897 1897
1898 int _state = _IDLE; 1898 int _state = _IDLE;
1899 1899
1900 final Socket _socket; 1900 final Socket _socket;
1901 final _HttpServer _httpServer; 1901 final _HttpServer _httpServer;
1902 final _HttpParser _httpParser; 1902 final _HttpParser _httpParser;
1903 StreamSubscription _subscription; 1903 StreamSubscription _subscription;
1904 Timer _idleTimer; 1904 Timer _idleTimer;
1905 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE); 1905 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE);
Søren Gjesse 2014/02/24 14:14:35 Why the empty lines?
Anders Johnsen 2014/02/24 14:35:10 Done.
1906 1906
1907
1908 bool _idleMark = false;
1909
1907 Future _streamFuture; 1910 Future _streamFuture;
1908 1911
1909 _HttpConnection(this._socket, this._httpServer) 1912 _HttpConnection(this._socket, this._httpServer)
1910 : _httpParser = new _HttpParser.requestParser() { 1913 : _httpParser = new _HttpParser.requestParser() {
1911 _startTimeout();
1912 _httpParser.listenToStream(_socket); 1914 _httpParser.listenToStream(_socket);
1913 _subscription = _httpParser.listen( 1915 _subscription = _httpParser.listen(
1914 (incoming) { 1916 (incoming) {
1915 _stopTimeout(); 1917 _httpServer._markActive(this);
1916 // If the incoming was closed, close the connection. 1918 // If the incoming was closed, close the connection.
1917 incoming.dataDone.then((closing) { 1919 incoming.dataDone.then((closing) {
1918 if (closing) destroy(); 1920 if (closing) destroy();
1919 }); 1921 });
1920 // Only handle one incoming request at the time. Keep the 1922 // Only handle one incoming request at the time. Keep the
1921 // stream paused until the request has been send. 1923 // stream paused until the request has been send.
1922 _subscription.pause(); 1924 _subscription.pause();
1923 _state = _ACTIVE; 1925 _state = _ACTIVE;
1924 var outgoing = new _HttpOutgoing(_socket); 1926 var outgoing = new _HttpOutgoing(_socket);
1925 var response = new _HttpResponse(incoming.uri, 1927 var response = new _HttpResponse(incoming.uri,
1926 incoming.headers.protocolVersion, 1928 incoming.headers.protocolVersion,
1927 outgoing, 1929 outgoing,
1928 _httpServer.serverHeader); 1930 _httpServer.serverHeader);
1929 var request = new _HttpRequest(response, incoming, _httpServer, this); 1931 var request = new _HttpRequest(response, incoming, _httpServer, this);
1930 _streamFuture = outgoing.done 1932 _streamFuture = outgoing.done
1931 .then((_) { 1933 .then((_) {
1932 response.deadline = null; 1934 response.deadline = null;
1933 if (_state == _DETACHED) return; 1935 if (_state == _DETACHED) return;
1934 if (response.persistentConnection && 1936 if (response.persistentConnection &&
1935 request.persistentConnection && 1937 request.persistentConnection &&
1936 incoming.fullBodyRead && 1938 incoming.fullBodyRead &&
1937 !_httpParser.upgrade && 1939 !_httpParser.upgrade &&
1938 !_httpServer.closed) { 1940 !_httpServer.closed) {
1939 _state = _IDLE; 1941 _state = _IDLE;
1940 _startTimeout(); 1942 _idleMark = false;
1943 _httpServer._markIdle(this);
1941 // Resume the subscription for incoming requests as the 1944 // Resume the subscription for incoming requests as the
1942 // request is now processed. 1945 // request is now processed.
1943 _subscription.resume(); 1946 _subscription.resume();
1944 } else { 1947 } else {
1945 // Close socket, keep-alive not used or body sent before 1948 // Close socket, keep-alive not used or body sent before
1946 // received data was handled. 1949 // received data was handled.
1947 destroy(); 1950 destroy();
1948 } 1951 }
1949 }, onError: (_) { 1952 }, onError: (_) {
1950 destroy(); 1953 destroy();
1951 }); 1954 });
1952 response._ignoreBody = request.method == "HEAD"; 1955 response._ignoreBody = request.method == "HEAD";
1953 response._httpRequest = request; 1956 response._httpRequest = request;
1954 _httpServer._handleRequest(request); 1957 _httpServer._handleRequest(request);
1955 }, 1958 },
1956 onDone: () { 1959 onDone: () {
1957 destroy(); 1960 destroy();
1958 }, 1961 },
1959 onError: (error) { 1962 onError: (error) {
1960 // Ignore failed requests that was closed before headers was received. 1963 // Ignore failed requests that was closed before headers was received.
1961 destroy(); 1964 destroy();
1962 }); 1965 });
1963 } 1966 }
1964 1967
1965 void _startTimeout() { 1968 void markIdle() {
1966 assert(_state == _IDLE); 1969 _idleMark = true;
1967 _stopTimeout();
1968 if (_httpServer.idleTimeout == null) return;
1969 _idleTimer = new Timer(_httpServer.idleTimeout, () {
1970 destroy();
1971 });
1972 } 1970 }
1973 1971
1974 void _stopTimeout() { 1972 bool get isMarkedIdle => _idleMark;
1975 if (_idleTimer != null) _idleTimer.cancel();
1976 }
1977 1973
1978 void destroy() { 1974 void destroy() {
1979 _stopTimeout();
1980 if (_state == _CLOSING || _state == _DETACHED) return; 1975 if (_state == _CLOSING || _state == _DETACHED) return;
1981 _state = _CLOSING; 1976 _state = _CLOSING;
1982 _socket.destroy(); 1977 _socket.destroy();
1983 _httpServer._connectionClosed(this); 1978 _httpServer._connectionClosed(this);
1984 } 1979 }
1985 1980
1986 Future<Socket> detachSocket() { 1981 Future<Socket> detachSocket() {
1987 _stopTimeout();
1988 _state = _DETACHED; 1982 _state = _DETACHED;
1989 // Remove connection from server. 1983 // Remove connection from server.
1990 _httpServer._connectionClosed(this); 1984 _httpServer._connectionClosed(this);
1991 1985
1992 _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming(); 1986 _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming();
1993 1987
1994 return _streamFuture.then((_) { 1988 return _streamFuture.then((_) {
1995 return new _DetachedSocket(_socket, detachedIncoming); 1989 return new _DetachedSocket(_socket, detachedIncoming);
1996 }); 1990 });
1997 } 1991 }
1998 1992
1999 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); 1993 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
2000 1994
2001 bool get _isActive => _state == _ACTIVE; 1995 bool get _isActive => _state == _ACTIVE;
2002 bool get _isIdle => _state == _IDLE; 1996 bool get _isIdle => _state == _IDLE;
2003 bool get _isClosing => _state == _CLOSING; 1997 bool get _isClosing => _state == _CLOSING;
2004 bool get _isDetached => _state == _DETACHED; 1998 bool get _isDetached => _state == _DETACHED;
2005 } 1999 }
2006 2000
2007 2001
2008 // HTTP server waiting for socket connections. 2002 // HTTP server waiting for socket connections.
2009 class _HttpServer extends Stream<HttpRequest> implements HttpServer { 2003 class _HttpServer extends Stream<HttpRequest> implements HttpServer {
2010 String serverHeader; 2004 String serverHeader;
2011 2005
2012 Duration idleTimeout = const Duration(seconds: 120); 2006 Duration _idleTimeout;
2007 Timer _idleTimer;
2013 2008
2014 static Future<HttpServer> bind(address, int port, int backlog) { 2009 static Future<HttpServer> bind(address, int port, int backlog) {
2015 return ServerSocket.bind(address, port, backlog: backlog).then((socket) { 2010 return ServerSocket.bind(address, port, backlog: backlog).then((socket) {
2016 return new _HttpServer._(socket, true); 2011 return new _HttpServer._(socket, true);
2017 }); 2012 });
2018 } 2013 }
2019 2014
2020 static Future<HttpServer> bindSecure(address, 2015 static Future<HttpServer> bindSecure(address,
2021 int port, 2016 int port,
2022 int backlog, 2017 int backlog,
2023 String certificate_name, 2018 String certificate_name,
2024 bool requestClientCertificate) { 2019 bool requestClientCertificate) {
2025 return SecureServerSocket.bind( 2020 return SecureServerSocket.bind(
2026 address, 2021 address,
2027 port, 2022 port,
2028 certificate_name, 2023 certificate_name,
2029 backlog: backlog, 2024 backlog: backlog,
2030 requestClientCertificate: requestClientCertificate) 2025 requestClientCertificate: requestClientCertificate)
2031 .then((socket) { 2026 .then((socket) {
2032 return new _HttpServer._(socket, true); 2027 return new _HttpServer._(socket, true);
2033 }); 2028 });
2034 } 2029 }
2035 2030
2036 _HttpServer._(this._serverSocket, this._closeServer) { 2031 _HttpServer._(this._serverSocket, this._closeServer) {
2037 _controller = new StreamController<HttpRequest>(sync: true, 2032 _controller = new StreamController<HttpRequest>(sync: true,
2038 onCancel: close); 2033 onCancel: close);
2034 idleTimeout = const Duration(seconds: 120);
2039 } 2035 }
2040 2036
2041 _HttpServer.listenOn(this._serverSocket) : _closeServer = false { 2037 _HttpServer.listenOn(this._serverSocket) : _closeServer = false {
2042 _controller = new StreamController<HttpRequest>(sync: true, 2038 _controller = new StreamController<HttpRequest>(sync: true,
2043 onCancel: close); 2039 onCancel: close);
2040 idleTimeout = const Duration(seconds: 120);
2041 }
2042
2043 Duration get idleTimeout => _idleTimeout;
2044
2045 void set idleTimeout(Duration duration) {
Søren Gjesse 2014/02/24 14:14:35 Update the dartdoc comment to say that it might ta
Anders Johnsen 2014/02/24 14:35:10 Done.
2046 if (_idleTimer != null) {
2047 _idleTimer.cancel();
2048 _idleTimer = null;
2049 }
2050 _idleTimeout = duration;
2051 if (_idleTimeout != null) {
2052 _idleTimer = new Timer.periodic(_idleTimeout, (_) {
2053 for (var idle in _idleConnections.toList()) {
2054 if (idle.isMarkedIdle) {
2055 idle.destroy();
2056 } else {
2057 idle.markIdle();
2058 }
2059 }
2060 });
2061 }
2044 } 2062 }
2045 2063
2046 StreamSubscription<HttpRequest> listen(void onData(HttpRequest event), 2064 StreamSubscription<HttpRequest> listen(void onData(HttpRequest event),
2047 {Function onError, 2065 {Function onError,
2048 void onDone(), 2066 void onDone(),
2049 bool cancelOnError}) { 2067 bool cancelOnError}) {
2050 _serverSocket.listen( 2068 _serverSocket.listen(
2051 (Socket socket) { 2069 (Socket socket) {
2052 socket.setOption(SocketOption.TCP_NODELAY, true); 2070 socket.setOption(SocketOption.TCP_NODELAY, true);
2053 // Accept the client connection. 2071 // Accept the client connection.
2054 _HttpConnection connection = new _HttpConnection(socket, this); 2072 _HttpConnection connection = new _HttpConnection(socket, this);
2055 _connections.add(connection); 2073 _idleConnections.add(connection);
2056 }, 2074 },
2057 onError: (error) { 2075 onError: (error) {
2058 // Ignore HandshakeExceptions as they are bound to a single request, 2076 // Ignore HandshakeExceptions as they are bound to a single request,
2059 // and are not fatal for the server. 2077 // and are not fatal for the server.
2060 if (error is! HandshakeException) { 2078 if (error is! HandshakeException) {
2061 _controller.addError(error); 2079 _controller.addError(error);
2062 } 2080 }
2063 }, 2081 },
2064 onDone: _controller.close); 2082 onDone: _controller.close);
2065 return _controller.stream.listen(onData, 2083 return _controller.stream.listen(onData,
2066 onError: onError, 2084 onError: onError,
2067 onDone: onDone, 2085 onDone: onDone,
2068 cancelOnError: cancelOnError); 2086 cancelOnError: cancelOnError);
2069 } 2087 }
2070 2088
2071 Future close({bool force: false}) { 2089 Future close({bool force: false}) {
2072 closed = true; 2090 closed = true;
2073 Future result; 2091 Future result;
2074 if (_serverSocket != null && _closeServer) { 2092 if (_serverSocket != null && _closeServer) {
2075 result = _serverSocket.close(); 2093 result = _serverSocket.close();
2076 } else { 2094 } else {
2077 result = new Future.value(); 2095 result = new Future.value();
2078 } 2096 }
2097 idleTimeout = null;
2079 if (force) { 2098 if (force) {
2080 for (var c in _connections.toList()) { 2099 for (var c in _activeConnections.toList()) {
2081 c.destroy(); 2100 c.destroy();
2082 } 2101 }
2083 assert(_connections.isEmpty); 2102 assert(_activeConnections.isEmpty);
2084 } else { 2103 }
2085 for (var c in _connections.where((c) => c._isIdle).toList()) { 2104 for (var c in _idleConnections.toList()) {
2086 c.destroy(); 2105 c.destroy();
2087 }
2088 } 2106 }
2089 _maybeCloseSessionManager(); 2107 _maybeCloseSessionManager();
2090 return result; 2108 return result;
2091 } 2109 }
2092 2110
2093 void _maybeCloseSessionManager() { 2111 void _maybeCloseSessionManager() {
2094 if (closed && 2112 if (closed &&
2095 _connections.isEmpty && 2113 _idleConnections.isEmpty &&
2114 _activeConnections.isEmpty &&
2096 _sessionManagerInstance != null) { 2115 _sessionManagerInstance != null) {
2097 _sessionManagerInstance.close(); 2116 _sessionManagerInstance.close();
2098 _sessionManagerInstance = null; 2117 _sessionManagerInstance = null;
2099 } 2118 }
2100 } 2119 }
2101 2120
2102 int get port { 2121 int get port {
2103 if (closed) throw new HttpException("HttpServer is not bound to a socket"); 2122 if (closed) throw new HttpException("HttpServer is not bound to a socket");
2104 return _serverSocket.port; 2123 return _serverSocket.port;
2105 } 2124 }
2106 2125
2107 InternetAddress get address { 2126 InternetAddress get address {
2108 if (closed) throw new HttpException("HttpServer is not bound to a socket"); 2127 if (closed) throw new HttpException("HttpServer is not bound to a socket");
2109 return _serverSocket.address; 2128 return _serverSocket.address;
2110 } 2129 }
2111 2130
2112 set sessionTimeout(int timeout) { 2131 set sessionTimeout(int timeout) {
2113 _sessionManager.sessionTimeout = timeout; 2132 _sessionManager.sessionTimeout = timeout;
2114 } 2133 }
2115 2134
2116 void _handleRequest(HttpRequest request) => _controller.add(request); 2135 void _handleRequest(HttpRequest request) => _controller.add(request);
2117 2136
2118 void _handleError(error) { 2137 void _handleError(error) {
2119 if (!closed) _controller.addError(error); 2138 if (!closed) _controller.addError(error);
2120 } 2139 }
2121 2140
2122 void _connectionClosed(_HttpConnection connection) { 2141 void _connectionClosed(_HttpConnection connection) {
2123 _connections.remove(connection); 2142 // Remove itself from either idle or active connections.
2143 connection.unlink();
2124 _maybeCloseSessionManager(); 2144 _maybeCloseSessionManager();
2125 } 2145 }
2126 2146
2147 void _markIdle(_HttpConnection connection) {
2148 _activeConnections.remove(connection);
2149 _idleConnections.add(connection);
2150 }
2151
2152 void _markActive(_HttpConnection connection) {
2153 _idleConnections.remove(connection);
2154 _activeConnections.add(connection);
2155 }
2156
2127 _HttpSessionManager get _sessionManager { 2157 _HttpSessionManager get _sessionManager {
2128 // Lazy init. 2158 // Lazy init.
2129 if (_sessionManagerInstance == null) { 2159 if (_sessionManagerInstance == null) {
2130 _sessionManagerInstance = new _HttpSessionManager(); 2160 _sessionManagerInstance = new _HttpSessionManager();
2131 } 2161 }
2132 return _sessionManagerInstance; 2162 return _sessionManagerInstance;
2133 } 2163 }
2134 2164
2135 HttpConnectionsInfo connectionsInfo() { 2165 HttpConnectionsInfo connectionsInfo() {
2136 HttpConnectionsInfo result = new HttpConnectionsInfo(); 2166 HttpConnectionsInfo result = new HttpConnectionsInfo();
2137 result.total = _connections.length; 2167 result.total = _activeConnections.length + _idleConnections.length;
2138 _connections.forEach((_HttpConnection conn) { 2168 _activeConnections.forEach((_HttpConnection conn) {
2139 if (conn._isActive) { 2169 if (conn._isActive) {
2140 result.active++; 2170 result.active++;
2141 } else if (conn._isIdle) {
2142 result.idle++;
2143 } else { 2171 } else {
2144 assert(conn._isClosing); 2172 assert(conn._isClosing);
2145 result.closing++; 2173 result.closing++;
2146 } 2174 }
2147 }); 2175 });
2176 _idleConnections.forEach((_HttpConnection conn) {
2177 result.idle++;
2178 assert(conn._isIdle);
2179 });
2148 return result; 2180 return result;
2149 } 2181 }
2150 2182
2151 _HttpSessionManager _sessionManagerInstance; 2183 _HttpSessionManager _sessionManagerInstance;
2152 2184
2153 // Indicated if the http server has been closed. 2185 // Indicated if the http server has been closed.
2154 bool closed = false; 2186 bool closed = false;
2155 2187
2156 // The server listen socket. Untyped as it can be both ServerSocket and 2188 // The server listen socket. Untyped as it can be both ServerSocket and
2157 // SecureServerSocket. 2189 // SecureServerSocket.
2158 final _serverSocket; 2190 final _serverSocket;
2159 final bool _closeServer; 2191 final bool _closeServer;
2160 2192
2161 // Set of currently connected clients. 2193 // Set of currently connected clients.
2162 final LinkedList<_HttpConnection> _connections 2194 final LinkedList<_HttpConnection> _activeConnections
2195 = new LinkedList<_HttpConnection>();
2196 final LinkedList<_HttpConnection> _idleConnections
2163 = new LinkedList<_HttpConnection>(); 2197 = new LinkedList<_HttpConnection>();
2164 StreamController<HttpRequest> _controller; 2198 StreamController<HttpRequest> _controller;
2165 // TODO(ajohnsen): Use close queue?
2166 } 2199 }
2167 2200
2168 2201
2169 class _ProxyConfiguration { 2202 class _ProxyConfiguration {
2170 static const String PROXY_PREFIX = "PROXY "; 2203 static const String PROXY_PREFIX = "PROXY ";
2171 static const String DIRECT_PREFIX = "DIRECT"; 2204 static const String DIRECT_PREFIX = "DIRECT";
2172 2205
2173 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() { 2206 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() {
2174 if (configuration == null) { 2207 if (configuration == null) {
2175 throw new HttpException("Invalid proxy configuration $configuration"); 2208 throw new HttpException("Invalid proxy configuration $configuration");
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after
2568 const _RedirectInfo(this.statusCode, this.method, this.location); 2601 const _RedirectInfo(this.statusCode, this.method, this.location);
2569 } 2602 }
2570 2603
2571 String _getHttpVersion() { 2604 String _getHttpVersion() {
2572 var version = Platform.version; 2605 var version = Platform.version;
2573 // Only include major and minor version numbers. 2606 // Only include major and minor version numbers.
2574 int index = version.indexOf('.', version.indexOf('.') + 1); 2607 int index = version.indexOf('.', version.indexOf('.') + 1);
2575 version = version.substring(0, index); 2608 version = version.substring(0, index);
2576 return 'Dart/$version (dart:io)'; 2609 return 'Dart/$version (dart:io)';
2577 } 2610 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698