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

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

Issue 486853005: Fix idle connection pool issue in dart:io's HttpClient (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fixed existing tests, removed bogus test, use async_helper for new test Created 6 years, 3 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 | dart/tests/standalone/io/http_client_stays_alive_test.dart » ('j') | 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 1567 matching lines...) Expand 10 before | Expand all | Expand 10 after
1578 c.close(); 1578 c.close();
1579 } 1579 }
1580 if (force) { 1580 if (force) {
1581 for (var c in _active.toList()) { 1581 for (var c in _active.toList()) {
1582 c.destroy(); 1582 c.destroy();
1583 } 1583 }
1584 } 1584 }
1585 } 1585 }
1586 1586
1587 Future<_ConnectionInfo> connect(String uriHost, 1587 Future<_ConnectionInfo> connect(String uriHost,
1588 int uriPort, 1588 int uriPort,
1589 _Proxy proxy, 1589 _Proxy proxy,
1590 _HttpClient client) { 1590 _HttpClient client) {
1591 if (hasIdle) { 1591 if (hasIdle) {
1592 var connection = takeIdle(); 1592 var connection = takeIdle();
1593 client._updateTimers(); 1593 client._connectionsChanged();
1594 return new Future.value(new _ConnectionInfo(connection, proxy)); 1594 return new Future.value(new _ConnectionInfo(connection, proxy));
1595 } 1595 }
1596 if (client.maxConnectionsPerHost != null && 1596 if (client.maxConnectionsPerHost != null &&
1597 _active.length + _connecting >= client.maxConnectionsPerHost) { 1597 _active.length + _connecting >= client.maxConnectionsPerHost) {
1598 var completer = new Completer(); 1598 var completer = new Completer();
1599 _pending.add(() { 1599 _pending.add(() {
1600 connect(uriHost, uriPort, proxy, client) 1600 connect(uriHost, uriPort, proxy, client)
1601 .then(completer.complete, onError: completer.completeError); 1601 .then(completer.complete, onError: completer.completeError);
1602 }); 1602 });
1603 return completer.future; 1603 return completer.future;
(...skipping 29 matching lines...) Expand all
1633 _connecting--; 1633 _connecting--;
1634 _checkPending(); 1634 _checkPending();
1635 throw error; 1635 throw error;
1636 }); 1636 });
1637 } 1637 }
1638 } 1638 }
1639 1639
1640 1640
1641 class _HttpClient implements HttpClient { 1641 class _HttpClient implements HttpClient {
1642 bool _closing = false; 1642 bool _closing = false;
1643 bool _closingForcefully = false;
1643 final Map<String, _ConnectionTarget> _connectionTargets 1644 final Map<String, _ConnectionTarget> _connectionTargets
1644 = new HashMap<String, _ConnectionTarget>(); 1645 = new HashMap<String, _ConnectionTarget>();
1645 final List<_Credentials> _credentials = []; 1646 final List<_Credentials> _credentials = [];
1646 final List<_ProxyCredentials> _proxyCredentials = []; 1647 final List<_ProxyCredentials> _proxyCredentials = [];
1647 Function _authenticate; 1648 Function _authenticate;
1648 Function _authenticateProxy; 1649 Function _authenticateProxy;
1649 Function _findProxy = HttpClient.findProxyFromEnvironment; 1650 Function _findProxy = HttpClient.findProxyFromEnvironment;
1650 Duration _idleTimeout = const Duration(seconds: 15); 1651 Duration _idleTimeout = const Duration(seconds: 15);
1651 Function _badCertificateCallback; 1652 Function _badCertificateCallback;
1652 1653
1653 Timer _noActiveTimer;
1654
1655 Duration get idleTimeout => _idleTimeout; 1654 Duration get idleTimeout => _idleTimeout;
1656 1655
1657 int maxConnectionsPerHost; 1656 int maxConnectionsPerHost;
1658 1657
1659 bool autoUncompress = true; 1658 bool autoUncompress = true;
1660 1659
1661 String userAgent = _getHttpVersion(); 1660 String userAgent = _getHttpVersion();
1662 1661
1663 void set idleTimeout(Duration timeout) { 1662 void set idleTimeout(Duration timeout) {
1664 _idleTimeout = timeout; 1663 _idleTimeout = timeout;
1665 for (var c in _connectionTargets.values) { 1664 for (var c in _connectionTargets.values) {
1666 for (var idle in c.idle) { 1665 for (var idle in c._idle) {
1667 // Reset timer. This is fine, as it's not happening often. 1666 // Reset timer. This is fine, as it's not happening often.
1668 idle.stopTimer(); 1667 idle.stopTimer();
1669 idle.startTimer(); 1668 idle.startTimer();
1670 } 1669 }
1671 } 1670 }
1672 } 1671 }
1673 1672
1674 set badCertificateCallback(bool callback(X509Certificate cert, 1673 set badCertificateCallback(bool callback(X509Certificate cert,
1675 String host, 1674 String host,
1676 int port)) { 1675 int port)) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1717 1716
1718 Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url); 1717 Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url);
1719 1718
1720 Future<HttpClientRequest> patch(String host, int port, String path) 1719 Future<HttpClientRequest> patch(String host, int port, String path)
1721 => open("patch", host, port, path); 1720 => open("patch", host, port, path);
1722 1721
1723 Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url); 1722 Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url);
1724 1723
1725 void close({bool force: false}) { 1724 void close({bool force: false}) {
1726 _closing = true; 1725 _closing = true;
1727 _connectionTargets.values.toList().forEach((c) => c.close(force)); 1726 _closingForcefully = force;
1727 _closeConnections(_closingForcefully);
1728 assert(!_connectionTargets.values.any((s) => s.hasIdle)); 1728 assert(!_connectionTargets.values.any((s) => s.hasIdle));
1729 assert(!force || 1729 assert(!force ||
1730 !_connectionTargets.values.any((s) => s._active.isNotEmpty)); 1730 !_connectionTargets.values.any((s) => s._active.isNotEmpty));
1731 } 1731 }
1732 1732
1733 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { 1733 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
1734 _authenticate = f; 1734 _authenticate = f;
1735 } 1735 }
1736 1736
1737 void addCredentials(Uri url, String realm, HttpClientCredentials cr) => 1737 void addCredentials(Uri url, String realm, HttpClientCredentials cr) =>
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1820 } 1820 }
1821 return request 1821 return request
1822 ..headers.chunkedTransferEncoding = false 1822 ..headers.chunkedTransferEncoding = false
1823 ..contentLength = 0; 1823 ..contentLength = 0;
1824 }); 1824 });
1825 } 1825 }
1826 1826
1827 // Return a live connection to the idle pool. 1827 // Return a live connection to the idle pool.
1828 void _returnConnection(_HttpClientConnection connection) { 1828 void _returnConnection(_HttpClientConnection connection) {
1829 _connectionTargets[connection.key].returnConnection(connection); 1829 _connectionTargets[connection.key].returnConnection(connection);
1830 _updateTimers(); 1830 _connectionsChanged();
1831 } 1831 }
1832 1832
1833 // Remove a closed connnection from the active set. 1833 // Remove a closed connnection from the active set.
1834 void _connectionClosed(_HttpClientConnection connection) { 1834 void _connectionClosed(_HttpClientConnection connection) {
1835 connection.stopTimer(); 1835 connection.stopTimer();
1836 var connectionTarget = _connectionTargets[connection.key]; 1836 var connectionTarget = _connectionTargets[connection.key];
1837 if (connectionTarget != null) { 1837 if (connectionTarget != null) {
1838 connectionTarget.connectionClosed(connection); 1838 connectionTarget.connectionClosed(connection);
1839 if (connectionTarget.isEmpty) { 1839 if (connectionTarget.isEmpty) {
1840 _connectionTargets.remove(connection.key); 1840 _connectionTargets.remove(connection.key);
1841 } 1841 }
1842 _updateTimers(); 1842 _connectionsChanged();
1843 } 1843 }
1844 } 1844 }
1845 1845
1846 void _updateTimers() { 1846 void _connectionsChanged() {
1847 bool hasActive = _connectionTargets.values.any((t) => t.hasActive); 1847 if (_closing) {
1848 if (!hasActive) { 1848 _closeConnections(_closingForcefully);
1849 bool hasIdle = _connectionTargets.values.any((t) => t.hasIdle);
1850 if (hasIdle && _noActiveTimer == null) {
1851 _noActiveTimer = new Timer(const Duration(milliseconds: 100), () {
1852 _noActiveTimer = null;
1853 bool hasActive =
1854 _connectionTargets.values.any((t) => t.hasActive);
1855 if (!hasActive) {
1856 close();
1857 _closing = false;
1858 }
1859 });
1860 }
1861 } else if (_noActiveTimer != null) {
1862 _noActiveTimer.cancel();
1863 _noActiveTimer = null;
1864 } 1849 }
1865 } 1850 }
1866 1851
1852 void _closeConnections(bool force) {
1853 for (var connectionTarget in _connectionTargets.values.toList()) {
1854 connectionTarget.close(force);
1855 }
1856 }
1857
1867 _ConnectionTarget _getConnectionTarget(String host, int port, bool isSecure) { 1858 _ConnectionTarget _getConnectionTarget(String host, int port, bool isSecure) {
1868 String key = _HttpClientConnection.makeKey(isSecure, host, port); 1859 String key = _HttpClientConnection.makeKey(isSecure, host, port);
1869 return _connectionTargets.putIfAbsent( 1860 return _connectionTargets.putIfAbsent(
1870 key, () => new _ConnectionTarget(key, host, port, isSecure)); 1861 key, () => new _ConnectionTarget(key, host, port, isSecure));
1871 } 1862 }
1872 1863
1873 // Get a new _HttpClientConnection, from the matching _ConnectionTarget. 1864 // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
1874 Future<_ConnectionInfo> _getConnection(String uriHost, 1865 Future<_ConnectionInfo> _getConnection(String uriHost,
1875 int uriPort, 1866 int uriPort,
1876 _ProxyConfiguration proxyConf, 1867 _ProxyConfiguration proxyConf,
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
2009 2000
2010 // Use HashMap, as we don't need to keep order. 2001 // Use HashMap, as we don't need to keep order.
2011 static Map<int, _HttpConnection> _connections = 2002 static Map<int, _HttpConnection> _connections =
2012 new HashMap<int, _HttpConnection>(); 2003 new HashMap<int, _HttpConnection>();
2013 2004
2014 final _socket; 2005 final _socket;
2015 final _HttpServer _httpServer; 2006 final _HttpServer _httpServer;
2016 final _HttpParser _httpParser; 2007 final _HttpParser _httpParser;
2017 int _state = _IDLE; 2008 int _state = _IDLE;
2018 StreamSubscription _subscription; 2009 StreamSubscription _subscription;
2019 Timer _idleTimer;
2020 bool _idleMark = false; 2010 bool _idleMark = false;
2021 Future _streamFuture; 2011 Future _streamFuture;
2022 2012
2023 _HttpConnection(this._socket, this._httpServer) 2013 _HttpConnection(this._socket, this._httpServer)
2024 : _httpParser = new _HttpParser.requestParser() { 2014 : _httpParser = new _HttpParser.requestParser() {
2025 try { _socket._owner = this; } catch (_) { print(_); } 2015 try { _socket._owner = this; } catch (_) { print(_); }
2026 _connections[_serviceId] = this; 2016 _connections[_serviceId] = this;
2027 _httpParser.listenToStream(_socket); 2017 _httpParser.listenToStream(_socket);
2028 _subscription = _httpParser.listen( 2018 _subscription = _httpParser.listen(
2029 (incoming) { 2019 (incoming) {
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after
2817 const _RedirectInfo(this.statusCode, this.method, this.location); 2807 const _RedirectInfo(this.statusCode, this.method, this.location);
2818 } 2808 }
2819 2809
2820 String _getHttpVersion() { 2810 String _getHttpVersion() {
2821 var version = Platform.version; 2811 var version = Platform.version;
2822 // Only include major and minor version numbers. 2812 // Only include major and minor version numbers.
2823 int index = version.indexOf('.', version.indexOf('.') + 1); 2813 int index = version.indexOf('.', version.indexOf('.') + 1);
2824 version = version.substring(0, index); 2814 version = version.substring(0, index);
2825 return 'Dart/$version (dart:io)'; 2815 return 'Dart/$version (dart:io)';
2826 } 2816 }
OLDNEW
« no previous file with comments | « no previous file | dart/tests/standalone/io/http_client_stays_alive_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698