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 1567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |