Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: sdk/lib/io/http_impl.dart

Issue 280813003: Merge _idleConnections and _activeConnections into one structure, _ConnectionTarget. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 1484 matching lines...) Expand 10 before | Expand all | Expand 10 after
1495 } 1495 }
1496 1496
1497 class _ConnnectionInfo { 1497 class _ConnnectionInfo {
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 _ConnnectionInfo(this.connection, this.proxy);
1502 } 1502 }
1503 1503
1504 1504
1505 class _ConnectionTarget {
1506 // Unique key for this connection target.
1507 final String key;
1508 final Set<_HttpClientConnection> _idle = new HashSet();
1509 final Set<_HttpClientConnection> _active = new HashSet();
1510
1511 _ConnectionTarget(this.key);
1512
1513 bool get isEmpty => _idle.isEmpty && _active.isEmpty;
1514
1515 bool get hasIdle => _idle.isNotEmpty;
1516
1517 bool get hasActive => _active.isNotEmpty;
1518
1519 _HttpClientConnection takeIdle() {
1520 assert(hasIdle);
1521 _HttpClientConnection connection = _idle.first;
1522 _idle.remove(connection);
1523 connection.stopTimer();
1524 _active.add(connection);
1525 return connection;
1526 }
1527
1528 void addNewActive(_HttpClientConnection connection) {
1529 _active.add(connection);
1530 }
1531
1532 void returnConnection(_HttpClientConnection connection) {
1533 assert(_active.contains(connection));
1534 _active.remove(connection);
1535 _idle.add(connection);
1536 }
1537
1538 void connectionClosed(_HttpClientConnection connection) {
1539 assert(!_active.contains(connection) || !_idle.contains(connection));
1540 _active.remove(connection);
1541 _idle.remove(connection);
1542 }
1543
1544 void close(bool force) {
1545 for (var c in _idle.toList()) {
1546 c.close();
1547 }
1548 if (force) {
1549 for (var c in _active.toList()) {
1550 c.destroy();
1551 }
1552 }
1553 }
1554 }
1555
1556
1505 class _HttpClient implements HttpClient { 1557 class _HttpClient implements HttpClient {
1506 bool _closing = false; 1558 bool _closing = false;
1507 final Map<String, Set<_HttpClientConnection>> _idleConnections 1559 final Map<String, _ConnectionTarget> _connectionTargets
1508 = new HashMap<String, Set<_HttpClientConnection>>(); 1560 = new HashMap<String, _ConnectionTarget>();
1509 final Map<String, Set<_HttpClientConnection>> _activeConnections
1510 = new HashMap<String, Set<_HttpClientConnection>>();
1511 final List<_Credentials> _credentials = []; 1561 final List<_Credentials> _credentials = [];
1512 final List<_ProxyCredentials> _proxyCredentials = []; 1562 final List<_ProxyCredentials> _proxyCredentials = [];
1513 Function _authenticate; 1563 Function _authenticate;
1514 Function _authenticateProxy; 1564 Function _authenticateProxy;
1515 Function _findProxy = HttpClient.findProxyFromEnvironment; 1565 Function _findProxy = HttpClient.findProxyFromEnvironment;
1516 Duration _idleTimeout = const Duration(seconds: 15); 1566 Duration _idleTimeout = const Duration(seconds: 15);
1517 Function _badCertificateCallback; 1567 Function _badCertificateCallback;
1518 1568
1519 Timer _noActiveTimer; 1569 Timer _noActiveTimer;
1520 1570
1521 Duration get idleTimeout => _idleTimeout; 1571 Duration get idleTimeout => _idleTimeout;
1522 1572
1523 String userAgent = _getHttpVersion(); 1573 String userAgent = _getHttpVersion();
1524 1574
1525 void set idleTimeout(Duration timeout) { 1575 void set idleTimeout(Duration timeout) {
1526 _idleTimeout = timeout; 1576 _idleTimeout = timeout;
1527 _idleConnections.values.forEach( 1577 for (var c in _connectionTargets.values) {
1528 (l) => l.forEach((c) { 1578 for (var idle in c.idle) {
1529 // Reset timer. This is fine, as it's not happening often. 1579 // Reset timer. This is fine, as it's not happening often.
1530 c.stopTimer(); 1580 idle.stopTimer();
1531 c.startTimer(); 1581 idle.startTimer();
1532 })); 1582 }
1583 }
1533 } 1584 }
1534 1585
1535 set badCertificateCallback(bool callback(X509Certificate cert, 1586 set badCertificateCallback(bool callback(X509Certificate cert,
1536 String host, 1587 String host,
1537 int port)) { 1588 int port)) {
1538 _badCertificateCallback = callback; 1589 _badCertificateCallback = callback;
1539 } 1590 }
1540 1591
1541 1592
1542 Future<HttpClientRequest> open(String method, 1593 Future<HttpClientRequest> open(String method,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1578 1629
1579 Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url); 1630 Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url);
1580 1631
1581 Future<HttpClientRequest> patch(String host, int port, String path) 1632 Future<HttpClientRequest> patch(String host, int port, String path)
1582 => open("patch", host, port, path); 1633 => open("patch", host, port, path);
1583 1634
1584 Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url); 1635 Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url);
1585 1636
1586 void close({bool force: false}) { 1637 void close({bool force: false}) {
1587 _closing = true; 1638 _closing = true;
1588 // Create flattened copy of _idleConnections, as 'destory' will manipulate 1639 _connectionTargets.values.toList().forEach((c) => c.close(force));
1589 // it. 1640 assert(!_connectionTargets.values.any((s) => s.hasIdle));
1590 var idle = _idleConnections.values.fold( 1641 assert(!force || _connectionTargets.isEmpty);
1591 [],
1592 (l, e) {
1593 l.addAll(e);
1594 return l;
1595 });
1596 idle.forEach((e) {
1597 e.close();
1598 });
1599 assert(_idleConnections.isEmpty);
1600 if (force) {
1601 for (var connection in
1602 _activeConnections.values.expand((s) => s).toList()) {
1603 connection.destroy();
1604 }
1605 assert(_activeConnections.isEmpty);
1606 _activeConnections.clear();
1607 }
1608 } 1642 }
1609 1643
1610 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { 1644 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
1611 _authenticate = f; 1645 _authenticate = f;
1612 } 1646 }
1613 1647
1614 void addCredentials(Uri url, String realm, HttpClientCredentials cr) => 1648 void addCredentials(Uri url, String realm, HttpClientCredentials cr) =>
1615 _credentials.add(new _SiteCredentials(url, realm, cr)); 1649 _credentials.add(new _SiteCredentials(url, realm, cr));
1616 1650
1617 set authenticateProxy( 1651 set authenticateProxy(
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1696 } 1730 }
1697 } 1731 }
1698 return request 1732 return request
1699 ..headers.chunkedTransferEncoding = false 1733 ..headers.chunkedTransferEncoding = false
1700 ..contentLength = 0; 1734 ..contentLength = 0;
1701 }); 1735 });
1702 } 1736 }
1703 1737
1704 // Return a live connection to the idle pool. 1738 // Return a live connection to the idle pool.
1705 void _returnConnection(_HttpClientConnection connection) { 1739 void _returnConnection(_HttpClientConnection connection) {
1706 var key = connection.key; 1740 _connectionTargets[connection.key].returnConnection(connection);
1707 _activeConnections[key].remove(connection);
1708 if (_activeConnections[key].isEmpty) {
1709 _activeConnections.remove(key);
1710 }
1711 if (_closing) {
1712 connection.close();
1713 return;
1714 }
1715 _idleConnections
1716 .putIfAbsent(key, () => new HashSet())
1717 .add(connection);
1718 connection.startTimer(); 1741 connection.startTimer();
1719 _updateTimers(); 1742 _updateTimers();
1720 } 1743 }
1721 1744
1722 // Remove a closed connnection from the active set. 1745 // Remove a closed connnection from the active set.
1723 void _connectionClosed(_HttpClientConnection connection) { 1746 void _connectionClosed(_HttpClientConnection connection) {
1724 connection.stopTimer(); 1747 connection.stopTimer();
1725 var key = connection.key; 1748 var connectionTarget = _connectionTargets[connection.key];
1726 if (_activeConnections.containsKey(key)) { 1749 if (connectionTarget != null) {
1727 _activeConnections[key].remove(connection); 1750 connectionTarget.connectionClosed(connection);
1728 if (_activeConnections[key].isEmpty) { 1751 if (connectionTarget.isEmpty) {
1729 _activeConnections.remove(key); 1752 _connectionTargets.remove(connection.key);
1730 } 1753 }
1754 _updateTimers();
1731 } 1755 }
1732 if (_idleConnections.containsKey(key)) {
1733 _idleConnections[key].remove(connection);
1734 if (_idleConnections[key].isEmpty) {
1735 _idleConnections.remove(key);
1736 }
1737 }
1738 _updateTimers();
1739 } 1756 }
1740 1757
1741 void _updateTimers() { 1758 void _updateTimers() {
1742 if (_activeConnections.isEmpty) { 1759 bool hasActive = _connectionTargets.values.any((t) => t.hasActive);
Søren Gjesse 2014/05/23 09:49:11 We could consider abstracting the _connectionTarge
1743 if (!_idleConnections.isEmpty && _noActiveTimer == null) { 1760 if (!hasActive) {
1761 bool hasIdle = _connectionTargets.values.any((t) => t.hasIdle);
1762 if (hasIdle && _noActiveTimer == null) {
1744 _noActiveTimer = new Timer(const Duration(milliseconds: 100), () { 1763 _noActiveTimer = new Timer(const Duration(milliseconds: 100), () {
1745 _noActiveTimer = null; 1764 _noActiveTimer = null;
1746 if (_activeConnections.isEmpty) { 1765 bool hasActive =
1766 _connectionTargets.values.any((t) => t.hasActive);
1767 if (!hasActive) {
1747 close(); 1768 close();
1748 _closing = false; 1769 _closing = false;
1749 } 1770 }
1750 }); 1771 });
1751 } 1772 }
1752 } else if (_noActiveTimer != null) { 1773 } else if (_noActiveTimer != null) {
1753 _noActiveTimer.cancel(); 1774 _noActiveTimer.cancel();
1754 _noActiveTimer = null; 1775 _noActiveTimer = null;
1755 } 1776 }
1756 } 1777 }
1757 1778
1758 // Get a new _HttpClientConnection, either from the idle pool or created from 1779 // Get a new _HttpClientConnection, either from the idle pool or created from
1759 // a new Socket. 1780 // a new Socket.
1760 Future<_ConnnectionInfo> _getConnection(String uriHost, 1781 Future<_ConnnectionInfo> _getConnection(String uriHost,
1761 int uriPort, 1782 int uriPort,
1762 _ProxyConfiguration proxyConf, 1783 _ProxyConfiguration proxyConf,
1763 bool isSecure) { 1784 bool isSecure) {
1764 Iterator<_Proxy> proxies = proxyConf.proxies.iterator; 1785 Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
1765 1786
1766 Future<_ConnnectionInfo> connect(error) { 1787 Future<_ConnnectionInfo> connect(error) {
1767 if (!proxies.moveNext()) return new Future.error(error); 1788 if (!proxies.moveNext()) return new Future.error(error);
1768 _Proxy proxy = proxies.current; 1789 _Proxy proxy = proxies.current;
1769 String host = proxy.isDirect ? uriHost: proxy.host; 1790 String host = proxy.isDirect ? uriHost: proxy.host;
1770 int port = proxy.isDirect ? uriPort: proxy.port; 1791 int port = proxy.isDirect ? uriPort: proxy.port;
1771 String key = _HttpClientConnection.makeKey(isSecure, host, port); 1792 String key = _HttpClientConnection.makeKey(isSecure, host, port);
1772 if (_idleConnections.containsKey(key)) { 1793 var connectionTarget = _connectionTargets[key];
1773 var connection = _idleConnections[key].first; 1794 if (connectionTarget != null && connectionTarget.hasIdle) {
1774 _idleConnections[key].remove(connection); 1795 var connection = connectionTarget.takeIdle();
1775 if (_idleConnections[key].isEmpty) {
1776 _idleConnections.remove(key);
1777 }
1778 connection.stopTimer();
1779 _activeConnections
1780 .putIfAbsent(key, () => new HashSet())
1781 .add(connection);
1782 _updateTimers(); 1796 _updateTimers();
1783 return new Future.value(new _ConnnectionInfo(connection, proxy)); 1797 return new Future.value(new _ConnnectionInfo(connection, proxy));
1784 } 1798 }
1785 var currentBadCertificateCallback = _badCertificateCallback; 1799 var currentBadCertificateCallback = _badCertificateCallback;
1786 bool callback(X509Certificate certificate) => 1800 bool callback(X509Certificate certificate) =>
1787 currentBadCertificateCallback == null ? false : 1801 currentBadCertificateCallback == null ? false :
1788 currentBadCertificateCallback(certificate, uriHost, uriPort); 1802 currentBadCertificateCallback(certificate, uriHost, uriPort);
1789 Future socketFuture = (isSecure && proxy.isDirect 1803 Future socketFuture = (isSecure && proxy.isDirect
1790 ? SecureSocket.connect(host, 1804 ? SecureSocket.connect(host,
1791 port, 1805 port,
1792 sendClientCertificate: true, 1806 sendClientCertificate: true,
1793 onBadCertificate: callback) 1807 onBadCertificate: callback)
1794 : Socket.connect(host, port)); 1808 : Socket.connect(host, port));
1795 return socketFuture.then((socket) { 1809 return socketFuture.then((socket) {
1796 socket.setOption(SocketOption.TCP_NODELAY, true); 1810 socket.setOption(SocketOption.TCP_NODELAY, true);
1797 var connection = new _HttpClientConnection(key, socket, this); 1811 var connection = new _HttpClientConnection(key, socket, this);
1798 if (isSecure && !proxy.isDirect) { 1812 if (isSecure && !proxy.isDirect) {
1799 connection._dispose = true; 1813 connection._dispose = true;
1800 return connection.createProxyTunnel( 1814 return connection.createProxyTunnel(
1801 uriHost, uriPort, proxy, callback) 1815 uriHost, uriPort, proxy, callback)
1802 .then((tunnel) { 1816 .then((tunnel) {
1803 _activeConnections 1817 var connectionTarget = _connectionTargets
1804 .putIfAbsent(tunnel.key, () => new HashSet()) 1818 .putIfAbsent(tunnel.key,
1805 .add(tunnel); 1819 () => new _ConnectionTarget(tunnel.key));
1820 connectionTarget.addNewActive(tunnel);
1806 return new _ConnnectionInfo(tunnel, proxy); 1821 return new _ConnnectionInfo(tunnel, proxy);
1807 }); 1822 });
1808 } else { 1823 } else {
1809 _activeConnections 1824 var connectionTarget = _connectionTargets
1810 .putIfAbsent(key, () => new HashSet()) 1825 .putIfAbsent(key, () => new _ConnectionTarget(key));
1811 .add(connection); 1826 connectionTarget.addNewActive(connection);
1812 return new _ConnnectionInfo(connection, proxy); 1827 return new _ConnnectionInfo(connection, proxy);
1813 } 1828 }
1814 }, onError: (error) { 1829 }, onError: (error) {
1815 // Continue with next proxy. 1830 // Continue with next proxy.
1816 return connect(error); 1831 return connect(error);
1817 }); 1832 });
1818 } 1833 }
1819 return connect(new HttpException("No proxies given")); 1834 return connect(new HttpException("No proxies given"));
1820 } 1835 }
1821 1836
(...skipping 843 matching lines...) Expand 10 before | Expand all | Expand 10 after
2665 const _RedirectInfo(this.statusCode, this.method, this.location); 2680 const _RedirectInfo(this.statusCode, this.method, this.location);
2666 } 2681 }
2667 2682
2668 String _getHttpVersion() { 2683 String _getHttpVersion() {
2669 var version = Platform.version; 2684 var version = Platform.version;
2670 // Only include major and minor version numbers. 2685 // Only include major and minor version numbers.
2671 int index = version.indexOf('.', version.indexOf('.') + 1); 2686 int index = version.indexOf('.', version.indexOf('.') + 1);
2672 version = version.substring(0, index); 2687 version = version.substring(0, index);
2673 return 'Dart/$version (dart:io)'; 2688 return 'Dart/$version (dart:io)';
2674 } 2689 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698