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

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

Issue 11348127: Make HTTP server close sockets when closed in idle state (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 // The close queue handles graceful closing of HTTP connections. When 5 // The close queue handles graceful closing of HTTP connections. When
6 // a connection is added to the queue it will enter a wait state 6 // a connection is added to the queue it will enter a wait state
7 // waiting for all data written and possibly socket shutdown from 7 // waiting for all data written and possibly socket shutdown from
8 // peer. 8 // peer.
9 class _CloseQueue { 9 class _CloseQueue {
10 _CloseQueue() : _q = new Set<_HttpConnectionBase>(); 10 _CloseQueue() : _q = new Set<_HttpConnectionBase>();
11 11
12 void add(_HttpConnectionBase connection) { 12 void add(_HttpConnectionBase connection) {
13 void closeIfDone() { 13 void closeIfDone() {
14 // We only check for write closed here. This means that we are 14 // We only check for write closed here. This means that we are
15 // not waiting for the client to half-close the socket before 15 // not waiting for the client to half-close the socket before
16 // fully closing the socket. 16 // fully closing the socket.
17 if (!connection._isWriteClosed) return; 17 if (!connection._isWriteClosed) return;
18 _q.remove(connection); 18 _q.remove(connection);
19 connection._socket.close(); 19 connection._socket.close();
20 if (connection.onClosed != null) connection.onClosed(); 20 if (connection.onClosed != null) connection.onClosed();
21 } 21 }
22 22
23 // If the connection is already fully closed don't insert it into the queue. 23 // If the connection is already fully closed don't insert it into the queue.
24 if (connection._isFullyClosed) { 24 if (connection._isFullyClosed) {
25 connection._socket.close(); 25 connection._socket.close();
26 if (connection.onClosed != null) connection.onClosed(); 26 if (connection.onClosed != null) connection.onClosed();
27 return; 27 return;
28 } 28 }
29 29
30 connection._state |= _HttpConnectionBase.CLOSING;
30 _q.add(connection); 31 _q.add(connection);
31 32
32 // If output stream is not closed for writing close it now and 33 // If output stream is not closed for writing close it now and
33 // wait for callback when closed. 34 // wait for callback when closed.
34 if (!connection._isWriteClosed) { 35 if (!connection._isWriteClosed) {
35 connection._socket.outputStream.close(); 36 connection._socket.outputStream.close();
36 connection._socket.outputStream.onClosed = () { 37 connection._socket.outputStream.onClosed = () {
37 connection._state |= _HttpConnectionBase.WRITE_CLOSED; 38 connection._state |= _HttpConnectionBase.WRITE_CLOSED;
38 closeIfDone(); 39 closeIfDone();
39 }; 40 };
40 } else { 41 } else {
41 connection._socket.outputStream.onClosed = () { assert(false); }; 42 connection._socket.outputStream.onClosed = () { assert(false); };
42 } 43 }
43 44
44 // If socket is not closed for reading wait for callback. 45 // If socket is not closed for reading wait for callback.
45 if (!connection._isReadClosed) { 46 if (!connection._isReadClosed) {
46 connection._socket.onClosed = () { 47 connection._socket.onClosed = () {
47 connection._state |= _HttpConnectionBase.READ_CLOSED; 48 connection._state |= _HttpConnectionBase.READ_CLOSED;
48 // This is a nop, as we are not using the read closed 49 // This is a nop, as we are not using the read closed
49 // information for anything. For both server and client 50 // information for anything. For both server and client
50 // connections the inbound message have been read to 51 // connections the inbound message have been read to
51 // completion when the socket enters the close queue. 52 // completion when the socket enters the close queue.
53 closeIfDone();
52 }; 54 };
53 } else { 55 } else {
54 connection._socket.onClosed = () { assert(false); }; 56 connection._socket.onClosed = () { assert(false); };
55 } 57 }
56 58
57 // Ignore any data on a socket in the close queue. 59 // Ignore any data on a socket in the close queue.
58 connection._socket.onData = connection._socket.read; 60 connection._socket.onData = connection._socket.read;
59 61
60 // If an error occurs immediately close the socket. 62 // If an error occurs immediately close the socket.
61 connection._socket.onError = (e) { 63 connection._socket.onError = (e) {
(...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 _requestOrResponse._streamSetErrorHandler(callback); 713 _requestOrResponse._streamSetErrorHandler(callback);
712 } 714 }
713 715
714 _HttpRequestResponseBase _requestOrResponse; 716 _HttpRequestResponseBase _requestOrResponse;
715 } 717 }
716 718
717 719
718 abstract class _HttpConnectionBase { 720 abstract class _HttpConnectionBase {
719 static const int IDLE = 0; 721 static const int IDLE = 0;
720 static const int ACTIVE = 1; 722 static const int ACTIVE = 1;
721 static const int REQUEST_DONE = 2; 723 static const int CLOSING = 2;
722 static const int RESPONSE_DONE = 4; 724 static const int REQUEST_DONE = 4;
725 static const int RESPONSE_DONE = 8;
723 static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE; 726 static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE;
724 static const int READ_CLOSED = 8; 727 static const int READ_CLOSED = 16;
725 static const int WRITE_CLOSED = 16; 728 static const int WRITE_CLOSED = 32;
726 static const int FULLY_CLOSED = READ_CLOSED | WRITE_CLOSED; 729 static const int FULLY_CLOSED = READ_CLOSED | WRITE_CLOSED;
727 730
728 _HttpConnectionBase() : hashCode = _nextHashCode { 731 _HttpConnectionBase() : hashCode = _nextHashCode {
729 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; 732 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF;
730 } 733 }
731 734
735 bool get _isIdle => (_state & ACTIVE) == 0;
736 bool get _isActive => (_state & ACTIVE) == ACTIVE;
737 bool get _isClosing => (_state & CLOSING) == CLOSING;
732 bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE; 738 bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE;
733 bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE; 739 bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE;
734 bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE; 740 bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE;
735 bool get _isReadClosed => (_state & READ_CLOSED) == READ_CLOSED; 741 bool get _isReadClosed => (_state & READ_CLOSED) == READ_CLOSED;
736 bool get _isWriteClosed => (_state & WRITE_CLOSED) == WRITE_CLOSED; 742 bool get _isWriteClosed => (_state & WRITE_CLOSED) == WRITE_CLOSED;
737 bool get _isFullyClosed => (_state & FULLY_CLOSED) == FULLY_CLOSED; 743 bool get _isFullyClosed => (_state & FULLY_CLOSED) == FULLY_CLOSED;
738 744
739 void _connectionEstablished(Socket socket) { 745 void _connectionEstablished(Socket socket) {
740 _socket = socket; 746 _socket = socket;
741 // Register handlers for socket events. All socket events are 747 // Register handlers for socket events. All socket events are
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 _httpParser.dataEnd = _onDataEnd; 831 _httpParser.dataEnd = _onDataEnd;
826 _httpParser.error = _onError; 832 _httpParser.error = _onError;
827 _httpParser.closed = _onClosed; 833 _httpParser.closed = _onClosed;
828 _httpParser.responseStart = (statusCode, reasonPhrase, version) { 834 _httpParser.responseStart = (statusCode, reasonPhrase, version) {
829 assert(false); 835 assert(false);
830 }; 836 };
831 } 837 }
832 838
833 void _onClosed() { 839 void _onClosed() {
834 _state |= _HttpConnectionBase.READ_CLOSED; 840 _state |= _HttpConnectionBase.READ_CLOSED;
841 _checkDone();
835 } 842 }
836 843
837 void _onError(e) { 844 void _onError(e) {
838 onError(e); 845 onError(e);
839 // Propagate the error to the streams. 846 // Propagate the error to the streams.
840 if (_request != null && _request._streamErrorHandler != null) { 847 if (_request != null && _request._streamErrorHandler != null) {
841 _request._streamErrorHandler(e); 848 _request._streamErrorHandler(e);
842 } 849 }
843 if (_response != null && _response._streamErrorHandler != null) { 850 if (_response != null && _response._streamErrorHandler != null) {
844 _response._streamErrorHandler(e); 851 _response._streamErrorHandler(e);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
877 bool close = 884 bool close =
878 !_response.persistentConnection || 885 !_response.persistentConnection ||
879 (_response._protocolVersion == "1.0" && _response._contentLength < 0); 886 (_response._protocolVersion == "1.0" && _response._contentLength < 0);
880 _request = null; 887 _request = null;
881 _response = null; 888 _response = null;
882 if (_isReadClosed || close) { 889 if (_isReadClosed || close) {
883 _server._closeQueue.add(this); 890 _server._closeQueue.add(this);
884 } else { 891 } else {
885 _state = _HttpConnectionBase.IDLE; 892 _state = _HttpConnectionBase.IDLE;
886 } 893 }
894 } else if (_state == _HttpConnectionBase.READ_CLOSED) {
895 // If entering READ_CLOSED state while idle close the connection.
896 _server._closeQueue.add(this);
887 } 897 }
888 } 898 }
889 899
890 void _onDataEnd(bool close) { 900 void _onDataEnd(bool close) {
891 _request._onDataEnd(); 901 _request._onDataEnd();
892 _state |= _HttpConnectionBase.REQUEST_DONE; 902 _state |= _HttpConnectionBase.REQUEST_DONE;
893 _checkDone(); 903 _checkDone();
894 } 904 }
895 905
896 void _responseClosed() { 906 void _responseClosed() {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 } 1027 }
1018 1028
1019 _HttpSessionManager get _sessionManager { 1029 _HttpSessionManager get _sessionManager {
1020 // Lazy init. 1030 // Lazy init.
1021 if (_sessionManagerInstance == null) { 1031 if (_sessionManagerInstance == null) {
1022 _sessionManagerInstance = new _HttpSessionManager(); 1032 _sessionManagerInstance = new _HttpSessionManager();
1023 } 1033 }
1024 return _sessionManagerInstance; 1034 return _sessionManagerInstance;
1025 } 1035 }
1026 1036
1037 HttpConnectionsInfo connectionsInfo() {
1038 HttpConnectionsInfo result = new HttpConnectionsInfo();
1039 result.total = _connections.length;
1040 _connections.forEach((_HttpConnection conn) {
1041 if (conn._isActive) {
1042 result.active++;
1043 } else if (conn._isIdle) {
1044 result.idle++;
1045 } else {
1046 assert(result._isClosing);
1047 result.closing++;
1048 }
1049 });
1050 return result;
1051 }
1027 1052
1028 ServerSocket _server; // The server listen socket. 1053 ServerSocket _server; // The server listen socket.
1029 bool _closeServer = false; 1054 bool _closeServer = false;
1030 Set<_HttpConnection> _connections; // Set of currently connected clients. 1055 Set<_HttpConnection> _connections; // Set of currently connected clients.
1031 List<_RequestHandlerRegistration> _handlers; 1056 List<_RequestHandlerRegistration> _handlers;
1032 Object _defaultHandler; 1057 Object _defaultHandler;
1033 Function _onError; 1058 Function _onError;
1034 _CloseQueue _closeQueue; 1059 _CloseQueue _closeQueue;
1035 _HttpSessionManager _sessionManagerInstance; 1060 _HttpSessionManager _sessionManagerInstance;
1036 } 1061 }
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 _response = new _HttpClientResponse(this); 1453 _response = new _HttpClientResponse(this);
1429 return _request; 1454 return _request;
1430 } 1455 }
1431 1456
1432 DetachedSocket detachSocket() { 1457 DetachedSocket detachSocket() {
1433 return _detachSocket(); 1458 return _detachSocket();
1434 } 1459 }
1435 1460
1436 void _onClosed() { 1461 void _onClosed() {
1437 _state |= _HttpConnectionBase.READ_CLOSED; 1462 _state |= _HttpConnectionBase.READ_CLOSED;
1463 _checkSocketDone();
1438 } 1464 }
1439 1465
1440 void _onError(e) { 1466 void _onError(e) {
1441 // Socket is closed either due to an error or due to normal socket close. 1467 // Socket is closed either due to an error or due to normal socket close.
1442 if (_onErrorCallback != null) { 1468 if (_onErrorCallback != null) {
1443 _onErrorCallback(e); 1469 _onErrorCallback(e);
1444 } else { 1470 } else {
1445 throw e; 1471 throw e;
1446 } 1472 }
1447 // Propagate the error to the streams. 1473 // Propagate the error to the streams.
(...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after
2073 2099
2074 2100
2075 class _RedirectInfo implements RedirectInfo { 2101 class _RedirectInfo implements RedirectInfo {
2076 const _RedirectInfo(int this.statusCode, 2102 const _RedirectInfo(int this.statusCode,
2077 String this.method, 2103 String this.method,
2078 Uri this.location); 2104 Uri this.location);
2079 final int statusCode; 2105 final int statusCode;
2080 final String method; 2106 final String method;
2081 final Uri location; 2107 final Uri location;
2082 } 2108 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698