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 1445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1456 DetachedSocket detachSocket() { | 1456 DetachedSocket detachSocket() { |
1457 return _detachSocket(); | 1457 return _detachSocket(); |
1458 } | 1458 } |
1459 | 1459 |
1460 void _onClosed() { | 1460 void _onClosed() { |
1461 _state |= _HttpConnectionBase.READ_CLOSED; | 1461 _state |= _HttpConnectionBase.READ_CLOSED; |
1462 _checkSocketDone(); | 1462 _checkSocketDone(); |
1463 } | 1463 } |
1464 | 1464 |
1465 void _onError(e) { | 1465 void _onError(e) { |
1466 // Socket is closed either due to an error or due to normal socket close. | 1466 if (_socketConn != null) { |
| 1467 _client._closeSocketConnection(_socketConn); |
| 1468 } |
1467 if (_onErrorCallback != null) { | 1469 if (_onErrorCallback != null) { |
1468 _onErrorCallback(e); | 1470 _onErrorCallback(e); |
1469 } else { | 1471 } else { |
1470 throw e; | 1472 throw e; |
1471 } | 1473 } |
1472 // Propagate the error to the streams. | 1474 // Propagate the error to the streams. |
1473 if (_response != null && _response._streamErrorHandler != null) { | 1475 if (_response != null && _response._streamErrorHandler != null) { |
1474 _response._streamErrorHandler(e); | 1476 _response._streamErrorHandler(e); |
1475 } | 1477 } |
1476 if (_socketConn != null) { | |
1477 _client._closeSocketConnection(_socketConn); | |
1478 } | |
1479 } | 1478 } |
1480 | 1479 |
1481 void _onResponseReceived(int statusCode, | 1480 void _onResponseReceived(int statusCode, |
1482 String reasonPhrase, | 1481 String reasonPhrase, |
1483 String version, | 1482 String version, |
1484 _HttpHeaders headers) { | 1483 _HttpHeaders headers) { |
1485 _response._onResponseReceived(statusCode, reasonPhrase, version, headers); | 1484 _response._onResponseReceived(statusCode, reasonPhrase, version, headers); |
1486 } | 1485 } |
1487 | 1486 |
1488 void _onDataReceived(List<int> data) { | 1487 void _onDataReceived(List<int> data) { |
1489 _response._onDataReceived(data); | 1488 _response._onDataReceived(data); |
1490 } | 1489 } |
1491 | 1490 |
1492 void _onDataEnd(bool close) { | 1491 void _onDataEnd(bool close) { |
| 1492 _state |= _HttpConnectionBase.RESPONSE_DONE; |
1493 _response._onDataEnd(); | 1493 _response._onDataEnd(); |
1494 _state |= _HttpConnectionBase.RESPONSE_DONE; | |
1495 _checkSocketDone(); | 1494 _checkSocketDone(); |
1496 } | 1495 } |
1497 | 1496 |
| 1497 void _onClientShutdown() { |
| 1498 if (!_isResponseDone) { |
| 1499 _onError(new HttpException("Client shutdown")); |
| 1500 } |
| 1501 } |
| 1502 |
1498 void set onRequest(void handler(HttpClientRequest request)) { | 1503 void set onRequest(void handler(HttpClientRequest request)) { |
1499 _onRequest = handler; | 1504 _onRequest = handler; |
1500 } | 1505 } |
1501 | 1506 |
1502 void set onResponse(void handler(HttpClientResponse response)) { | 1507 void set onResponse(void handler(HttpClientResponse response)) { |
1503 _onResponse = handler; | 1508 _onResponse = handler; |
1504 } | 1509 } |
1505 | 1510 |
1506 void set onError(void callback(e)) { | 1511 void set onError(void callback(e)) { |
1507 _onErrorCallback = callback; | 1512 _onErrorCallback = callback; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1541 } | 1546 } |
1542 | 1547 |
1543 void redirect([String method, Uri url]) { | 1548 void redirect([String method, Uri url]) { |
1544 if (method == null) method = _method; | 1549 if (method == null) method = _method; |
1545 if (url == null) { | 1550 if (url == null) { |
1546 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); | 1551 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); |
1547 } | 1552 } |
1548 var redirect = new _RedirectInfo(_response.statusCode, method, url); | 1553 var redirect = new _RedirectInfo(_response.statusCode, method, url); |
1549 // The actual redirect is postponed until both response and | 1554 // The actual redirect is postponed until both response and |
1550 // request are done. | 1555 // request are done. |
1551 if (_isAllDone) { | 1556 assert(_pendingRetry == null); |
1552 _doRedirect(redirect); | 1557 _pendingRedirect = redirect; |
1553 } else { | |
1554 // Prepare for redirect. | |
1555 assert(_pendingRetry == null); | |
1556 _pendingRedirect = redirect; | |
1557 } | |
1558 } | 1558 } |
1559 | 1559 |
1560 List<RedirectInfo> get redirects => _redirects; | 1560 List<RedirectInfo> get redirects => _redirects; |
1561 | 1561 |
1562 Function _onRequest; | 1562 Function _onRequest; |
1563 Function _onResponse; | 1563 Function _onResponse; |
1564 Function _onErrorCallback; | 1564 Function _onErrorCallback; |
1565 | 1565 |
1566 _HttpClient _client; | 1566 _HttpClient _client; |
1567 _SocketConnection _socketConn; | 1567 _SocketConnection _socketConn; |
(...skipping 19 matching lines...) Expand all Loading... |
1587 class _SocketConnection { | 1587 class _SocketConnection { |
1588 _SocketConnection(String this._host, | 1588 _SocketConnection(String this._host, |
1589 int this._port, | 1589 int this._port, |
1590 Socket this._socket); | 1590 Socket this._socket); |
1591 | 1591 |
1592 void _markReturned() { | 1592 void _markReturned() { |
1593 _socket.onData = null; | 1593 _socket.onData = null; |
1594 _socket.onClosed = null; | 1594 _socket.onClosed = null; |
1595 _socket.onError = null; | 1595 _socket.onError = null; |
1596 _returnTime = new Date.now(); | 1596 _returnTime = new Date.now(); |
| 1597 _httpClientConnection = null; |
1597 } | 1598 } |
1598 | 1599 |
1599 void _close() { | 1600 void _close() { |
1600 _socket.onData = null; | 1601 _socket.onData = null; |
1601 _socket.onClosed = null; | 1602 _socket.onClosed = null; |
1602 _socket.onError = null; | 1603 _socket.onError = null; |
| 1604 _httpClientConnection = null; |
1603 _socket.close(); | 1605 _socket.close(); |
1604 } | 1606 } |
1605 | 1607 |
1606 Duration _idleTime(Date now) => now.difference(_returnTime); | 1608 Duration _idleTime(Date now) => now.difference(_returnTime); |
1607 | 1609 |
1608 int get hashCode => _socket.hashCode; | 1610 int get hashCode => _socket.hashCode; |
1609 | 1611 |
1610 String _host; | 1612 String _host; |
1611 int _port; | 1613 int _port; |
1612 Socket _socket; | 1614 Socket _socket; |
1613 Date _returnTime; | 1615 Date _returnTime; |
| 1616 HttpClientConnection _httpClientConnection; |
1614 } | 1617 } |
1615 | 1618 |
1616 class _ProxyConfiguration { | 1619 class _ProxyConfiguration { |
1617 static const String PROXY_PREFIX = "PROXY "; | 1620 static const String PROXY_PREFIX = "PROXY "; |
1618 static const String DIRECT_PREFIX = "DIRECT"; | 1621 static const String DIRECT_PREFIX = "DIRECT"; |
1619 | 1622 |
1620 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() { | 1623 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() { |
1621 if (configuration == null) { | 1624 if (configuration == null) { |
1622 throw new HttpException("Invalid proxy configuration $configuration"); | 1625 throw new HttpException("Invalid proxy configuration $configuration"); |
1623 } | 1626 } |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1723 _authenticate = f; | 1726 _authenticate = f; |
1724 } | 1727 } |
1725 | 1728 |
1726 void addCredentials( | 1729 void addCredentials( |
1727 Uri url, String realm, HttpClientCredentials cr) { | 1730 Uri url, String realm, HttpClientCredentials cr) { |
1728 credentials.add(new _Credentials(url, realm, cr)); | 1731 credentials.add(new _Credentials(url, realm, cr)); |
1729 } | 1732 } |
1730 | 1733 |
1731 set findProxy(String f(Uri uri)) => _findProxy = f; | 1734 set findProxy(String f(Uri uri)) => _findProxy = f; |
1732 | 1735 |
1733 void shutdown() { | 1736 void shutdown({bool force: false}) { |
1734 _closeQueue.shutdown(); | 1737 if (force) _closeQueue.shutdown(); |
1735 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { | 1738 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { |
1736 while (!connections.isEmpty) { | 1739 while (!connections.isEmpty) { |
1737 _SocketConnection socketConn = connections.removeFirst(); | 1740 _SocketConnection socketConn = connections.removeFirst(); |
1738 socketConn._socket.close(); | 1741 socketConn._socket.close(); |
1739 } | 1742 } |
1740 }); | 1743 }); |
1741 _activeSockets.forEach((_SocketConnection socketConn) { | 1744 if (force) { |
1742 socketConn._socket.close(); | 1745 _activeSockets.forEach((_SocketConnection socketConn) { |
1743 }); | 1746 socketConn._socket.close(); |
| 1747 socketConn._httpClientConnection._onClientShutdown(); |
| 1748 }); |
| 1749 } |
1744 if (_evictionTimer != null) _cancelEvictionTimer(); | 1750 if (_evictionTimer != null) _cancelEvictionTimer(); |
1745 _shutdown = true; | 1751 _shutdown = true; |
1746 } | 1752 } |
1747 | 1753 |
1748 void _cancelEvictionTimer() { | 1754 void _cancelEvictionTimer() { |
1749 _evictionTimer.cancel(); | 1755 _evictionTimer.cancel(); |
1750 _evictionTimer = null; | 1756 _evictionTimer = null; |
1751 } | 1757 } |
1752 | 1758 |
1753 String _connectionKey(String host, int port) { | 1759 String _connectionKey(String host, int port) { |
1754 return "$host:$port"; | 1760 return "$host:$port"; |
1755 } | 1761 } |
1756 | 1762 |
1757 HttpClientConnection _prepareHttpClientConnection( | 1763 HttpClientConnection _prepareHttpClientConnection( |
1758 String method, | 1764 String method, |
1759 Uri url, | 1765 Uri url, |
1760 [_HttpClientConnection connection]) { | 1766 [_HttpClientConnection connection]) { |
1761 | 1767 |
1762 void _establishConnection(String host, | 1768 void _establishConnection(String host, |
1763 int port, | 1769 int port, |
1764 _ProxyConfiguration proxyConfiguration, | 1770 _ProxyConfiguration proxyConfiguration, |
1765 int proxyIndex, | 1771 int proxyIndex, |
1766 bool reusedConnection) { | 1772 bool reusedConnection) { |
1767 | 1773 |
1768 void _connectionOpened(_SocketConnection socketConn, | 1774 void _connectionOpened(_SocketConnection socketConn, |
1769 _HttpClientConnection connection, | 1775 _HttpClientConnection connection, |
1770 bool usingProxy) { | 1776 bool usingProxy) { |
| 1777 socketConn._httpClientConnection = connection; |
1771 connection._usingProxy = usingProxy; | 1778 connection._usingProxy = usingProxy; |
1772 connection._connectionEstablished(socketConn); | 1779 connection._connectionEstablished(socketConn); |
1773 HttpClientRequest request = connection.open(method, url); | 1780 HttpClientRequest request = connection.open(method, url); |
1774 request.headers.host = host; | 1781 request.headers.host = host; |
1775 request.headers.port = port; | 1782 request.headers.port = port; |
1776 if (url.userInfo != null && !url.userInfo.isEmpty) { | 1783 if (url.userInfo != null && !url.userInfo.isEmpty) { |
1777 // If the URL contains user information use that for basic | 1784 // If the URL contains user information use that for basic |
1778 // authorization | 1785 // authorization |
1779 _UTF8Encoder encoder = new _UTF8Encoder(); | 1786 _UTF8Encoder encoder = new _UTF8Encoder(); |
1780 String auth = | 1787 String auth = |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1875 proxyConfiguration = new _ProxyConfiguration(_findProxy(url)); | 1882 proxyConfiguration = new _ProxyConfiguration(_findProxy(url)); |
1876 } | 1883 } |
1877 | 1884 |
1878 // Establish the connection starting with the first proxy configured. | 1885 // Establish the connection starting with the first proxy configured. |
1879 _establishConnection(host, port, proxyConfiguration, 0, reusedConnection); | 1886 _establishConnection(host, port, proxyConfiguration, 0, reusedConnection); |
1880 | 1887 |
1881 return connection; | 1888 return connection; |
1882 } | 1889 } |
1883 | 1890 |
1884 void _returnSocketConnection(_SocketConnection socketConn) { | 1891 void _returnSocketConnection(_SocketConnection socketConn) { |
| 1892 // If the HTTP client is being shutdown don't return the connection. |
| 1893 if (_shutdown) { |
| 1894 socketConn._close(); |
| 1895 return; |
| 1896 }; |
| 1897 |
1885 // Mark socket as returned to unregister from the old connection. | 1898 // Mark socket as returned to unregister from the old connection. |
1886 socketConn._markReturned(); | 1899 socketConn._markReturned(); |
1887 | 1900 |
1888 // If the HTTP client is beeing shutdown don't return the connection. | |
1889 if (_shutdown) { | |
1890 socketConn._socket.close(); | |
1891 return; | |
1892 }; | |
1893 | |
1894 String key = _connectionKey(socketConn._host, socketConn._port); | 1901 String key = _connectionKey(socketConn._host, socketConn._port); |
1895 | 1902 |
1896 // Get or create the connection list for this key. | 1903 // Get or create the connection list for this key. |
1897 Queue sockets = _openSockets[key]; | 1904 Queue sockets = _openSockets[key]; |
1898 if (sockets == null) { | 1905 if (sockets == null) { |
1899 sockets = new Queue(); | 1906 sockets = new Queue(); |
1900 _openSockets[key] = sockets; | 1907 _openSockets[key] = sockets; |
1901 } | 1908 } |
1902 | 1909 |
1903 // If there is currently no eviction timer start one. | 1910 // If there is currently no eviction timer start one. |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2098 | 2105 |
2099 | 2106 |
2100 class _RedirectInfo implements RedirectInfo { | 2107 class _RedirectInfo implements RedirectInfo { |
2101 const _RedirectInfo(int this.statusCode, | 2108 const _RedirectInfo(int this.statusCode, |
2102 String this.method, | 2109 String this.method, |
2103 Uri this.location); | 2110 Uri this.location); |
2104 final int statusCode; | 2111 final int statusCode; |
2105 final String method; | 2112 final String method; |
2106 final Uri location; | 2113 final Uri location; |
2107 } | 2114 } |
OLD | NEW |