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

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

Issue 15268004: Add timeouts to HttpClient. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update comment. Created 7 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 | « sdk/lib/io/http.dart ('k') | tests/standalone/io/http_client_timeout_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 class _HttpIncoming extends Stream<List<int>> { 7 class _HttpIncoming extends Stream<List<int>> {
8 final int _transferLength; 8 final int _transferLength;
9 final Completer _dataCompleter = new Completer(); 9 final Completer _dataCompleter = new Completer();
10 Stream<List<int>> _stream; 10 Stream<List<int>> _stream;
(...skipping 1053 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 } 1064 }
1065 1065
1066 class _HttpClientConnection { 1066 class _HttpClientConnection {
1067 final String key; 1067 final String key;
1068 final Socket _socket; 1068 final Socket _socket;
1069 final bool _proxyTunnel; 1069 final bool _proxyTunnel;
1070 final _HttpParser _httpParser; 1070 final _HttpParser _httpParser;
1071 StreamSubscription _subscription; 1071 StreamSubscription _subscription;
1072 final _HttpClient _httpClient; 1072 final _HttpClient _httpClient;
1073 bool _dispose = false; 1073 bool _dispose = false;
1074 Timer _idleTimer;
1074 bool closed = false; 1075 bool closed = false;
1075 1076
1076 Completer<_HttpIncoming> _nextResponseCompleter; 1077 Completer<_HttpIncoming> _nextResponseCompleter;
1077 Future _streamFuture; 1078 Future _streamFuture;
1078 1079
1079 _HttpClientConnection(String this.key, 1080 _HttpClientConnection(String this.key,
1080 Socket this._socket, 1081 Socket this._socket,
1081 _HttpClient this._httpClient, 1082 _HttpClient this._httpClient,
1082 [this._proxyTunnel = false]) 1083 [this._proxyTunnel = false])
1083 : _httpParser = new _HttpParser.responseParser() { 1084 : _httpParser = new _HttpParser.responseParser() {
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
1278 key, secureSocket, request._httpClient, true); 1279 key, secureSocket, request._httpClient, true);
1279 }); 1280 });
1280 } 1281 }
1281 1282
1282 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); 1283 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
1283 1284
1284 static makeKey(bool isSecure, String host, int port) { 1285 static makeKey(bool isSecure, String host, int port) {
1285 return isSecure ? "ssh:$host:$port" : "$host:$port"; 1286 return isSecure ? "ssh:$host:$port" : "$host:$port";
1286 } 1287 }
1287 1288
1289 void stopTimer() {
1290 if (_idleTimer != null) {
1291 _idleTimer.cancel();
1292 _idleTimer = null;
1293 }
1294 }
1295
1296 void startTimer() {
1297 assert(_idleTimer == null);
1298 _idleTimer = new Timer(
1299 _httpClient.idleTimeout,
1300 () {
1301 _idleTimer = null;
1302 close();
1303 });
1304 }
1288 } 1305 }
1289 1306
1290 class _ConnnectionInfo { 1307 class _ConnnectionInfo {
1291 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy); 1308 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy);
1292 final _HttpClientConnection connection; 1309 final _HttpClientConnection connection;
1293 final _Proxy proxy; 1310 final _Proxy proxy;
1294 } 1311 }
1295 1312
1296 1313
1297 class _HttpClient implements HttpClient { 1314 class _HttpClient implements HttpClient {
1298 // TODO(ajohnsen): Use eviction timeout. 1315 // TODO(ajohnsen): Use eviction timeout.
1299 static const int DEFAULT_EVICTION_TIMEOUT = 60000;
1300 bool _closing = false; 1316 bool _closing = false;
1301 1317
1302 final Map<String, Set<_HttpClientConnection>> _idleConnections 1318 final Map<String, Set<_HttpClientConnection>> _idleConnections
1303 = new Map<String, Set<_HttpClientConnection>>(); 1319 = new Map<String, Set<_HttpClientConnection>>();
1304 final Set<_HttpClientConnection> _activeConnections 1320 final Set<_HttpClientConnection> _activeConnections
1305 = new Set<_HttpClientConnection>(); 1321 = new Set<_HttpClientConnection>();
1306 final List<_Credentials> _credentials = []; 1322 final List<_Credentials> _credentials = [];
1307 final List<_ProxyCredentials> _proxyCredentials = []; 1323 final List<_ProxyCredentials> _proxyCredentials = [];
1308 Function _authenticate; 1324 Function _authenticate;
1309 Function _authenticateProxy; 1325 Function _authenticateProxy;
1310 Function _findProxy = HttpClient.findProxyFromEnvironment; 1326 Function _findProxy = HttpClient.findProxyFromEnvironment;
1327 Duration _idleTimeout = const Duration(seconds: 15);
1328
1329 Timer _noActiveTimer;
1330
1331 Duration get idleTimeout => _idleTimeout;
1332
1333 void set idleTimeout(Duration timeout) {
1334 _idleTimeout = timeout;
1335 var idle = _idleConnections.values.forEach(
1336 (l) => l.forEach((c) {
1337 // Reset timer. This is fine, as it's not happening often.
1338 c.stopTimer();
1339 c.startTimer();
1340 }));
1341 }
1311 1342
1312 Future<HttpClientRequest> open(String method, 1343 Future<HttpClientRequest> open(String method,
1313 String host, 1344 String host,
1314 int port, 1345 int port,
1315 String path) { 1346 String path) {
1316 // TODO(sgjesse): The path set here can contain both query and 1347 // TODO(sgjesse): The path set here can contain both query and
1317 // fragment. They should be cracked and set correctly. 1348 // fragment. They should be cracked and set correctly.
1318 return _openUrl(method, new Uri.fromComponents( 1349 return _openUrl(method, new Uri.fromComponents(
1319 scheme: "http", domain: host, port: port, path: path)); 1350 scheme: "http", domain: host, port: port, path: path));
1320 } 1351 }
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1478 }); 1509 });
1479 } 1510 }
1480 1511
1481 // Return a live connection to the idle pool. 1512 // Return a live connection to the idle pool.
1482 void _returnConnection(_HttpClientConnection connection) { 1513 void _returnConnection(_HttpClientConnection connection) {
1483 _activeConnections.remove(connection); 1514 _activeConnections.remove(connection);
1484 if (_closing) { 1515 if (_closing) {
1485 connection.close(); 1516 connection.close();
1486 return; 1517 return;
1487 } 1518 }
1488 // TODO(ajohnsen): Listen for socket close events.
1489 if (!_idleConnections.containsKey(connection.key)) { 1519 if (!_idleConnections.containsKey(connection.key)) {
1490 _idleConnections[connection.key] = new LinkedHashSet(); 1520 _idleConnections[connection.key] = new LinkedHashSet();
1491 } 1521 }
1492 _idleConnections[connection.key].add(connection); 1522 _idleConnections[connection.key].add(connection);
1523 connection.startTimer();
1524 _updateTimers();
1493 } 1525 }
1494 1526
1495 // Remove a closed connnection from the active set. 1527 // Remove a closed connnection from the active set.
1496 void _connectionClosed(_HttpClientConnection connection) { 1528 void _connectionClosed(_HttpClientConnection connection) {
1529 connection.stopTimer();
1497 _activeConnections.remove(connection); 1530 _activeConnections.remove(connection);
1498 if (_idleConnections.containsKey(connection.key)) { 1531 if (_idleConnections.containsKey(connection.key)) {
1499 _idleConnections[connection.key].remove(connection); 1532 _idleConnections[connection.key].remove(connection);
1500 if (_idleConnections[connection.key].isEmpty) { 1533 if (_idleConnections[connection.key].isEmpty) {
1501 _idleConnections.remove(connection.key); 1534 _idleConnections.remove(connection.key);
1502 } 1535 }
1503 } 1536 }
1537 _updateTimers();
1538 }
1539
1540 void _updateTimers() {
1541 if (_activeConnections.isEmpty) {
1542 if (!_idleConnections.isEmpty && _noActiveTimer == null) {
1543 _noActiveTimer = new Timer(const Duration(milliseconds: 100), () {
1544 _noActiveTimer = null;
1545 if (_activeConnections.isEmpty) {
1546 close();
1547 _closing = false;
1548 }
1549 });
1550 }
1551 } else if (_noActiveTimer != null) {
1552 _noActiveTimer.cancel();
1553 _noActiveTimer = null;
1554 }
1504 } 1555 }
1505 1556
1506 // Get a new _HttpClientConnection, either from the idle pool or created from 1557 // Get a new _HttpClientConnection, either from the idle pool or created from
1507 // a new Socket. 1558 // a new Socket.
1508 Future<_ConnnectionInfo> _getConnection(String uriHost, 1559 Future<_ConnnectionInfo> _getConnection(String uriHost,
1509 int uriPort, 1560 int uriPort,
1510 _ProxyConfiguration proxyConf, 1561 _ProxyConfiguration proxyConf,
1511 bool isSecure) { 1562 bool isSecure) {
1512 Iterator<_Proxy> proxies = proxyConf.proxies.iterator; 1563 Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
1513 1564
1514 Future<_ConnnectionInfo> connect(error) { 1565 Future<_ConnnectionInfo> connect(error) {
1515 if (!proxies.moveNext()) return new Future.error(error); 1566 if (!proxies.moveNext()) return new Future.error(error);
1516 _Proxy proxy = proxies.current; 1567 _Proxy proxy = proxies.current;
1517 String host = proxy.isDirect ? uriHost: proxy.host; 1568 String host = proxy.isDirect ? uriHost: proxy.host;
1518 int port = proxy.isDirect ? uriPort: proxy.port; 1569 int port = proxy.isDirect ? uriPort: proxy.port;
1519 String key = _HttpClientConnection.makeKey(isSecure, host, port); 1570 String key = _HttpClientConnection.makeKey(isSecure, host, port);
1520 if (_idleConnections.containsKey(key)) { 1571 if (_idleConnections.containsKey(key)) {
1521 var connection = _idleConnections[key].first; 1572 var connection = _idleConnections[key].first;
1522 _idleConnections[key].remove(connection); 1573 _idleConnections[key].remove(connection);
1523 if (_idleConnections[key].isEmpty) { 1574 if (_idleConnections[key].isEmpty) {
1524 _idleConnections.remove(key); 1575 _idleConnections.remove(key);
1525 } 1576 }
1577 connection.stopTimer();
1526 _activeConnections.add(connection); 1578 _activeConnections.add(connection);
1579 _updateTimers();
1527 return new Future.value(new _ConnnectionInfo(connection, proxy)); 1580 return new Future.value(new _ConnnectionInfo(connection, proxy));
1528 } 1581 }
1529 return (isSecure && proxy.isDirect 1582 return (isSecure && proxy.isDirect
1530 ? SecureSocket.connect(host, 1583 ? SecureSocket.connect(host,
1531 port, 1584 port,
1532 sendClientCertificate: true) 1585 sendClientCertificate: true)
1533 : Socket.connect(host, port)) 1586 : Socket.connect(host, port))
1534 .then((socket) { 1587 .then((socket) {
1535 socket.setOption(SocketOption.TCP_NODELAY, true); 1588 socket.setOption(SocketOption.TCP_NODELAY, true);
1536 var connection = new _HttpClientConnection(key, socket, this); 1589 var connection = new _HttpClientConnection(key, socket, this);
(...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after
2260 2313
2261 2314
2262 class _RedirectInfo implements RedirectInfo { 2315 class _RedirectInfo implements RedirectInfo {
2263 const _RedirectInfo(int this.statusCode, 2316 const _RedirectInfo(int this.statusCode,
2264 String this.method, 2317 String this.method,
2265 Uri this.location); 2318 Uri this.location);
2266 final int statusCode; 2319 final int statusCode;
2267 final String method; 2320 final String method;
2268 final Uri location; 2321 final Uri location;
2269 } 2322 }
OLDNEW
« no previous file with comments | « sdk/lib/io/http.dart ('k') | tests/standalone/io/http_client_timeout_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698