Chromium Code Reviews| Index: runtime/bin/http_impl.dart |
| diff --git a/runtime/bin/http_impl.dart b/runtime/bin/http_impl.dart |
| index 1cad3472760f4079699cee8c8682d9701251302e..df3a9da2aaaf57cbb9e17db9620588ed778ab399 100644 |
| --- a/runtime/bin/http_impl.dart |
| +++ b/runtime/bin/http_impl.dart |
| @@ -688,7 +688,10 @@ class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse { |
| } |
| String get reasonPhrase() => _findReasonPhrase(_statusCode); |
| - void set reasonPhrase(String reasonPhrase) => _reasonPhrase = reasonPhrase; |
| + void set reasonPhrase(String reasonPhrase) { |
| + if (_outputStream != null) return new HttpException("Header already sent"); |
| + _reasonPhrase = reasonPhrase; |
| + } |
| // Set a header on the response. NOTE: If the same header is set |
| // more than once only the last one will be part of the response. |
| @@ -725,6 +728,7 @@ class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse { |
| } |
| void _streamClose() { |
| + _httpConnection._phase = _HttpConnectionBase.PHASE_IDLE; |
| _state = DONE; |
| // Stop tracking no pending write events. |
| _httpConnection.outputStream.onNoPendingWrites = null; |
| @@ -918,7 +922,12 @@ class _HttpOutputStream implements OutputStream { |
| class _HttpConnectionBase { |
| - _HttpConnectionBase() : _sendBuffers = new Queue(), |
| + static final int PHASE_IDLE = 0; |
| + static final int PHASE_REQUEST = 1; |
| + static final int PHASE_RESPONSE = 2; |
| + |
| + _HttpConnectionBase() : _phase = PHASE_IDLE, |
| + _sendBuffers = new Queue(), |
| _httpParser = new HttpParser(); |
| void _connectionEstablished(Socket socket) { |
| @@ -951,9 +960,14 @@ class _HttpConnectionBase { |
| } |
| void _onClosed() { |
|
Anders Johnsen
2012/03/02 13:48:10
This is a lot easier to read. Thank you!
|
| - // Client closed socket for writing. Socket should still be open |
| - // for writing the response. |
| - _closing = true; |
| + if (_phase != PHASE_IDLE) { |
| + // Client closed socket for writing. Socket should still be open |
| + // for writing the response. |
| + _closing = true; |
| + } else { |
| + // The connection is currently not used by any request just close it. |
| + _socket.close(); |
| + } |
| if (_onDisconnectCallback != null) _onDisconnectCallback(); |
| } |
| @@ -973,6 +987,7 @@ class _HttpConnectionBase { |
| _onErrorCallback = callback; |
| } |
| + int _phase; |
| Socket _socket; |
| bool _closing = false; // Is the socket closed by the client? |
| HttpParser _httpParser; |
| @@ -1002,6 +1017,7 @@ class _HttpConnection extends _HttpConnectionBase { |
| void _onRequestStart(String method, String uri) { |
| // Create new request and response objects for this request. |
| + _phase = PHASE_REQUEST; |
| _request = new _HttpRequest(this); |
| _response = new _HttpResponse(this); |
| _request._onRequestStart(method, uri); |
| @@ -1028,6 +1044,11 @@ class _HttpConnection extends _HttpConnectionBase { |
| } |
| void _onDataEnd() { |
| + // Phase might already have gone to PHASE_IDLE if the response is |
| + // sent without waiting for request body. |
| + if (_phase == PHASE_REQUEST) { |
| + _phase = PHASE_RESPONSE; |
| + } |
| _request._onDataEnd(); |
| } |
| @@ -1372,6 +1393,8 @@ class _SocketConnection { |
| Duration _idleTime(Date now) => now.difference(_returnTime); |
| + int hashCode() => _socket.hashCode(); |
| + |
| String _host; |
| int _port; |
| Socket _socket; |
| @@ -1382,7 +1405,9 @@ class _SocketConnection { |
| class _HttpClient implements HttpClient { |
| static final int DEFAULT_EVICTION_TIMEOUT = 60000; |
| - _HttpClient() : _openSockets = new Map(), _shutdown = false; |
| + _HttpClient() : _openSockets = new Map(), |
| + _activeSockets = new Set(), |
| + _shutdown = false; |
| HttpClientConnection open( |
| String method, String host, int port, String path) { |
| @@ -1399,13 +1424,15 @@ class _HttpClient implements HttpClient { |
| } |
| void shutdown() { |
| - _openSockets.forEach( |
| - void _(String key, Queue<_SocketConnection> connections) { |
| - while (!connections.isEmpty()) { |
| - var socketConn = connections.removeFirst(); |
| - socketConn._socket.close(); |
| - } |
| - }); |
| + _openSockets.forEach((String key, Queue<_SocketConnection> connections) { |
| + while (!connections.isEmpty()) { |
| + _SocketConnection socketConn = connections.removeFirst(); |
| + socketConn._socket.close(); |
| + } |
| + }); |
| + _activeSockets.forEach((_SocketConnection socketConn) { |
| + socketConn._socket.close(); |
| + }); |
| if (_evictionTimer != null) { |
| _evictionTimer.cancel(); |
| } |
| @@ -1441,6 +1468,7 @@ class _HttpClient implements HttpClient { |
| socket.onError = null; |
| _SocketConnection socketConn = |
| new _SocketConnection(host, port, socket); |
| + _activeSockets.add(socketConn); |
| _connectionOpened(socketConn, connection); |
| }; |
| socket.onError = () { |
| @@ -1450,6 +1478,7 @@ class _HttpClient implements HttpClient { |
| }; |
| } else { |
| _SocketConnection socketConn = socketConnections.removeFirst(); |
| + _activeSockets.add(socketConn); |
| new Timer((ignored) => _connectionOpened(socketConn, connection), 0); |
| // Get rid of eviction timer if there are no more active connections. |
| @@ -1501,6 +1530,7 @@ class _HttpClient implements HttpClient { |
| } |
| // Return connection. |
| + _activeSockets.remove(socketConn); |
| sockets.addFirst(socketConn); |
| socketConn._markReturned(); |
| } |
| @@ -1512,6 +1542,7 @@ class _HttpClient implements HttpClient { |
| Function _onOpen; |
| Function _onError; |
| Map<String, Queue<_SocketConnection>> _openSockets; |
| + Set<_SocketConnection> _activeSockets; |
| Timer _evictionTimer; |
| bool _shutdown; // Has this HTTP client been shutdown? |
| } |