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 1504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1515 | 1515 |
1516 | 1516 |
1517 class _ConnectionTarget { | 1517 class _ConnectionTarget { |
1518 // Unique key for this connection target. | 1518 // Unique key for this connection target. |
1519 final String key; | 1519 final String key; |
1520 final String host; | 1520 final String host; |
1521 final int port; | 1521 final int port; |
1522 final bool isSecure; | 1522 final bool isSecure; |
1523 final Set<_HttpClientConnection> _idle = new HashSet(); | 1523 final Set<_HttpClientConnection> _idle = new HashSet(); |
1524 final Set<_HttpClientConnection> _active = new HashSet(); | 1524 final Set<_HttpClientConnection> _active = new HashSet(); |
| 1525 final Queue _pending = new ListQueue(); |
1525 int _connecting = 0; | 1526 int _connecting = 0; |
1526 | 1527 |
1527 _ConnectionTarget(this.key, this.host, this.port, this.isSecure); | 1528 _ConnectionTarget(this.key, this.host, this.port, this.isSecure); |
1528 | 1529 |
1529 bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0; | 1530 bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0; |
1530 | 1531 |
1531 bool get hasIdle => _idle.isNotEmpty; | 1532 bool get hasIdle => _idle.isNotEmpty; |
1532 | 1533 |
1533 bool get hasActive => _active.isNotEmpty && _connecting > 0; | 1534 bool get hasActive => _active.isNotEmpty || _connecting > 0; |
1534 | 1535 |
1535 _HttpClientConnection takeIdle() { | 1536 _HttpClientConnection takeIdle() { |
1536 assert(hasIdle); | 1537 assert(hasIdle); |
1537 _HttpClientConnection connection = _idle.first; | 1538 _HttpClientConnection connection = _idle.first; |
1538 _idle.remove(connection); | 1539 _idle.remove(connection); |
1539 connection.stopTimer(); | 1540 connection.stopTimer(); |
1540 _active.add(connection); | 1541 _active.add(connection); |
1541 return connection; | 1542 return connection; |
1542 } | 1543 } |
1543 | 1544 |
| 1545 _checkPending() { |
| 1546 if (_pending.isNotEmpty) { |
| 1547 _pending.removeFirst()(); |
| 1548 } |
| 1549 } |
| 1550 |
1544 void addNewActive(_HttpClientConnection connection) { | 1551 void addNewActive(_HttpClientConnection connection) { |
1545 _active.add(connection); | 1552 _active.add(connection); |
1546 } | 1553 } |
1547 | 1554 |
1548 void returnConnection(_HttpClientConnection connection) { | 1555 void returnConnection(_HttpClientConnection connection) { |
1549 assert(_active.contains(connection)); | 1556 assert(_active.contains(connection)); |
1550 _active.remove(connection); | 1557 _active.remove(connection); |
1551 _idle.add(connection); | 1558 _idle.add(connection); |
| 1559 connection.startTimer(); |
| 1560 _checkPending(); |
1552 } | 1561 } |
1553 | 1562 |
1554 void connectionClosed(_HttpClientConnection connection) { | 1563 void connectionClosed(_HttpClientConnection connection) { |
1555 assert(!_active.contains(connection) || !_idle.contains(connection)); | 1564 assert(!_active.contains(connection) || !_idle.contains(connection)); |
1556 _active.remove(connection); | 1565 _active.remove(connection); |
1557 _idle.remove(connection); | 1566 _idle.remove(connection); |
| 1567 _checkPending(); |
1558 } | 1568 } |
1559 | 1569 |
1560 void close(bool force) { | 1570 void close(bool force) { |
1561 for (var c in _idle.toList()) { | 1571 for (var c in _idle.toList()) { |
1562 c.close(); | 1572 c.close(); |
1563 } | 1573 } |
1564 if (force) { | 1574 if (force) { |
1565 for (var c in _active.toList()) { | 1575 for (var c in _active.toList()) { |
1566 c.destroy(); | 1576 c.destroy(); |
1567 } | 1577 } |
1568 } | 1578 } |
1569 } | 1579 } |
1570 | 1580 |
1571 Future<_ConnectionInfo> connect(String uriHost, | 1581 Future<_ConnectionInfo> connect(String uriHost, |
1572 int uriPort, | 1582 int uriPort, |
1573 _Proxy proxy, | 1583 _Proxy proxy, |
1574 _HttpClient client) { | 1584 _HttpClient client) { |
1575 if (hasIdle) { | 1585 if (hasIdle) { |
1576 var connection = takeIdle(); | 1586 var connection = takeIdle(); |
1577 client._updateTimers(); | 1587 client._updateTimers(); |
1578 return new Future.value(new _ConnectionInfo(connection, proxy)); | 1588 return new Future.value(new _ConnectionInfo(connection, proxy)); |
1579 } | 1589 } |
| 1590 if (client.maxConnectionsPerHost != null && |
| 1591 _active.length + _connecting >= client.maxConnectionsPerHost) { |
| 1592 var completer = new Completer(); |
| 1593 _pending.add(() { |
| 1594 connect(uriHost, uriPort, proxy, client) |
| 1595 .then(completer.complete, onError: completer.completeError); |
| 1596 }); |
| 1597 return completer.future; |
| 1598 } |
1580 var currentBadCertificateCallback = client._badCertificateCallback; | 1599 var currentBadCertificateCallback = client._badCertificateCallback; |
1581 bool callback(X509Certificate certificate) => | 1600 bool callback(X509Certificate certificate) => |
1582 currentBadCertificateCallback == null ? false : | 1601 currentBadCertificateCallback == null ? false : |
1583 currentBadCertificateCallback(certificate, uriHost, uriPort); | 1602 currentBadCertificateCallback(certificate, uriHost, uriPort); |
1584 Future socketFuture = (isSecure && proxy.isDirect | 1603 Future socketFuture = (isSecure && proxy.isDirect |
1585 ? SecureSocket.connect(host, | 1604 ? SecureSocket.connect(host, |
1586 port, | 1605 port, |
1587 sendClientCertificate: true, | 1606 sendClientCertificate: true, |
1588 onBadCertificate: callback) | 1607 onBadCertificate: callback) |
1589 : Socket.connect(host, port)); | 1608 : Socket.connect(host, port)); |
1590 _connecting++; | 1609 _connecting++; |
1591 return socketFuture.then((socket) { | 1610 return socketFuture.then((socket) { |
1592 _connecting--; | 1611 _connecting--; |
1593 socket.setOption(SocketOption.TCP_NODELAY, true); | 1612 socket.setOption(SocketOption.TCP_NODELAY, true); |
1594 var connection = new _HttpClientConnection(key, socket, client); | 1613 var connection = new _HttpClientConnection(key, socket, client); |
1595 if (isSecure && !proxy.isDirect) { | 1614 if (isSecure && !proxy.isDirect) { |
1596 connection._dispose = true; | 1615 connection._dispose = true; |
1597 return connection.createProxyTunnel(uriHost, uriPort, proxy, callback) | 1616 return connection.createProxyTunnel(uriHost, uriPort, proxy, callback) |
1598 .then((tunnel) { | 1617 .then((tunnel) { |
1599 client._getConnectionTarget(uriHost, uriPort, true) | 1618 client._getConnectionTarget(uriHost, uriPort, true) |
1600 .addNewActive(tunnel); | 1619 .addNewActive(tunnel); |
1601 return new _ConnectionInfo(tunnel, proxy); | 1620 return new _ConnectionInfo(tunnel, proxy); |
1602 }); | 1621 }); |
1603 } else { | 1622 } else { |
1604 addNewActive(connection); | 1623 addNewActive(connection); |
1605 return new _ConnectionInfo(connection, proxy); | 1624 return new _ConnectionInfo(connection, proxy); |
1606 } | 1625 } |
| 1626 }, onError: (error) { |
| 1627 _connecting--; |
| 1628 _checkPending(); |
| 1629 throw error; |
1607 }); | 1630 }); |
1608 } | 1631 } |
1609 } | 1632 } |
1610 | 1633 |
1611 | 1634 |
1612 class _HttpClient implements HttpClient { | 1635 class _HttpClient implements HttpClient { |
1613 bool _closing = false; | 1636 bool _closing = false; |
1614 final Map<String, _ConnectionTarget> _connectionTargets | 1637 final Map<String, _ConnectionTarget> _connectionTargets |
1615 = new HashMap<String, _ConnectionTarget>(); | 1638 = new HashMap<String, _ConnectionTarget>(); |
1616 final List<_Credentials> _credentials = []; | 1639 final List<_Credentials> _credentials = []; |
1617 final List<_ProxyCredentials> _proxyCredentials = []; | 1640 final List<_ProxyCredentials> _proxyCredentials = []; |
1618 Function _authenticate; | 1641 Function _authenticate; |
1619 Function _authenticateProxy; | 1642 Function _authenticateProxy; |
1620 Function _findProxy = HttpClient.findProxyFromEnvironment; | 1643 Function _findProxy = HttpClient.findProxyFromEnvironment; |
1621 Duration _idleTimeout = const Duration(seconds: 15); | 1644 Duration _idleTimeout = const Duration(seconds: 15); |
1622 Function _badCertificateCallback; | 1645 Function _badCertificateCallback; |
1623 | 1646 |
1624 Timer _noActiveTimer; | 1647 Timer _noActiveTimer; |
1625 | 1648 |
1626 Duration get idleTimeout => _idleTimeout; | 1649 Duration get idleTimeout => _idleTimeout; |
1627 | 1650 |
| 1651 int maxConnectionsPerHost; |
| 1652 |
1628 String userAgent = _getHttpVersion(); | 1653 String userAgent = _getHttpVersion(); |
1629 | 1654 |
1630 void set idleTimeout(Duration timeout) { | 1655 void set idleTimeout(Duration timeout) { |
1631 _idleTimeout = timeout; | 1656 _idleTimeout = timeout; |
1632 for (var c in _connectionTargets.values) { | 1657 for (var c in _connectionTargets.values) { |
1633 for (var idle in c.idle) { | 1658 for (var idle in c.idle) { |
1634 // Reset timer. This is fine, as it's not happening often. | 1659 // Reset timer. This is fine, as it's not happening often. |
1635 idle.stopTimer(); | 1660 idle.stopTimer(); |
1636 idle.startTimer(); | 1661 idle.startTimer(); |
1637 } | 1662 } |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1787 } | 1812 } |
1788 return request | 1813 return request |
1789 ..headers.chunkedTransferEncoding = false | 1814 ..headers.chunkedTransferEncoding = false |
1790 ..contentLength = 0; | 1815 ..contentLength = 0; |
1791 }); | 1816 }); |
1792 } | 1817 } |
1793 | 1818 |
1794 // Return a live connection to the idle pool. | 1819 // Return a live connection to the idle pool. |
1795 void _returnConnection(_HttpClientConnection connection) { | 1820 void _returnConnection(_HttpClientConnection connection) { |
1796 _connectionTargets[connection.key].returnConnection(connection); | 1821 _connectionTargets[connection.key].returnConnection(connection); |
1797 connection.startTimer(); | |
1798 _updateTimers(); | 1822 _updateTimers(); |
1799 } | 1823 } |
1800 | 1824 |
1801 // Remove a closed connnection from the active set. | 1825 // Remove a closed connnection from the active set. |
1802 void _connectionClosed(_HttpClientConnection connection) { | 1826 void _connectionClosed(_HttpClientConnection connection) { |
1803 connection.stopTimer(); | 1827 connection.stopTimer(); |
1804 var connectionTarget = _connectionTargets[connection.key]; | 1828 var connectionTarget = _connectionTargets[connection.key]; |
1805 if (connectionTarget != null) { | 1829 if (connectionTarget != null) { |
1806 connectionTarget.connectionClosed(connection); | 1830 connectionTarget.connectionClosed(connection); |
1807 if (connectionTarget.isEmpty) { | 1831 if (connectionTarget.isEmpty) { |
(...skipping 921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2729 const _RedirectInfo(this.statusCode, this.method, this.location); | 2753 const _RedirectInfo(this.statusCode, this.method, this.location); |
2730 } | 2754 } |
2731 | 2755 |
2732 String _getHttpVersion() { | 2756 String _getHttpVersion() { |
2733 var version = Platform.version; | 2757 var version = Platform.version; |
2734 // Only include major and minor version numbers. | 2758 // Only include major and minor version numbers. |
2735 int index = version.indexOf('.', version.indexOf('.') + 1); | 2759 int index = version.indexOf('.', version.indexOf('.') + 1); |
2736 version = version.substring(0, index); | 2760 version = version.substring(0, index); |
2737 return 'Dart/$version (dart:io)'; | 2761 return 'Dart/$version (dart:io)'; |
2738 } | 2762 } |
OLD | NEW |