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