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 1476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1487 assert(_idleTimer == null); | 1487 assert(_idleTimer == null); |
1488 _idleTimer = new Timer( | 1488 _idleTimer = new Timer( |
1489 _httpClient.idleTimeout, | 1489 _httpClient.idleTimeout, |
1490 () { | 1490 () { |
1491 _idleTimer = null; | 1491 _idleTimer = null; |
1492 close(); | 1492 close(); |
1493 }); | 1493 }); |
1494 } | 1494 } |
1495 } | 1495 } |
1496 | 1496 |
1497 class _ConnnectionInfo { | 1497 class _ConnectionInfo { |
1498 final _HttpClientConnection connection; | 1498 final _HttpClientConnection connection; |
1499 final _Proxy proxy; | 1499 final _Proxy proxy; |
1500 | 1500 |
1501 _ConnnectionInfo(this.connection, this.proxy); | 1501 _ConnectionInfo(this.connection, this.proxy); |
1502 } | 1502 } |
1503 | 1503 |
1504 | 1504 |
1505 class _ConnectionTarget { | 1505 class _ConnectionTarget { |
1506 // Unique key for this connection target. | 1506 // Unique key for this connection target. |
1507 final String key; | 1507 final String key; |
| 1508 final String host; |
| 1509 final int port; |
| 1510 final bool isSecure; |
1508 final Set<_HttpClientConnection> _idle = new HashSet(); | 1511 final Set<_HttpClientConnection> _idle = new HashSet(); |
1509 final Set<_HttpClientConnection> _active = new HashSet(); | 1512 final Set<_HttpClientConnection> _active = new HashSet(); |
| 1513 int _connecting = 0; |
1510 | 1514 |
1511 _ConnectionTarget(this.key); | 1515 _ConnectionTarget(this.key, this.host, this.port, this.isSecure); |
1512 | 1516 |
1513 bool get isEmpty => _idle.isEmpty && _active.isEmpty; | 1517 bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0; |
1514 | 1518 |
1515 bool get hasIdle => _idle.isNotEmpty; | 1519 bool get hasIdle => _idle.isNotEmpty; |
1516 | 1520 |
1517 bool get hasActive => _active.isNotEmpty; | 1521 bool get hasActive => _active.isNotEmpty && _connecting > 0; |
1518 | 1522 |
1519 _HttpClientConnection takeIdle() { | 1523 _HttpClientConnection takeIdle() { |
1520 assert(hasIdle); | 1524 assert(hasIdle); |
1521 _HttpClientConnection connection = _idle.first; | 1525 _HttpClientConnection connection = _idle.first; |
1522 _idle.remove(connection); | 1526 _idle.remove(connection); |
1523 connection.stopTimer(); | 1527 connection.stopTimer(); |
1524 _active.add(connection); | 1528 _active.add(connection); |
1525 return connection; | 1529 return connection; |
1526 } | 1530 } |
1527 | 1531 |
(...skipping 16 matching lines...) Expand all Loading... |
1544 void close(bool force) { | 1548 void close(bool force) { |
1545 for (var c in _idle.toList()) { | 1549 for (var c in _idle.toList()) { |
1546 c.close(); | 1550 c.close(); |
1547 } | 1551 } |
1548 if (force) { | 1552 if (force) { |
1549 for (var c in _active.toList()) { | 1553 for (var c in _active.toList()) { |
1550 c.destroy(); | 1554 c.destroy(); |
1551 } | 1555 } |
1552 } | 1556 } |
1553 } | 1557 } |
| 1558 |
| 1559 Future<_ConnectionInfo> connect(String uriHost, |
| 1560 int uriPort, |
| 1561 _Proxy proxy, |
| 1562 _HttpClient client) { |
| 1563 if (hasIdle) { |
| 1564 var connection = takeIdle(); |
| 1565 client._updateTimers(); |
| 1566 return new Future.value(new _ConnectionInfo(connection, proxy)); |
| 1567 } |
| 1568 var currentBadCertificateCallback = client._badCertificateCallback; |
| 1569 bool callback(X509Certificate certificate) => |
| 1570 currentBadCertificateCallback == null ? false : |
| 1571 currentBadCertificateCallback(certificate, uriHost, uriPort); |
| 1572 Future socketFuture = (isSecure && proxy.isDirect |
| 1573 ? SecureSocket.connect(host, |
| 1574 port, |
| 1575 sendClientCertificate: true, |
| 1576 onBadCertificate: callback) |
| 1577 : Socket.connect(host, port)); |
| 1578 _connecting++; |
| 1579 return socketFuture.then((socket) { |
| 1580 _connecting--; |
| 1581 socket.setOption(SocketOption.TCP_NODELAY, true); |
| 1582 var connection = new _HttpClientConnection(key, socket, client); |
| 1583 if (isSecure && !proxy.isDirect) { |
| 1584 connection._dispose = true; |
| 1585 return connection.createProxyTunnel(uriHost, uriPort, proxy, callback) |
| 1586 .then((tunnel) { |
| 1587 client._getConnectionTarget(uriHost, uriPort, true) |
| 1588 .addNewActive(tunnel); |
| 1589 return new _ConnectionInfo(tunnel, proxy); |
| 1590 }); |
| 1591 } else { |
| 1592 addNewActive(connection); |
| 1593 return new _ConnectionInfo(connection, proxy); |
| 1594 } |
| 1595 }); |
| 1596 } |
1554 } | 1597 } |
1555 | 1598 |
1556 | 1599 |
1557 class _HttpClient implements HttpClient { | 1600 class _HttpClient implements HttpClient { |
1558 bool _closing = false; | 1601 bool _closing = false; |
1559 final Map<String, _ConnectionTarget> _connectionTargets | 1602 final Map<String, _ConnectionTarget> _connectionTargets |
1560 = new HashMap<String, _ConnectionTarget>(); | 1603 = new HashMap<String, _ConnectionTarget>(); |
1561 final List<_Credentials> _credentials = []; | 1604 final List<_Credentials> _credentials = []; |
1562 final List<_ProxyCredentials> _proxyCredentials = []; | 1605 final List<_ProxyCredentials> _proxyCredentials = []; |
1563 Function _authenticate; | 1606 Function _authenticate; |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1769 _closing = false; | 1812 _closing = false; |
1770 } | 1813 } |
1771 }); | 1814 }); |
1772 } | 1815 } |
1773 } else if (_noActiveTimer != null) { | 1816 } else if (_noActiveTimer != null) { |
1774 _noActiveTimer.cancel(); | 1817 _noActiveTimer.cancel(); |
1775 _noActiveTimer = null; | 1818 _noActiveTimer = null; |
1776 } | 1819 } |
1777 } | 1820 } |
1778 | 1821 |
1779 // Get a new _HttpClientConnection, either from the idle pool or created from | 1822 _ConnectionTarget _getConnectionTarget(String host, int port, bool isSecure) { |
1780 // a new Socket. | 1823 String key = _HttpClientConnection.makeKey(isSecure, host, port); |
1781 Future<_ConnnectionInfo> _getConnection(String uriHost, | 1824 return _connectionTargets.putIfAbsent( |
| 1825 key, () => new _ConnectionTarget(key, host, port, isSecure)); |
| 1826 } |
| 1827 |
| 1828 // Get a new _HttpClientConnection, from the matching _ConnectionTarget. |
| 1829 Future<_ConnectionInfo> _getConnection(String uriHost, |
1782 int uriPort, | 1830 int uriPort, |
1783 _ProxyConfiguration proxyConf, | 1831 _ProxyConfiguration proxyConf, |
1784 bool isSecure) { | 1832 bool isSecure) { |
1785 Iterator<_Proxy> proxies = proxyConf.proxies.iterator; | 1833 Iterator<_Proxy> proxies = proxyConf.proxies.iterator; |
1786 | 1834 |
1787 Future<_ConnnectionInfo> connect(error) { | 1835 Future<_ConnectionInfo> connect(error) { |
1788 if (!proxies.moveNext()) return new Future.error(error); | 1836 if (!proxies.moveNext()) return new Future.error(error); |
1789 _Proxy proxy = proxies.current; | 1837 _Proxy proxy = proxies.current; |
1790 String host = proxy.isDirect ? uriHost: proxy.host; | 1838 String host = proxy.isDirect ? uriHost: proxy.host; |
1791 int port = proxy.isDirect ? uriPort: proxy.port; | 1839 int port = proxy.isDirect ? uriPort: proxy.port; |
1792 String key = _HttpClientConnection.makeKey(isSecure, host, port); | 1840 return _getConnectionTarget(host, port, isSecure) |
1793 var connectionTarget = _connectionTargets[key]; | 1841 .connect(uriHost, uriPort, proxy, this) |
1794 if (connectionTarget != null && connectionTarget.hasIdle) { | 1842 // On error, continue with next proxy. |
1795 var connection = connectionTarget.takeIdle(); | 1843 .catchError(connect); |
1796 _updateTimers(); | |
1797 return new Future.value(new _ConnnectionInfo(connection, proxy)); | |
1798 } | |
1799 var currentBadCertificateCallback = _badCertificateCallback; | |
1800 bool callback(X509Certificate certificate) => | |
1801 currentBadCertificateCallback == null ? false : | |
1802 currentBadCertificateCallback(certificate, uriHost, uriPort); | |
1803 Future socketFuture = (isSecure && proxy.isDirect | |
1804 ? SecureSocket.connect(host, | |
1805 port, | |
1806 sendClientCertificate: true, | |
1807 onBadCertificate: callback) | |
1808 : Socket.connect(host, port)); | |
1809 return socketFuture.then((socket) { | |
1810 socket.setOption(SocketOption.TCP_NODELAY, true); | |
1811 var connection = new _HttpClientConnection(key, socket, this); | |
1812 if (isSecure && !proxy.isDirect) { | |
1813 connection._dispose = true; | |
1814 return connection.createProxyTunnel( | |
1815 uriHost, uriPort, proxy, callback) | |
1816 .then((tunnel) { | |
1817 var connectionTarget = _connectionTargets | |
1818 .putIfAbsent(tunnel.key, | |
1819 () => new _ConnectionTarget(tunnel.key)); | |
1820 connectionTarget.addNewActive(tunnel); | |
1821 return new _ConnnectionInfo(tunnel, proxy); | |
1822 }); | |
1823 } else { | |
1824 var connectionTarget = _connectionTargets | |
1825 .putIfAbsent(key, () => new _ConnectionTarget(key)); | |
1826 connectionTarget.addNewActive(connection); | |
1827 return new _ConnnectionInfo(connection, proxy); | |
1828 } | |
1829 }, onError: (error) { | |
1830 // Continue with next proxy. | |
1831 return connect(error); | |
1832 }); | |
1833 } | 1844 } |
1834 return connect(new HttpException("No proxies given")); | 1845 return connect(new HttpException("No proxies given")); |
1835 } | 1846 } |
1836 | 1847 |
1837 _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { | 1848 _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { |
1838 // Look for credentials. | 1849 // Look for credentials. |
1839 _SiteCredentials cr = | 1850 _SiteCredentials cr = |
1840 _credentials.fold(null, (prev, value) { | 1851 _credentials.fold(null, (prev, value) { |
1841 if (value.applies(url, scheme)) { | 1852 if (value.applies(url, scheme)) { |
1842 if (prev == null) return value; | 1853 if (prev == null) return value; |
(...skipping 862 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2705 const _RedirectInfo(this.statusCode, this.method, this.location); | 2716 const _RedirectInfo(this.statusCode, this.method, this.location); |
2706 } | 2717 } |
2707 | 2718 |
2708 String _getHttpVersion() { | 2719 String _getHttpVersion() { |
2709 var version = Platform.version; | 2720 var version = Platform.version; |
2710 // Only include major and minor version numbers. | 2721 // Only include major and minor version numbers. |
2711 int index = version.indexOf('.', version.indexOf('.') + 1); | 2722 int index = version.indexOf('.', version.indexOf('.') + 1); |
2712 version = version.substring(0, index); | 2723 version = version.substring(0, index); |
2713 return 'Dart/$version (dart:io)'; | 2724 return 'Dart/$version (dart:io)'; |
2714 } | 2725 } |
OLD | NEW |