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