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