OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 const int _OUTGOING_BUFFER_SIZE = 8 * 1024; | 7 const int _OUTGOING_BUFFER_SIZE = 8 * 1024; |
8 | 8 |
9 class _HttpIncoming extends Stream<List<int>> { | 9 class _HttpIncoming extends Stream<List<int>> { |
10 final int _transferLength; | 10 final int _transferLength; |
(...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1352 _streamFuture = outgoing.done | 1352 _streamFuture = outgoing.done |
1353 .then((s) { | 1353 .then((s) { |
1354 // Request sent, set up response completer. | 1354 // Request sent, set up response completer. |
1355 _nextResponseCompleter = new Completer(); | 1355 _nextResponseCompleter = new Completer(); |
1356 | 1356 |
1357 // Listen for response. | 1357 // Listen for response. |
1358 _nextResponseCompleter.future | 1358 _nextResponseCompleter.future |
1359 .then((incoming) { | 1359 .then((incoming) { |
1360 _currentUri = null; | 1360 _currentUri = null; |
1361 incoming.dataDone.then((closing) { | 1361 incoming.dataDone.then((closing) { |
| 1362 if (closed) return; |
1362 if (!closing && | 1363 if (!closing && |
1363 !_dispose && | 1364 !_dispose && |
1364 incoming.headers.persistentConnection && | 1365 incoming.headers.persistentConnection && |
1365 request.persistentConnection) { | 1366 request.persistentConnection) { |
1366 // Return connection, now we are done. | 1367 // Return connection, now we are done. |
1367 _httpClient._returnConnection(this); | 1368 _httpClient._returnConnection(this); |
1368 _subscription.resume(); | 1369 _subscription.resume(); |
1369 } else { | 1370 } else { |
1370 destroy(); | 1371 destroy(); |
1371 } | 1372 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1495 | 1496 |
1496 class _ConnnectionInfo { | 1497 class _ConnnectionInfo { |
1497 final _HttpClientConnection connection; | 1498 final _HttpClientConnection connection; |
1498 final _Proxy proxy; | 1499 final _Proxy proxy; |
1499 | 1500 |
1500 _ConnnectionInfo(this.connection, this.proxy); | 1501 _ConnnectionInfo(this.connection, this.proxy); |
1501 } | 1502 } |
1502 | 1503 |
1503 | 1504 |
1504 class _HttpClient implements HttpClient { | 1505 class _HttpClient implements HttpClient { |
1505 // TODO(ajohnsen): Use eviction timeout. | |
1506 bool _closing = false; | 1506 bool _closing = false; |
1507 | |
1508 final Map<String, Set<_HttpClientConnection>> _idleConnections | 1507 final Map<String, Set<_HttpClientConnection>> _idleConnections |
1509 = new HashMap<String, Set<_HttpClientConnection>>(); | 1508 = new HashMap<String, Set<_HttpClientConnection>>(); |
1510 final Set<_HttpClientConnection> _activeConnections | 1509 final Map<String, Set<_HttpClientConnection>> _activeConnections |
1511 = new HashSet<_HttpClientConnection>(); | 1510 = new HashMap<String, Set<_HttpClientConnection>>(); |
1512 final List<_Credentials> _credentials = []; | 1511 final List<_Credentials> _credentials = []; |
1513 final List<_ProxyCredentials> _proxyCredentials = []; | 1512 final List<_ProxyCredentials> _proxyCredentials = []; |
1514 Function _authenticate; | 1513 Function _authenticate; |
1515 Function _authenticateProxy; | 1514 Function _authenticateProxy; |
1516 Function _findProxy = HttpClient.findProxyFromEnvironment; | 1515 Function _findProxy = HttpClient.findProxyFromEnvironment; |
1517 Duration _idleTimeout = const Duration(seconds: 15); | 1516 Duration _idleTimeout = const Duration(seconds: 15); |
1518 Function _badCertificateCallback; | 1517 Function _badCertificateCallback; |
1519 | 1518 |
1520 Timer _noActiveTimer; | 1519 Timer _noActiveTimer; |
1521 | 1520 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1592 [], | 1591 [], |
1593 (l, e) { | 1592 (l, e) { |
1594 l.addAll(e); | 1593 l.addAll(e); |
1595 return l; | 1594 return l; |
1596 }); | 1595 }); |
1597 idle.forEach((e) { | 1596 idle.forEach((e) { |
1598 e.close(); | 1597 e.close(); |
1599 }); | 1598 }); |
1600 assert(_idleConnections.isEmpty); | 1599 assert(_idleConnections.isEmpty); |
1601 if (force) { | 1600 if (force) { |
1602 for (var connection in _activeConnections.toList()) { | 1601 for (var connection in |
| 1602 _activeConnections.values.expand((s) => s).toList()) { |
1603 connection.destroy(); | 1603 connection.destroy(); |
1604 } | 1604 } |
1605 assert(_activeConnections.isEmpty); | 1605 assert(_activeConnections.isEmpty); |
1606 _activeConnections.clear(); | 1606 _activeConnections.clear(); |
1607 } | 1607 } |
1608 } | 1608 } |
1609 | 1609 |
1610 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { | 1610 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { |
1611 _authenticate = f; | 1611 _authenticate = f; |
1612 } | 1612 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1696 } | 1696 } |
1697 } | 1697 } |
1698 return request | 1698 return request |
1699 ..headers.chunkedTransferEncoding = false | 1699 ..headers.chunkedTransferEncoding = false |
1700 ..contentLength = 0; | 1700 ..contentLength = 0; |
1701 }); | 1701 }); |
1702 } | 1702 } |
1703 | 1703 |
1704 // Return a live connection to the idle pool. | 1704 // Return a live connection to the idle pool. |
1705 void _returnConnection(_HttpClientConnection connection) { | 1705 void _returnConnection(_HttpClientConnection connection) { |
1706 _activeConnections.remove(connection); | 1706 var key = connection.key; |
| 1707 _activeConnections[key].remove(connection); |
| 1708 if (_activeConnections[key].isEmpty) { |
| 1709 _activeConnections.remove(key); |
| 1710 } |
1707 if (_closing) { | 1711 if (_closing) { |
1708 connection.close(); | 1712 connection.close(); |
1709 return; | 1713 return; |
1710 } | 1714 } |
1711 if (!_idleConnections.containsKey(connection.key)) { | 1715 _idleConnections |
1712 _idleConnections[connection.key] = new HashSet(); | 1716 .putIfAbsent(key, () => new HashSet()) |
1713 } | 1717 .add(connection); |
1714 _idleConnections[connection.key].add(connection); | |
1715 connection.startTimer(); | 1718 connection.startTimer(); |
1716 _updateTimers(); | 1719 _updateTimers(); |
1717 } | 1720 } |
1718 | 1721 |
1719 // Remove a closed connnection from the active set. | 1722 // Remove a closed connnection from the active set. |
1720 void _connectionClosed(_HttpClientConnection connection) { | 1723 void _connectionClosed(_HttpClientConnection connection) { |
1721 connection.stopTimer(); | 1724 connection.stopTimer(); |
1722 _activeConnections.remove(connection); | 1725 var key = connection.key; |
1723 if (_idleConnections.containsKey(connection.key)) { | 1726 if (_activeConnections.containsKey(key)) { |
1724 _idleConnections[connection.key].remove(connection); | 1727 _activeConnections[key].remove(connection); |
1725 if (_idleConnections[connection.key].isEmpty) { | 1728 if (_activeConnections[key].isEmpty) { |
1726 _idleConnections.remove(connection.key); | 1729 _activeConnections.remove(key); |
| 1730 } |
| 1731 } |
| 1732 if (_idleConnections.containsKey(key)) { |
| 1733 _idleConnections[key].remove(connection); |
| 1734 if (_idleConnections[key].isEmpty) { |
| 1735 _idleConnections.remove(key); |
1727 } | 1736 } |
1728 } | 1737 } |
1729 _updateTimers(); | 1738 _updateTimers(); |
1730 } | 1739 } |
1731 | 1740 |
1732 void _updateTimers() { | 1741 void _updateTimers() { |
1733 if (_activeConnections.isEmpty) { | 1742 if (_activeConnections.isEmpty) { |
1734 if (!_idleConnections.isEmpty && _noActiveTimer == null) { | 1743 if (!_idleConnections.isEmpty && _noActiveTimer == null) { |
1735 _noActiveTimer = new Timer(const Duration(milliseconds: 100), () { | 1744 _noActiveTimer = new Timer(const Duration(milliseconds: 100), () { |
1736 _noActiveTimer = null; | 1745 _noActiveTimer = null; |
(...skipping 23 matching lines...) Expand all Loading... |
1760 String host = proxy.isDirect ? uriHost: proxy.host; | 1769 String host = proxy.isDirect ? uriHost: proxy.host; |
1761 int port = proxy.isDirect ? uriPort: proxy.port; | 1770 int port = proxy.isDirect ? uriPort: proxy.port; |
1762 String key = _HttpClientConnection.makeKey(isSecure, host, port); | 1771 String key = _HttpClientConnection.makeKey(isSecure, host, port); |
1763 if (_idleConnections.containsKey(key)) { | 1772 if (_idleConnections.containsKey(key)) { |
1764 var connection = _idleConnections[key].first; | 1773 var connection = _idleConnections[key].first; |
1765 _idleConnections[key].remove(connection); | 1774 _idleConnections[key].remove(connection); |
1766 if (_idleConnections[key].isEmpty) { | 1775 if (_idleConnections[key].isEmpty) { |
1767 _idleConnections.remove(key); | 1776 _idleConnections.remove(key); |
1768 } | 1777 } |
1769 connection.stopTimer(); | 1778 connection.stopTimer(); |
1770 _activeConnections.add(connection); | 1779 _activeConnections |
| 1780 .putIfAbsent(key, () => new HashSet()) |
| 1781 .add(connection); |
1771 _updateTimers(); | 1782 _updateTimers(); |
1772 return new Future.value(new _ConnnectionInfo(connection, proxy)); | 1783 return new Future.value(new _ConnnectionInfo(connection, proxy)); |
1773 } | 1784 } |
1774 var currentBadCertificateCallback = _badCertificateCallback; | 1785 var currentBadCertificateCallback = _badCertificateCallback; |
1775 bool callback(X509Certificate certificate) => | 1786 bool callback(X509Certificate certificate) => |
1776 currentBadCertificateCallback == null ? false : | 1787 currentBadCertificateCallback == null ? false : |
1777 currentBadCertificateCallback(certificate, uriHost, uriPort); | 1788 currentBadCertificateCallback(certificate, uriHost, uriPort); |
1778 Future socketFuture = (isSecure && proxy.isDirect | 1789 Future socketFuture = (isSecure && proxy.isDirect |
1779 ? SecureSocket.connect(host, | 1790 ? SecureSocket.connect(host, |
1780 port, | 1791 port, |
1781 sendClientCertificate: true, | 1792 sendClientCertificate: true, |
1782 onBadCertificate: callback) | 1793 onBadCertificate: callback) |
1783 : Socket.connect(host, port)); | 1794 : Socket.connect(host, port)); |
1784 return socketFuture.then((socket) { | 1795 return socketFuture.then((socket) { |
1785 socket.setOption(SocketOption.TCP_NODELAY, true); | 1796 socket.setOption(SocketOption.TCP_NODELAY, true); |
1786 var connection = new _HttpClientConnection(key, socket, this); | 1797 var connection = new _HttpClientConnection(key, socket, this); |
1787 if (isSecure && !proxy.isDirect) { | 1798 if (isSecure && !proxy.isDirect) { |
1788 connection._dispose = true; | 1799 connection._dispose = true; |
1789 return connection.createProxyTunnel( | 1800 return connection.createProxyTunnel( |
1790 uriHost, uriPort, proxy, callback) | 1801 uriHost, uriPort, proxy, callback) |
1791 .then((tunnel) { | 1802 .then((tunnel) { |
1792 _activeConnections.add(tunnel); | 1803 _activeConnections |
| 1804 .putIfAbsent(tunnel.key, () => new HashSet()) |
| 1805 .add(tunnel); |
1793 return new _ConnnectionInfo(tunnel, proxy); | 1806 return new _ConnnectionInfo(tunnel, proxy); |
1794 }); | 1807 }); |
1795 } else { | 1808 } else { |
1796 _activeConnections.add(connection); | 1809 _activeConnections |
| 1810 .putIfAbsent(key, () => new HashSet()) |
| 1811 .add(connection); |
1797 return new _ConnnectionInfo(connection, proxy); | 1812 return new _ConnnectionInfo(connection, proxy); |
1798 } | 1813 } |
1799 }, onError: (error) { | 1814 }, onError: (error) { |
1800 // Continue with next proxy. | 1815 // Continue with next proxy. |
1801 return connect(error); | 1816 return connect(error); |
1802 }); | 1817 }); |
1803 } | 1818 } |
1804 return connect(new HttpException("No proxies given")); | 1819 return connect(new HttpException("No proxies given")); |
1805 } | 1820 } |
1806 | 1821 |
(...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2621 const _RedirectInfo(this.statusCode, this.method, this.location); | 2636 const _RedirectInfo(this.statusCode, this.method, this.location); |
2622 } | 2637 } |
2623 | 2638 |
2624 String _getHttpVersion() { | 2639 String _getHttpVersion() { |
2625 var version = Platform.version; | 2640 var version = Platform.version; |
2626 // Only include major and minor version numbers. | 2641 // Only include major and minor version numbers. |
2627 int index = version.indexOf('.', version.indexOf('.') + 1); | 2642 int index = version.indexOf('.', version.indexOf('.') + 1); |
2628 version = version.substring(0, index); | 2643 version = version.substring(0, index); |
2629 return 'Dart/$version (dart:io)'; | 2644 return 'Dart/$version (dart:io)'; |
2630 } | 2645 } |
OLD | NEW |