| 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 |