Chromium Code Reviews| 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>(); |
| (...skipping 740 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 751 _httpParser.streamData(buffer); | 751 _httpParser.streamData(buffer); |
| 752 } | 752 } |
| 753 }; | 753 }; |
| 754 _socket.onClosed = _httpParser.streamDone; | 754 _socket.onClosed = _httpParser.streamDone; |
| 755 _socket.onError = _httpParser.streamError; | 755 _socket.onError = _httpParser.streamError; |
| 756 // Ignore errors in the socket output stream as this is getting | 756 // Ignore errors in the socket output stream as this is getting |
| 757 // the same errors as the socket itself. | 757 // the same errors as the socket itself. |
| 758 _socket.outputStream.onError = (e) => null; | 758 _socket.outputStream.onError = (e) => null; |
| 759 } | 759 } |
| 760 | 760 |
| 761 bool _write(List<int> data, [bool copyBuffer = false]) { | 761 bool _write(List<int> data, [bool copyBuffer = false]); |
| 762 return _socket.outputStream.write(data, copyBuffer); | 762 bool _writeFrom(List<int> buffer, [int offset, int len]); |
| 763 } | 763 bool _flush(); |
| 764 | 764 bool _close(); |
| 765 bool _writeFrom(List<int> buffer, [int offset, int len]) { | 765 bool _destroy(); |
| 766 return _socket.outputStream.writeFrom(buffer, offset, len); | 766 DetachedSocket _detachSocket(); |
| 767 } | |
| 768 | |
| 769 bool _flush() { | |
| 770 _socket.outputStream.flush(); | |
| 771 } | |
| 772 | |
| 773 bool _close() { | |
| 774 _socket.outputStream.close(); | |
| 775 } | |
| 776 | |
| 777 bool _destroy() { | |
| 778 _socket.close(); | |
| 779 } | |
| 780 | |
| 781 DetachedSocket _detachSocket() { | |
| 782 _socket.onData = null; | |
| 783 _socket.onClosed = null; | |
| 784 _socket.onError = null; | |
| 785 _socket.outputStream.onNoPendingWrites = null; | |
| 786 Socket socket = _socket; | |
| 787 _socket = null; | |
| 788 if (onDetach != null) onDetach(); | |
| 789 return new _DetachedSocket(socket, _httpParser.readUnparsedData()); | |
| 790 } | |
| 791 | 767 |
| 792 HttpConnectionInfo get connectionInfo { | 768 HttpConnectionInfo get connectionInfo { |
| 793 if (_socket == null) return null; | 769 if (_socket == null) return null; |
| 794 try { | 770 try { |
| 795 _HttpConnectionInfo info = new _HttpConnectionInfo(); | 771 _HttpConnectionInfo info = new _HttpConnectionInfo(); |
| 796 info.remoteHost = _socket.remoteHost; | 772 info.remoteHost = _socket.remoteHost; |
| 797 info.remotePort = _socket.remotePort; | 773 info.remotePort = _socket.remotePort; |
| 798 info.localPort = _socket.port; | 774 info.localPort = _socket.port; |
| 799 return info; | 775 return info; |
| 800 } catch (e) { } | 776 } catch (e) { } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 828 _httpParser.requestStart = _onRequestReceived; | 804 _httpParser.requestStart = _onRequestReceived; |
| 829 _httpParser.dataReceived = _onDataReceived; | 805 _httpParser.dataReceived = _onDataReceived; |
| 830 _httpParser.dataEnd = _onDataEnd; | 806 _httpParser.dataEnd = _onDataEnd; |
| 831 _httpParser.error = _onError; | 807 _httpParser.error = _onError; |
| 832 _httpParser.closed = _onClosed; | 808 _httpParser.closed = _onClosed; |
| 833 _httpParser.responseStart = (statusCode, reasonPhrase, version) { | 809 _httpParser.responseStart = (statusCode, reasonPhrase, version) { |
| 834 assert(false); | 810 assert(false); |
| 835 }; | 811 }; |
| 836 } | 812 } |
| 837 | 813 |
| 814 void _bufferData(List<int> data, [bool copyBuffer = false]) { | |
| 815 if (_buffer == null) _buffer = new _BufferList(); | |
| 816 if (copyBuffer) data = data.getRange(0, data.length); | |
| 817 _buffer.add(data); | |
| 818 } | |
| 819 | |
| 820 void _releaseBuffer() { | |
|
Mads Ager (google)
2012/12/05 16:02:18
Maybe name this something like _writeBufferedRespo
Søren Gjesse
2012/12/06 17:23:08
Done.
| |
| 821 if (_buffer != null) { | |
| 822 while (!_buffer.isEmpty) { | |
| 823 var data = _buffer.first; | |
| 824 _socket.outputStream.write(data, false); | |
| 825 _buffer.removeBytes(data.length); | |
| 826 } | |
| 827 _buffer = null; | |
| 828 } | |
| 829 } | |
| 830 | |
| 831 bool _write(List<int> data, [bool copyBuffer = false]) { | |
| 832 if (_isRequestDone) { | |
| 833 return _socket.outputStream.write(data, copyBuffer); | |
| 834 } else { | |
| 835 _bufferData(data, copyBuffer); | |
| 836 return false; | |
| 837 } | |
| 838 } | |
| 839 | |
| 840 bool _writeFrom(List<int> data, [int offset, int len]) { | |
| 841 if (_isRequestDone) { | |
| 842 return _socket.outputStream.writeFrom(data, offset, len); | |
| 843 } else { | |
| 844 if (offset == null) offset = 0; | |
| 845 if (len == null) len = buffer.length - offset; | |
| 846 _bufferData(data.getRange(offset, len), false); | |
| 847 return false; | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 bool _flush() { | |
| 852 _socket.outputStream.flush(); | |
| 853 } | |
| 854 | |
| 855 bool _close() { | |
| 856 _socket.outputStream.close(); | |
| 857 } | |
| 858 | |
| 859 bool _destroy() { | |
| 860 _socket.close(); | |
| 861 } | |
| 862 | |
| 838 void _onClosed() { | 863 void _onClosed() { |
| 839 _state |= _HttpConnectionBase.READ_CLOSED; | 864 _state |= _HttpConnectionBase.READ_CLOSED; |
| 840 _checkDone(); | 865 _checkDone(); |
| 841 } | 866 } |
| 842 | 867 |
| 868 DetachedSocket _detachSocket() { | |
| 869 _socket.onData = null; | |
| 870 _socket.onClosed = null; | |
| 871 _socket.onError = null; | |
| 872 _socket.outputStream.onNoPendingWrites = null; | |
| 873 _releaseBuffer(); | |
| 874 Socket socket = _socket; | |
| 875 _socket = null; | |
| 876 if (onDetach != null) onDetach(); | |
| 877 return new _DetachedSocket(socket, _httpParser.readUnparsedData()); | |
| 878 } | |
| 879 | |
| 843 void _onError(e) { | 880 void _onError(e) { |
| 844 onError(e); | 881 onError(e); |
| 845 // Propagate the error to the streams. | 882 // Propagate the error to the streams. |
| 846 if (_request != null && _request._streamErrorHandler != null) { | 883 if (_request != null && _request._streamErrorHandler != null) { |
| 847 _request._streamErrorHandler(e); | 884 _request._streamErrorHandler(e); |
| 848 } | 885 } |
| 849 if (_response != null && _response._streamErrorHandler != null) { | 886 if (_response != null && _response._streamErrorHandler != null) { |
| 850 _response._streamErrorHandler(e); | 887 _response._streamErrorHandler(e); |
| 851 } | 888 } |
| 852 if (_socket != null) _socket.close(); | 889 if (_socket != null) _socket.close(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 886 bool close = | 923 bool close = |
| 887 !_response.persistentConnection || | 924 !_response.persistentConnection || |
| 888 (_response._protocolVersion == "1.0" && _response._contentLength < 0); | 925 (_response._protocolVersion == "1.0" && _response._contentLength < 0); |
| 889 _request = null; | 926 _request = null; |
| 890 _response = null; | 927 _response = null; |
| 891 if (close) { | 928 if (close) { |
| 892 _server._closeQueue.add(this); | 929 _server._closeQueue.add(this); |
| 893 } else { | 930 } else { |
| 894 _state = _HttpConnectionBase.IDLE; | 931 _state = _HttpConnectionBase.IDLE; |
| 895 } | 932 } |
| 933 } else if (_isResponseDone) { | |
| 934 // If the response is closed before the request is fully read | |
| 935 // close this connection. If there is buffered output | |
| 936 // (e.g. error response for invalid request where the server did | |
| 937 // not care to read the request body) this is send. | |
| 938 assert(!_isRequestDone); | |
| 939 _releaseBuffer(); | |
| 940 _close(); | |
| 941 _server._closeQueue.add(this); | |
| 896 } | 942 } |
| 897 } | 943 } |
| 898 | 944 |
| 899 void _onDataEnd(bool close) { | 945 void _onDataEnd(bool close) { |
| 946 // Start sending queued response if any. | |
| 947 _releaseBuffer(); | |
| 948 _state |= _HttpConnectionBase.REQUEST_DONE; | |
| 900 _request._onDataEnd(); | 949 _request._onDataEnd(); |
| 901 _state |= _HttpConnectionBase.REQUEST_DONE; | |
| 902 _checkDone(); | |
| 903 } | 950 } |
| 904 | 951 |
| 905 void _responseClosed() { | 952 void _responseClosed() { |
| 906 _state |= _HttpConnectionBase.RESPONSE_DONE; | 953 _state |= _HttpConnectionBase.RESPONSE_DONE; |
| 907 _checkDone(); | 954 _checkDone(); |
| 908 } | 955 } |
| 909 | 956 |
| 910 HttpServer _server; | 957 HttpServer _server; |
| 911 HttpRequest _request; | 958 HttpRequest _request; |
| 912 HttpResponse _response; | 959 HttpResponse _response; |
| 913 | 960 |
| 961 // Buffer for data written before full response have been processed. | |
|
Mads Ager (google)
2012/12/05 16:02:18
have -> has
Søren Gjesse
2012/12/06 17:23:08
Done.
| |
| 962 _BufferList _buffer; | |
| 963 | |
| 914 // Callbacks. | 964 // Callbacks. |
| 915 Function onRequestReceived; | 965 Function onRequestReceived; |
| 916 Function onError; | 966 Function onError; |
| 917 } | 967 } |
| 918 | 968 |
| 919 | 969 |
| 920 class _RequestHandlerRegistration { | 970 class _RequestHandlerRegistration { |
| 921 _RequestHandlerRegistration(Function this._matcher, Function this._handler); | 971 _RequestHandlerRegistration(Function this._matcher, Function this._handler); |
| 922 Function _matcher; | 972 Function _matcher; |
| 923 Function _handler; | 973 Function _handler; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1114 if (_done) throw new HttpException("Request closed"); | 1164 if (_done) throw new HttpException("Request closed"); |
| 1115 if (_outputStream == null) { | 1165 if (_outputStream == null) { |
| 1116 _outputStream = new _HttpOutputStream(this); | 1166 _outputStream = new _HttpOutputStream(this); |
| 1117 } | 1167 } |
| 1118 return _outputStream; | 1168 return _outputStream; |
| 1119 } | 1169 } |
| 1120 | 1170 |
| 1121 // Delegate functions for the HttpOutputStream implementation. | 1171 // Delegate functions for the HttpOutputStream implementation. |
| 1122 bool _streamWrite(List<int> buffer, bool copyBuffer) { | 1172 bool _streamWrite(List<int> buffer, bool copyBuffer) { |
| 1123 if (_done) throw new HttpException("Request closed"); | 1173 if (_done) throw new HttpException("Request closed"); |
| 1174 _emptyBody = false; | |
|
Mads Ager (google)
2012/12/05 16:02:18
Should this be
_emptyBody = buffer.length != 0 |
Søren Gjesse
2012/12/06 17:23:08
Good point, however it should be
_emptyBody = buf
| |
| 1124 return _write(buffer, copyBuffer); | 1175 return _write(buffer, copyBuffer); |
| 1125 } | 1176 } |
| 1126 | 1177 |
| 1127 bool _streamWriteFrom(List<int> buffer, int offset, int len) { | 1178 bool _streamWriteFrom(List<int> buffer, int offset, int len) { |
| 1128 if (_done) throw new HttpException("Request closed"); | 1179 if (_done) throw new HttpException("Request closed"); |
| 1180 _emptyBody = false; | |
|
Mads Ager (google)
2012/12/05 16:02:18
Ditto
Søren Gjesse
2012/12/06 17:23:08
Done.
| |
| 1129 return _writeList(buffer, offset, len); | 1181 return _writeList(buffer, offset, len); |
| 1130 } | 1182 } |
| 1131 | 1183 |
| 1132 void _streamFlush() { | 1184 void _streamFlush() { |
| 1133 _httpConnection._flush(); | 1185 _httpConnection._flush(); |
| 1134 } | 1186 } |
| 1135 | 1187 |
| 1136 void _streamClose() { | 1188 void _streamClose() { |
| 1137 _ensureHeadersSent(); | 1189 _ensureHeadersSent(); |
| 1138 _state = _HttpRequestResponseBase.DONE; | 1190 _state = _HttpRequestResponseBase.DONE; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1209 // Write headers. | 1261 // Write headers. |
| 1210 _writeHeaders(); | 1262 _writeHeaders(); |
| 1211 _state = _HttpRequestResponseBase.HEADER_SENT; | 1263 _state = _HttpRequestResponseBase.HEADER_SENT; |
| 1212 } | 1264 } |
| 1213 | 1265 |
| 1214 String _method; | 1266 String _method; |
| 1215 Uri _uri; | 1267 Uri _uri; |
| 1216 _HttpClientConnection _connection; | 1268 _HttpClientConnection _connection; |
| 1217 _HttpOutputStream _outputStream; | 1269 _HttpOutputStream _outputStream; |
| 1218 Function _streamErrorHandler; | 1270 Function _streamErrorHandler; |
| 1271 bool _emptyBody = true; | |
| 1219 } | 1272 } |
| 1220 | 1273 |
| 1221 | 1274 |
| 1222 class _HttpClientResponse | 1275 class _HttpClientResponse |
| 1223 extends _HttpRequestResponseBase implements HttpClientResponse { | 1276 extends _HttpRequestResponseBase implements HttpClientResponse { |
| 1224 _HttpClientResponse(_HttpClientConnection connection) | 1277 _HttpClientResponse(_HttpClientConnection connection) |
| 1225 : super(connection) { | 1278 : super(connection) { |
| 1226 _connection = connection; | 1279 _connection = connection; |
| 1227 } | 1280 } |
| 1228 | 1281 |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1417 } | 1470 } |
| 1418 | 1471 |
| 1419 | 1472 |
| 1420 class _HttpClientConnection | 1473 class _HttpClientConnection |
| 1421 extends _HttpConnectionBase implements HttpClientConnection { | 1474 extends _HttpConnectionBase implements HttpClientConnection { |
| 1422 | 1475 |
| 1423 _HttpClientConnection(_HttpClient this._client) { | 1476 _HttpClientConnection(_HttpClient this._client) { |
| 1424 _httpParser = new _HttpParser.responseParser(); | 1477 _httpParser = new _HttpParser.responseParser(); |
| 1425 } | 1478 } |
| 1426 | 1479 |
| 1480 bool _write(List<int> data, [bool copyBuffer = false]) { | |
| 1481 return _socket.outputStream.write(data, copyBuffer); | |
| 1482 } | |
| 1483 | |
| 1484 bool _writeFrom(List<int> data, [int offset, int len]) { | |
| 1485 return _socket.outputStream.writeFrom(data, offset, len); | |
| 1486 } | |
| 1487 | |
| 1488 bool _flush() { | |
| 1489 _socket.outputStream.flush(); | |
| 1490 } | |
| 1491 | |
| 1492 bool _close() { | |
| 1493 _socket.outputStream.close(); | |
| 1494 } | |
| 1495 | |
| 1496 bool _destroy() { | |
| 1497 _socket.close(); | |
| 1498 } | |
| 1499 | |
| 1500 DetachedSocket _detachSocket() { | |
| 1501 _socket.onData = null; | |
| 1502 _socket.onClosed = null; | |
| 1503 _socket.onError = null; | |
| 1504 _socket.outputStream.onNoPendingWrites = null; | |
| 1505 Socket socket = _socket; | |
| 1506 _socket = null; | |
| 1507 if (onDetach != null) onDetach(); | |
| 1508 return new _DetachedSocket(socket, _httpParser.readUnparsedData()); | |
| 1509 } | |
| 1510 | |
| 1427 void _connectionEstablished(_SocketConnection socketConn) { | 1511 void _connectionEstablished(_SocketConnection socketConn) { |
| 1428 super._connectionEstablished(socketConn._socket); | 1512 super._connectionEstablished(socketConn._socket); |
| 1429 _socketConn = socketConn; | 1513 _socketConn = socketConn; |
| 1430 // Register HTTP parser callbacks. | 1514 // Register HTTP parser callbacks. |
| 1431 _httpParser.responseStart = _onResponseReceived; | 1515 _httpParser.responseStart = _onResponseReceived; |
| 1432 _httpParser.dataReceived = _onDataReceived; | 1516 _httpParser.dataReceived = _onDataReceived; |
| 1433 _httpParser.dataEnd = _onDataEnd; | 1517 _httpParser.dataEnd = _onDataEnd; |
| 1434 _httpParser.error = _onError; | 1518 _httpParser.error = _onError; |
| 1435 _httpParser.closed = _onClosed; | 1519 _httpParser.closed = _onClosed; |
| 1436 _httpParser.requestStart = (method, uri, version) { assert(false); }; | 1520 _httpParser.requestStart = (method, uri, version) { assert(false); }; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1465 | 1549 |
| 1466 void _requestClosed() { | 1550 void _requestClosed() { |
| 1467 _state |= _HttpConnectionBase.REQUEST_DONE; | 1551 _state |= _HttpConnectionBase.REQUEST_DONE; |
| 1468 _checkSocketDone(); | 1552 _checkSocketDone(); |
| 1469 } | 1553 } |
| 1470 | 1554 |
| 1471 HttpClientRequest open(String method, Uri uri) { | 1555 HttpClientRequest open(String method, Uri uri) { |
| 1472 _method = method; | 1556 _method = method; |
| 1473 // Tell the HTTP parser the method it is expecting a response to. | 1557 // Tell the HTTP parser the method it is expecting a response to. |
| 1474 _httpParser.responseToMethod = method; | 1558 _httpParser.responseToMethod = method; |
| 1475 _request = new _HttpClientRequest(method, uri, this); | 1559 // If the connection already have a request this is a retry of a |
|
Mads Ager (google)
2012/12/05 16:02:18
have -> has
Søren Gjesse
2012/12/06 17:23:08
Done.
| |
| 1560 // request. In this case the request object is reused to ensure | |
| 1561 // that the same headers are send. | |
| 1562 if (_request != null) { | |
| 1563 _request._method = method; | |
| 1564 _request._uri = uri; | |
| 1565 _request._headers._mutable = true; | |
| 1566 _request._state = _HttpRequestResponseBase.START; | |
| 1567 } else { | |
| 1568 _request = new _HttpClientRequest(method, uri, this); | |
| 1569 } | |
| 1476 _response = new _HttpClientResponse(this); | 1570 _response = new _HttpClientResponse(this); |
| 1477 return _request; | 1571 return _request; |
| 1478 } | 1572 } |
| 1479 | 1573 |
| 1480 DetachedSocket detachSocket() { | 1574 DetachedSocket detachSocket() { |
| 1481 return _detachSocket(); | 1575 return _detachSocket(); |
| 1482 } | 1576 } |
| 1483 | 1577 |
| 1484 void _onClosed() { | 1578 void _onClosed() { |
| 1485 _state |= _HttpConnectionBase.READ_CLOSED; | 1579 _state |= _HttpConnectionBase.READ_CLOSED; |
| 1486 _checkSocketDone(); | 1580 _checkSocketDone(); |
| 1487 } | 1581 } |
| 1488 | 1582 |
| 1489 void _onError(e) { | 1583 void _onError(e) { |
| 1490 // Cancel any pending data in the HTTP parser. | 1584 // Cancel any pending data in the HTTP parser. |
| 1491 _httpParser.cancel(); | 1585 _httpParser.cancel(); |
| 1492 if (_socketConn != null) { | 1586 if (_socketConn != null) { |
| 1493 _client._closeSocketConnection(_socketConn); | 1587 _client._closeSocketConnection(_socketConn); |
| 1494 } | 1588 } |
| 1495 // Report the error. | 1589 |
| 1496 if (_response != null && _response._streamErrorHandler != null) { | 1590 // If it looks as if we got a bad connection from the connection |
| 1497 _response._streamErrorHandler(e); | 1591 // pool and the request can be retried do a retry. |
| 1498 } else if (_onErrorCallback != null) { | 1592 if (_socketConn != null && _socketConn._fromPool && _request._emptyBody) { |
| 1499 _onErrorCallback(e); | 1593 String method = _request._method; |
| 1594 Uri uri = _request._uri; | |
| 1595 _socketConn = null; | |
| 1596 | |
| 1597 // Retry the URL using the same connection instance. | |
| 1598 _httpParser.restart(); | |
| 1599 _client._openUrl(method, uri, this); | |
| 1500 } else { | 1600 } else { |
| 1501 throw e; | 1601 // Report the error. |
| 1602 if (_response != null && _response._streamErrorHandler != null) { | |
| 1603 _response._streamErrorHandler(e); | |
| 1604 } else if (_onErrorCallback != null) { | |
| 1605 _onErrorCallback(e); | |
| 1606 } else { | |
| 1607 throw e; | |
| 1608 } | |
| 1502 } | 1609 } |
| 1503 } | 1610 } |
| 1504 | 1611 |
| 1505 void _onResponseReceived(int statusCode, | 1612 void _onResponseReceived(int statusCode, |
| 1506 String reasonPhrase, | 1613 String reasonPhrase, |
| 1507 String version, | 1614 String version, |
| 1508 _HttpHeaders headers) { | 1615 _HttpHeaders headers) { |
| 1509 _response._onResponseReceived(statusCode, reasonPhrase, version, headers); | 1616 _response._onResponseReceived(statusCode, reasonPhrase, version, headers); |
| 1510 } | 1617 } |
| 1511 | 1618 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1532 void set onResponse(void handler(HttpClientResponse response)) { | 1639 void set onResponse(void handler(HttpClientResponse response)) { |
| 1533 _onResponse = handler; | 1640 _onResponse = handler; |
| 1534 } | 1641 } |
| 1535 | 1642 |
| 1536 void set onError(void callback(e)) { | 1643 void set onError(void callback(e)) { |
| 1537 _onErrorCallback = callback; | 1644 _onErrorCallback = callback; |
| 1538 } | 1645 } |
| 1539 | 1646 |
| 1540 void _doRetry(_RedirectInfo retry) { | 1647 void _doRetry(_RedirectInfo retry) { |
| 1541 assert(_socketConn == null); | 1648 assert(_socketConn == null); |
| 1542 _request = null; | |
| 1543 _response = null; | |
| 1544 | 1649 |
| 1545 // Retry the URL using the same connection instance. | 1650 // Retry the URL using the same connection instance. |
| 1546 _state = _HttpConnectionBase.IDLE; | 1651 _state = _HttpConnectionBase.IDLE; |
| 1547 _client._openUrl(retry.method, retry.location, this); | 1652 _client._openUrl(retry.method, retry.location, this); |
| 1548 } | 1653 } |
| 1549 | 1654 |
| 1550 void _retry() { | 1655 void _retry() { |
| 1551 var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); | 1656 var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); |
| 1552 // The actual retry is postponed until both response and request | 1657 // The actual retry is postponed until both response and request |
| 1553 // are done. | 1658 // are done. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1608 | 1713 |
| 1609 | 1714 |
| 1610 // Class for holding keep-alive sockets in the cache for the HTTP | 1715 // Class for holding keep-alive sockets in the cache for the HTTP |
| 1611 // client together with the connection information. | 1716 // client together with the connection information. |
| 1612 class _SocketConnection { | 1717 class _SocketConnection { |
| 1613 _SocketConnection(String this._host, | 1718 _SocketConnection(String this._host, |
| 1614 int this._port, | 1719 int this._port, |
| 1615 Socket this._socket); | 1720 Socket this._socket); |
| 1616 | 1721 |
| 1617 void _markReturned() { | 1722 void _markReturned() { |
| 1618 _socket.onData = null; | 1723 // Any activity on the socket while waiting in the pool will |
| 1619 _socket.onClosed = null; | 1724 // invalidate the connection os that it is not reused. |
|
Mads Ager (google)
2012/12/05 16:02:18
os -> so
Søren Gjesse
2012/12/06 17:23:08
Done.
| |
| 1620 _socket.onError = null; | 1725 _socket.onData = _invalidate; |
| 1726 _socket.onClosed = _invalidate; | |
| 1727 _socket.onError = (_) => _invalidate(); | |
| 1621 _returnTime = new Date.now(); | 1728 _returnTime = new Date.now(); |
| 1622 _httpClientConnection = null; | 1729 _httpClientConnection = null; |
| 1623 } | 1730 } |
| 1624 | 1731 |
| 1732 void _markRetreived() { | |
|
Mads Ager (google)
2012/12/05 16:02:18
_markRetrieved
Søren Gjesse
2012/12/06 17:23:08
Done.
| |
| 1733 _socket.onData = null; | |
| 1734 _socket.onClosed = null; | |
| 1735 _socket.onError = null; | |
| 1736 _httpClientConnection = null; | |
| 1737 } | |
| 1738 | |
| 1625 void _close() { | 1739 void _close() { |
| 1626 _socket.onData = null; | 1740 _socket.onData = null; |
| 1627 _socket.onClosed = null; | 1741 _socket.onClosed = null; |
| 1628 _socket.onError = null; | 1742 _socket.onError = null; |
| 1629 _httpClientConnection = null; | 1743 _httpClientConnection = null; |
| 1630 _socket.close(); | 1744 _socket.close(); |
| 1631 } | 1745 } |
| 1632 | 1746 |
| 1633 Duration _idleTime(Date now) => now.difference(_returnTime); | 1747 Duration _idleTime(Date now) => now.difference(_returnTime); |
| 1634 | 1748 |
| 1749 bool get _fromPool => _returnTime != null; | |
| 1750 | |
| 1751 void _invalidate() { | |
| 1752 _valid = false; | |
| 1753 _close(); | |
| 1754 } | |
| 1755 | |
| 1635 int get hashCode => _socket.hashCode; | 1756 int get hashCode => _socket.hashCode; |
| 1636 | 1757 |
| 1637 String _host; | 1758 String _host; |
| 1638 int _port; | 1759 int _port; |
| 1639 Socket _socket; | 1760 Socket _socket; |
| 1640 Date _returnTime; | 1761 Date _returnTime; |
| 1762 bool _valid = true; | |
| 1641 HttpClientConnection _httpClientConnection; | 1763 HttpClientConnection _httpClientConnection; |
| 1642 } | 1764 } |
| 1643 | 1765 |
| 1644 class _ProxyConfiguration { | 1766 class _ProxyConfiguration { |
| 1645 static const String PROXY_PREFIX = "PROXY "; | 1767 static const String PROXY_PREFIX = "PROXY "; |
| 1646 static const String DIRECT_PREFIX = "DIRECT"; | 1768 static const String DIRECT_PREFIX = "DIRECT"; |
| 1647 | 1769 |
| 1648 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() { | 1770 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() { |
| 1649 if (configuration == null) { | 1771 if (configuration == null) { |
| 1650 throw new HttpException("Invalid proxy configuration $configuration"); | 1772 throw new HttpException("Invalid proxy configuration $configuration"); |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1840 connectPort = port; | 1962 connectPort = port; |
| 1841 } else { | 1963 } else { |
| 1842 connectHost = proxy.host; | 1964 connectHost = proxy.host; |
| 1843 connectPort = proxy.port; | 1965 connectPort = proxy.port; |
| 1844 } | 1966 } |
| 1845 | 1967 |
| 1846 // If there are active connections for this key get the first one | 1968 // If there are active connections for this key get the first one |
| 1847 // otherwise create a new one. | 1969 // otherwise create a new one. |
| 1848 String key = _connectionKey(connectHost, connectPort); | 1970 String key = _connectionKey(connectHost, connectPort); |
| 1849 Queue socketConnections = _openSockets[key]; | 1971 Queue socketConnections = _openSockets[key]; |
| 1850 // Remove active connections that are of the wrong type (HTTP or HTTPS). | 1972 // Remove active connections that are not valid any more or of |
| 1973 // the wrong type (HTTP or HTTPS). | |
| 1851 while (socketConnections != null && | 1974 while (socketConnections != null && |
| 1852 !socketConnections.isEmpty && | 1975 !socketConnections.isEmpty && |
| 1853 secure != (socketConnections.first._socket is SecureSocket)) { | 1976 (!socketConnections.first._valid || |
| 1854 socketConnection.removeFirst()._close(); | 1977 secure != (socketConnections.first._socket is SecureSocket))) { |
| 1978 socketConnections.removeFirst()._close(); | |
| 1855 } | 1979 } |
| 1856 if (socketConnections == null || socketConnections.isEmpty) { | 1980 if (socketConnections == null || socketConnections.isEmpty) { |
| 1857 Socket socket = secure ? new SecureSocket(connectHost, connectPort) : | 1981 Socket socket = secure ? new SecureSocket(connectHost, connectPort) : |
| 1858 new Socket(connectHost, connectPort); | 1982 new Socket(connectHost, connectPort); |
| 1859 // Until the connection is established handle connection errors | 1983 // Until the connection is established handle connection errors |
| 1860 // here as the HttpClientConnection object is not yet associated | 1984 // here as the HttpClientConnection object is not yet associated |
| 1861 // with the socket. | 1985 // with the socket. |
| 1862 socket.onError = (e) { | 1986 socket.onError = (e) { |
| 1863 proxyIndex++; | 1987 proxyIndex++; |
| 1864 if (proxyIndex < proxyConfiguration.proxies.length) { | 1988 if (proxyIndex < proxyConfiguration.proxies.length) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1877 // HttpClientConnection object which will be associated with | 2001 // HttpClientConnection object which will be associated with |
| 1878 // the connected socket. | 2002 // the connected socket. |
| 1879 socket.onError = null; | 2003 socket.onError = null; |
| 1880 _SocketConnection socketConn = | 2004 _SocketConnection socketConn = |
| 1881 new _SocketConnection(connectHost, connectPort, socket); | 2005 new _SocketConnection(connectHost, connectPort, socket); |
| 1882 _activeSockets.add(socketConn); | 2006 _activeSockets.add(socketConn); |
| 1883 _connectionOpened(socketConn, connection, !proxy.isDirect); | 2007 _connectionOpened(socketConn, connection, !proxy.isDirect); |
| 1884 }; | 2008 }; |
| 1885 } else { | 2009 } else { |
| 1886 _SocketConnection socketConn = socketConnections.removeFirst(); | 2010 _SocketConnection socketConn = socketConnections.removeFirst(); |
| 2011 socketConn._markRetreived(); | |
| 1887 _activeSockets.add(socketConn); | 2012 _activeSockets.add(socketConn); |
| 1888 new Timer(0, (ignored) => | 2013 new Timer(0, (ignored) => |
| 1889 _connectionOpened(socketConn, connection, !proxy.isDirect)); | 2014 _connectionOpened(socketConn, connection, !proxy.isDirect)); |
| 1890 | 2015 |
| 1891 // Get rid of eviction timer if there are no more active connections. | 2016 // Get rid of eviction timer if there are no more active connections. |
| 1892 if (socketConnections.isEmpty) _openSockets.remove(key); | 2017 if (socketConnections.isEmpty) _openSockets.remove(key); |
| 1893 if (_openSockets.isEmpty) _cancelEvictionTimer(); | 2018 if (_openSockets.isEmpty) _cancelEvictionTimer(); |
| 1894 } | 2019 } |
| 1895 } | 2020 } |
| 1896 | 2021 |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2150 | 2275 |
| 2151 | 2276 |
| 2152 class _RedirectInfo implements RedirectInfo { | 2277 class _RedirectInfo implements RedirectInfo { |
| 2153 const _RedirectInfo(int this.statusCode, | 2278 const _RedirectInfo(int this.statusCode, |
| 2154 String this.method, | 2279 String this.method, |
| 2155 Uri this.location); | 2280 Uri this.location); |
| 2156 final int statusCode; | 2281 final int statusCode; |
| 2157 final String method; | 2282 final String method; |
| 2158 final Uri location; | 2283 final Uri location; |
| 2159 } | 2284 } |
| OLD | NEW |