OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |