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 // When either the client has closed or all data has been |
15 // not waiting for the client to half-close the socket before | 15 // written to the client we close the underlying socket |
16 // fully closing the socket. | 16 // completely. |
17 if (!connection._isWriteClosed) return; | 17 if (!connection._isWriteClosed && !connection._isReadClosed) return; |
Mads Ager (google)
2012/11/20 08:04:28
Maybe remove the negations and make this:
if (con
Søren Gjesse
2012/11/20 08:15:11
Much better, done.
| |
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 |
24 // the queue. | |
24 if (connection._isFullyClosed) { | 25 if (connection._isFullyClosed) { |
25 connection._socket.close(); | 26 connection._socket.close(); |
26 if (connection.onClosed != null) connection.onClosed(); | 27 if (connection.onClosed != null) connection.onClosed(); |
27 return; | 28 return; |
28 } | 29 } |
29 | 30 |
30 connection._state |= _HttpConnectionBase.CLOSING; | 31 connection._state |= _HttpConnectionBase.CLOSING; |
31 _q.add(connection); | 32 _q.add(connection); |
32 | 33 |
33 // If output stream is not closed for writing close it now and | 34 // If output stream is not closed for writing close it now and |
34 // wait for callback when closed. | 35 // wait for callback when closed. |
35 if (!connection._isWriteClosed) { | 36 if (!connection._isWriteClosed) { |
36 connection._socket.outputStream.close(); | 37 connection._socket.outputStream.close(); |
37 connection._socket.outputStream.onClosed = () { | 38 connection._socket.outputStream.onClosed = () { |
38 connection._state |= _HttpConnectionBase.WRITE_CLOSED; | 39 connection._state |= _HttpConnectionBase.WRITE_CLOSED; |
39 closeIfDone(); | 40 closeIfDone(); |
40 }; | 41 }; |
41 } else { | 42 } else { |
42 connection._socket.outputStream.onClosed = () { assert(false); }; | 43 connection._socket.outputStream.onClosed = () { assert(false); }; |
43 } | 44 } |
44 | 45 |
45 // If socket is not closed for reading wait for callback. | 46 // If socket is not closed for reading wait for callback. |
46 if (!connection._isReadClosed) { | 47 if (!connection._isReadClosed) { |
47 connection._socket.onClosed = () { | 48 connection._socket.onClosed = () { |
48 connection._state |= _HttpConnectionBase.READ_CLOSED; | 49 connection._state |= _HttpConnectionBase.READ_CLOSED; |
49 // This is a nop, as we are not using the read closed | |
50 // information for anything. For both server and client | |
51 // connections the inbound message have been read to | |
52 // completion when the socket enters the close queue. | |
53 closeIfDone(); | 50 closeIfDone(); |
54 }; | 51 }; |
55 } else { | 52 } else { |
56 connection._socket.onClosed = () { assert(false); }; | 53 connection._socket.onClosed = () { assert(false); }; |
57 } | 54 } |
58 | 55 |
59 // Ignore any data on a socket in the close queue. | 56 // Ignore any data on a socket in the close queue. |
60 connection._socket.onData = connection._socket.read; | 57 connection._socket.onData = connection._socket.read; |
61 | 58 |
62 // If an error occurs immediately close the socket. | 59 // If an error occurs immediately close the socket. |
63 connection._socket.onError = (e) { | 60 connection._socket.onError = (e) { |
61 connection._state |= _HttpConnectionBase.READ_CLOSED; | |
64 connection._state |= _HttpConnectionBase.WRITE_CLOSED; | 62 connection._state |= _HttpConnectionBase.WRITE_CLOSED; |
65 closeIfDone(); | 63 closeIfDone(); |
66 }; | 64 }; |
67 } | 65 } |
68 | 66 |
69 void shutdown() { | 67 void shutdown() { |
70 _q.forEach((_HttpConnectionBase connection) { | 68 _q.forEach((_HttpConnectionBase connection) { |
71 connection._socket.close(); | 69 connection._socket.close(); |
72 }); | 70 }); |
73 } | 71 } |
(...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
869 if (onRequestReceived != null) { | 867 if (onRequestReceived != null) { |
870 onRequestReceived(_request, _response); | 868 onRequestReceived(_request, _response); |
871 } | 869 } |
872 } | 870 } |
873 | 871 |
874 void _onDataReceived(List<int> data) { | 872 void _onDataReceived(List<int> data) { |
875 _request._onDataReceived(data); | 873 _request._onDataReceived(data); |
876 } | 874 } |
877 | 875 |
878 void _checkDone() { | 876 void _checkDone() { |
879 if (_isAllDone) { | 877 if (_isReadClosed) { |
880 // If we are done writing the response, and either the client | 878 // If the client closes the conversation is ended. |
881 // has closed or the connection is not persistent, we must | 879 _server._closeQueue.add(this); |
882 // close. Also if using HTTP 1.0 and the content length was not | 880 } else if (_isAllDone) { |
883 // known we must close to indicate end of body. | 881 // If we are done writing the response, and the connection is |
882 // not persistent, we must close. Also if using HTTP 1.0 and the | |
883 // content length was not known we must close to indicate end of | |
884 // body. | |
884 bool close = | 885 bool close = |
885 !_response.persistentConnection || | 886 !_response.persistentConnection || |
886 (_response._protocolVersion == "1.0" && _response._contentLength < 0); | 887 (_response._protocolVersion == "1.0" && _response._contentLength < 0); |
887 _request = null; | 888 _request = null; |
888 _response = null; | 889 _response = null; |
889 if (_isReadClosed || close) { | 890 if (close) { |
890 _server._closeQueue.add(this); | 891 _server._closeQueue.add(this); |
891 } else { | 892 } else { |
892 _state = _HttpConnectionBase.IDLE; | 893 _state = _HttpConnectionBase.IDLE; |
893 } | 894 } |
894 } else if (_state == _HttpConnectionBase.READ_CLOSED) { | |
895 // If entering READ_CLOSED state while idle close the connection. | |
896 _server._closeQueue.add(this); | |
897 } | 895 } |
898 } | 896 } |
899 | 897 |
900 void _onDataEnd(bool close) { | 898 void _onDataEnd(bool close) { |
901 _request._onDataEnd(); | 899 _request._onDataEnd(); |
902 _state |= _HttpConnectionBase.REQUEST_DONE; | 900 _state |= _HttpConnectionBase.REQUEST_DONE; |
903 _checkDone(); | 901 _checkDone(); |
904 } | 902 } |
905 | 903 |
906 void _responseClosed() { | 904 void _responseClosed() { |
(...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2099 | 2097 |
2100 | 2098 |
2101 class _RedirectInfo implements RedirectInfo { | 2099 class _RedirectInfo implements RedirectInfo { |
2102 const _RedirectInfo(int this.statusCode, | 2100 const _RedirectInfo(int this.statusCode, |
2103 String this.method, | 2101 String this.method, |
2104 Uri this.location); | 2102 Uri this.location); |
2105 final int statusCode; | 2103 final int statusCode; |
2106 final String method; | 2104 final String method; |
2107 final Uri location; | 2105 final Uri location; |
2108 } | 2106 } |
OLD | NEW |