OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class _HttpHeaders implements HttpHeaders { | 5 class _HttpHeaders implements HttpHeaders { |
6 _HttpHeaders() : _headers = new Map<String, List<String>>(); | 6 _HttpHeaders() : _headers = new Map<String, List<String>>(); |
7 | 7 |
8 List<String> operator[](String name) { | 8 List<String> operator[](String name) { |
9 name = name.toLowerCase(); | 9 name = name.toLowerCase(); |
10 return _headers[name]; | 10 return _headers[name]; |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 String value; | 598 String value; |
599 Date expires; | 599 Date expires; |
600 int maxAge; | 600 int maxAge; |
601 String domain; | 601 String domain; |
602 String path; | 602 String path; |
603 bool httpOnly = false; | 603 bool httpOnly = false; |
604 bool secure = false; | 604 bool secure = false; |
605 } | 605 } |
606 | 606 |
607 | 607 |
| 608 // The close queue handles graceful closing of HTTP connections. When |
| 609 // a connection is added to the queue it will enter a wait state |
| 610 // waiting for all data written and possibly socket shutdown from |
| 611 // peer. |
| 612 class _CloseQueue { |
| 613 _CloseQueue() : _q = new Set<_HttpConnectionBase>(); |
| 614 |
| 615 void add(_HttpConnectionBase connection) { |
| 616 void closeIfDone() { |
| 617 // We only check for write closed here. This means that we are |
| 618 // not waiting for the client to half-close the socket before |
| 619 // fully closing the socket. |
| 620 if (!connection._isWriteClosed) return; |
| 621 _q.remove(connection); |
| 622 connection._socket.close(); |
| 623 if (connection.onClosed != null) connection.onClosed(); |
| 624 } |
| 625 |
| 626 // If the connection is already fully closed don't insert it into the queue. |
| 627 if (connection._isFullyClosed) { |
| 628 connection._socket.close(); |
| 629 if (connection.onClosed != null) connection.onClosed(); |
| 630 return; |
| 631 } |
| 632 |
| 633 _q.add(connection); |
| 634 |
| 635 // If output stream is not closed for writing close it now and |
| 636 // wait for callback when closed. |
| 637 if (!connection._isWriteClosed) { |
| 638 connection._socket.outputStream.close(); |
| 639 connection._socket.outputStream.onClosed = () { |
| 640 connection._state |= _HttpConnectionBase.WRITE_CLOSED; |
| 641 closeIfDone(); |
| 642 }; |
| 643 } else { |
| 644 connection._socket.outputStream.onClosed = () { assert(false); }; |
| 645 } |
| 646 |
| 647 // If socket is not closed for reading wait for callback. |
| 648 if (!connection._isReadClosed) { |
| 649 connection._socket.onClosed = () { |
| 650 connection._state |= _HttpConnectionBase.READ_CLOSED; |
| 651 // This is a nop, as we are not using the read closed |
| 652 // information for anything. For both server and client |
| 653 // connections the inbound message have been read to |
| 654 // completion when the socket enters the close queue. |
| 655 }; |
| 656 } else { |
| 657 connection._socket.onClosed = () { assert(false); }; |
| 658 } |
| 659 |
| 660 // Ignore any data on a socket in the close queue. |
| 661 connection._socket.onData = connection._socket.read; |
| 662 |
| 663 // If an error occurs immediately close the socket. |
| 664 connection._socket.onError = (e) { |
| 665 connection._state |= _HttpConnectionBase.WRITE_CLOSED; |
| 666 closeIfDone(); |
| 667 }; |
| 668 } |
| 669 |
| 670 void shutdown() { |
| 671 _q.forEach((_HttpConnectionBase connection) { |
| 672 connection._socket.close(); |
| 673 }); |
| 674 } |
| 675 |
| 676 final Set<_HttpConnectionBase> _q; |
| 677 } |
| 678 |
| 679 |
608 class _HttpRequestResponseBase { | 680 class _HttpRequestResponseBase { |
609 final int START = 0; | 681 final int START = 0; |
610 final int HEADER_SENT = 1; | 682 final int HEADER_SENT = 1; |
611 final int DONE = 2; | 683 final int DONE = 2; |
612 final int UPGRADED = 3; | 684 final int UPGRADED = 3; |
613 | 685 |
614 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) | 686 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) |
615 : _headers = new _HttpHeaders() { | 687 : _headers = new _HttpHeaders() { |
616 _state = START; | 688 _state = START; |
617 _headResponse = false; | 689 _headResponse = false; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 bool allWritten = true; | 761 bool allWritten = true; |
690 if (_contentLength < 0) { | 762 if (_contentLength < 0) { |
691 // Terminate the content if transfer encoding is chunked. | 763 // Terminate the content if transfer encoding is chunked. |
692 allWritten = _httpConnection._write(_Const.END_CHUNKED); | 764 allWritten = _httpConnection._write(_Const.END_CHUNKED); |
693 } else { | 765 } else { |
694 if (!_headResponse && _bodyBytesWritten < _contentLength) { | 766 if (!_headResponse && _bodyBytesWritten < _contentLength) { |
695 throw new HttpException("Sending less than specified content length"); | 767 throw new HttpException("Sending less than specified content length"); |
696 } | 768 } |
697 assert(_headResponse || _bodyBytesWritten == _contentLength); | 769 assert(_headResponse || _bodyBytesWritten == _contentLength); |
698 } | 770 } |
699 // If we are done writing the response, and either the client has | |
700 // closed or the connection is not persistent, we can close. Also | |
701 // if using HTTP 1.0 and the content length was not known we must | |
702 // close to indicate end of body. | |
703 if (!persistentConnection || _httpConnection._closing || | |
704 (_protocolVersion == "1.0" && _contentLength < 0)) { | |
705 _httpConnection._close(); | |
706 } | |
707 return allWritten; | 771 return allWritten; |
708 } | 772 } |
709 | 773 |
710 bool _writeHeaders() { | 774 bool _writeHeaders() { |
711 _headers._mutable = false; | 775 _headers._mutable = false; |
712 _headers._write(_httpConnection); | 776 _headers._write(_httpConnection); |
713 // Terminate header. | 777 // Terminate header. |
714 return _writeCRLF(); | 778 return _writeCRLF(); |
715 } | 779 } |
716 | 780 |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 if (_state == START) { | 1070 if (_state == START) { |
1007 _writeHeader(); | 1071 _writeHeader(); |
1008 } | 1072 } |
1009 _state = UPGRADED; | 1073 _state = UPGRADED; |
1010 // Ensure that any trailing data is written. | 1074 // Ensure that any trailing data is written. |
1011 _writeDone(); | 1075 _writeDone(); |
1012 // Indicate to the connection that the response handling is done. | 1076 // Indicate to the connection that the response handling is done. |
1013 return _httpConnection._detachSocket(); | 1077 return _httpConnection._detachSocket(); |
1014 } | 1078 } |
1015 | 1079 |
1016 void _responseEnd() { | |
1017 _ensureHeadersSent(); | |
1018 _state = DONE; | |
1019 // Stop tracking no pending write events. | |
1020 _httpConnection._onNoPendingWrites = null; | |
1021 // Ensure that any trailing data is written. | |
1022 _writeDone(); | |
1023 // Indicate to the connection that the response handling is done. | |
1024 _httpConnection._responseDone(); | |
1025 } | |
1026 | |
1027 // Delegate functions for the HttpOutputStream implementation. | 1080 // Delegate functions for the HttpOutputStream implementation. |
1028 bool _streamWrite(List<int> buffer, bool copyBuffer) { | 1081 bool _streamWrite(List<int> buffer, bool copyBuffer) { |
1029 if (_done) throw new HttpException("Response closed"); | 1082 if (_done) throw new HttpException("Response closed"); |
1030 return _write(buffer, copyBuffer); | 1083 return _write(buffer, copyBuffer); |
1031 } | 1084 } |
1032 | 1085 |
1033 bool _streamWriteFrom(List<int> buffer, int offset, int len) { | 1086 bool _streamWriteFrom(List<int> buffer, int offset, int len) { |
1034 if (_done) throw new HttpException("Response closed"); | 1087 if (_done) throw new HttpException("Response closed"); |
1035 return _writeList(buffer, offset, len); | 1088 return _writeList(buffer, offset, len); |
1036 } | 1089 } |
1037 | 1090 |
1038 void _streamFlush() { | 1091 void _streamFlush() { |
1039 _httpConnection._flush(); | 1092 _httpConnection._flush(); |
1040 } | 1093 } |
1041 | 1094 |
1042 void _streamClose() { | 1095 void _streamClose() { |
1043 _responseEnd(); | 1096 _ensureHeadersSent(); |
| 1097 _state = DONE; |
| 1098 // Stop tracking no pending write events. |
| 1099 _httpConnection._onNoPendingWrites = null; |
| 1100 // Ensure that any trailing data is written. |
| 1101 _writeDone(); |
| 1102 // Indicate to the connection that the response handling is done. |
| 1103 _httpConnection._responseClosed(); |
1044 } | 1104 } |
1045 | 1105 |
1046 void _streamSetNoPendingWriteHandler(callback()) { | 1106 void _streamSetNoPendingWriteHandler(callback()) { |
1047 if (_state != DONE) { | 1107 if (_state != DONE) { |
1048 _httpConnection._onNoPendingWrites = callback; | 1108 _httpConnection._onNoPendingWrites = callback; |
1049 } | 1109 } |
1050 } | 1110 } |
1051 | 1111 |
1052 void _streamSetCloseHandler(callback()) { | 1112 void _streamSetCloseHandler(callback()) { |
1053 // TODO(sgjesse): Handle this. | 1113 // TODO(sgjesse): Handle this. |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1250 | 1310 |
1251 void set onError(void callback(e)) { | 1311 void set onError(void callback(e)) { |
1252 _requestOrResponse._streamSetErrorHandler(callback); | 1312 _requestOrResponse._streamSetErrorHandler(callback); |
1253 } | 1313 } |
1254 | 1314 |
1255 _HttpRequestResponseBase _requestOrResponse; | 1315 _HttpRequestResponseBase _requestOrResponse; |
1256 } | 1316 } |
1257 | 1317 |
1258 | 1318 |
1259 abstract class _HttpConnectionBase { | 1319 abstract class _HttpConnectionBase { |
1260 _HttpConnectionBase() : _httpParser = new _HttpParser(), | 1320 static const int IDLE = 0; |
1261 hashCode = _nextHashCode { | 1321 static const int ACTIVE = 1; |
| 1322 static const int REQUEST_DONE = 2; |
| 1323 static const int RESPONSE_DONE = 4; |
| 1324 static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE; |
| 1325 static const int READ_CLOSED = 8; |
| 1326 static const int WRITE_CLOSED = 16; |
| 1327 static const int FULLY_CLOSED = READ_CLOSED | WRITE_CLOSED; |
| 1328 |
| 1329 _HttpConnectionBase() : hashCode = _nextHashCode { |
1262 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; | 1330 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; |
1263 } | 1331 } |
1264 | 1332 |
| 1333 bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE; |
| 1334 bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE; |
| 1335 bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE; |
| 1336 bool get _isReadClosed => (_state & READ_CLOSED) == READ_CLOSED; |
| 1337 bool get _isWriteClosed => (_state & WRITE_CLOSED) == WRITE_CLOSED; |
| 1338 bool get _isFullyClosed => (_state & FULLY_CLOSED) == FULLY_CLOSED; |
| 1339 |
1265 void _connectionEstablished(Socket socket) { | 1340 void _connectionEstablished(Socket socket) { |
1266 _socket = socket; | 1341 _socket = socket; |
1267 // Register handler for socket events. | 1342 // Register handlers for socket events. All socket events are |
1268 _socket.onData = _onData; | 1343 // passed to the HTTP parser. |
1269 _socket.onClosed = _onClosed; | 1344 _socket.onData = () { |
1270 _socket.onError = _onError; | 1345 List<int> buffer = _socket.read(); |
| 1346 if (buffer != null) { |
| 1347 _httpParser.streamData(buffer); |
| 1348 } |
| 1349 }; |
| 1350 _socket.onClosed = _httpParser.streamDone; |
| 1351 _socket.onError = _httpParser.streamError; |
1271 // Ignore errors in the socket output stream as this is getting | 1352 // Ignore errors in the socket output stream as this is getting |
1272 // the same errors as the socket itself. | 1353 // the same errors as the socket itself. |
1273 _socket.outputStream.onError = (e) => null; | 1354 _socket.outputStream.onError = (e) => null; |
1274 } | 1355 } |
1275 | 1356 |
1276 bool _write(List<int> data, [bool copyBuffer = false]) { | 1357 bool _write(List<int> data, [bool copyBuffer = false]) { |
1277 if (!_error && !_closing) { | 1358 return _socket.outputStream.write(data, copyBuffer); |
1278 return _socket.outputStream.write(data, copyBuffer); | |
1279 } | |
1280 } | 1359 } |
1281 | 1360 |
1282 bool _writeFrom(List<int> buffer, [int offset, int len]) { | 1361 bool _writeFrom(List<int> buffer, [int offset, int len]) { |
1283 if (!_error && !_closing) { | 1362 return _socket.outputStream.writeFrom(buffer, offset, len); |
1284 return _socket.outputStream.writeFrom(buffer, offset, len); | |
1285 } | |
1286 } | 1363 } |
1287 | 1364 |
1288 bool _flush() { | 1365 bool _flush() { |
1289 _socket.outputStream.flush(); | 1366 _socket.outputStream.flush(); |
1290 } | 1367 } |
1291 | 1368 |
1292 bool _close() { | 1369 bool _close() { |
1293 _closing = true; | |
1294 _socket.outputStream.close(); | 1370 _socket.outputStream.close(); |
1295 } | 1371 } |
1296 | 1372 |
1297 bool _destroy() { | 1373 bool _destroy() { |
1298 _closing = true; | |
1299 _socket.close(); | 1374 _socket.close(); |
1300 } | 1375 } |
1301 | 1376 |
1302 void _onData() { | |
1303 List<int> buffer = _socket.read(); | |
1304 if (buffer != null) { | |
1305 _httpParser.writeList(buffer, 0, buffer.length); | |
1306 } | |
1307 } | |
1308 | |
1309 void _onClosed() { | |
1310 _closing = true; | |
1311 _onConnectionClosed(null); | |
1312 } | |
1313 | |
1314 void _onError(e) { | |
1315 // If an error occurs, make sure to close the socket if one is associated. | |
1316 _error = true; | |
1317 if (_socket != null) { | |
1318 _socket.close(); | |
1319 } | |
1320 _onConnectionClosed(e); | |
1321 } | |
1322 | |
1323 DetachedSocket _detachSocket() { | 1377 DetachedSocket _detachSocket() { |
1324 _socket.onData = null; | 1378 _socket.onData = null; |
1325 _socket.onClosed = null; | 1379 _socket.onClosed = null; |
1326 _socket.onError = null; | 1380 _socket.onError = null; |
1327 _socket.outputStream.onNoPendingWrites = null; | 1381 _socket.outputStream.onNoPendingWrites = null; |
1328 Socket socket = _socket; | 1382 Socket socket = _socket; |
1329 _socket = null; | 1383 _socket = null; |
1330 if (onDetach != null) onDetach(); | 1384 if (onDetach != null) onDetach(); |
1331 return new _DetachedSocket(socket, _httpParser.readUnparsedData()); | 1385 return new _DetachedSocket(socket, _httpParser.readUnparsedData()); |
1332 } | 1386 } |
1333 | 1387 |
1334 HttpConnectionInfo get connectionInfo { | 1388 HttpConnectionInfo get connectionInfo { |
1335 if (_socket == null || _closing || _error) return null; | 1389 if (_socket == null) return null; |
1336 try { | 1390 try { |
1337 _HttpConnectionInfo info = new _HttpConnectionInfo(); | 1391 _HttpConnectionInfo info = new _HttpConnectionInfo(); |
1338 info.remoteHost = _socket.remoteHost; | 1392 info.remoteHost = _socket.remoteHost; |
1339 info.remotePort = _socket.remotePort; | 1393 info.remotePort = _socket.remotePort; |
1340 info.localPort = _socket.port; | 1394 info.localPort = _socket.port; |
1341 return info; | 1395 return info; |
1342 } catch (e) { } | 1396 } catch (e) { } |
1343 return null; | 1397 return null; |
1344 } | 1398 } |
1345 | 1399 |
1346 void _onConnectionClosed(e); | |
1347 void _responseDone(); | |
1348 | |
1349 void set _onNoPendingWrites(void callback()) { | 1400 void set _onNoPendingWrites(void callback()) { |
1350 if (!_error) { | 1401 _socket.outputStream.onNoPendingWrites = callback; |
1351 _socket.outputStream.onNoPendingWrites = callback; | |
1352 } | |
1353 } | 1402 } |
1354 | 1403 |
| 1404 int _state = IDLE; |
| 1405 |
1355 Socket _socket; | 1406 Socket _socket; |
1356 bool _closing = false; // Is the socket closed by the client? | |
1357 bool _error = false; // Is the socket closed due to an error? | |
1358 _HttpParser _httpParser; | 1407 _HttpParser _httpParser; |
1359 | 1408 |
| 1409 // Callbacks. |
1360 Function onDetach; | 1410 Function onDetach; |
| 1411 Function onClosed; |
1361 | 1412 |
1362 // Hash code for HTTP connection. Currently this is just a counter. | 1413 // Hash code for HTTP connection. Currently this is just a counter. |
1363 final int hashCode; | 1414 final int hashCode; |
1364 static int _nextHashCode = 0; | 1415 static int _nextHashCode = 0; |
1365 } | 1416 } |
1366 | 1417 |
1367 | 1418 |
1368 // HTTP server connection over a socket. | 1419 // HTTP server connection over a socket. |
1369 class _HttpConnection extends _HttpConnectionBase { | 1420 class _HttpConnection extends _HttpConnectionBase { |
1370 _HttpConnection(HttpServer this._server) { | 1421 _HttpConnection(HttpServer this._server) { |
| 1422 _httpParser = new _HttpParser.requestParser(); |
1371 // Register HTTP parser callbacks. | 1423 // Register HTTP parser callbacks. |
1372 _httpParser.requestStart = | 1424 _httpParser.requestStart = _onRequestStart; |
1373 (method, uri, version) => _onRequestStart(method, uri, version); | 1425 _httpParser.headerReceived = _onHeaderReceived; |
1374 _httpParser.responseStart = | 1426 _httpParser.headersComplete = _onHeadersComplete; |
1375 (statusCode, reasonPhrase, version) => | 1427 _httpParser.dataReceived = _onDataReceived; |
1376 _onResponseStart(statusCode, reasonPhrase, version); | 1428 _httpParser.dataEnd = _onDataEnd; |
1377 _httpParser.headerReceived = | 1429 _httpParser.error = _onError; |
1378 (name, value) => _onHeaderReceived(name, value); | 1430 _httpParser.closed = _onClosed; |
1379 _httpParser.headersComplete = () => _onHeadersComplete(); | 1431 _httpParser.responseStart = (statusCode, reasonPhrase, version) { |
1380 _httpParser.dataReceived = (data) => _onDataReceived(data); | 1432 assert(false); |
1381 _httpParser.dataEnd = (close) => _onDataEnd(close); | 1433 }; |
1382 _httpParser.error = (e) => _onError(e); | |
1383 } | 1434 } |
1384 | 1435 |
1385 void _onConnectionClosed(e) { | 1436 void _onClosed() { |
1386 // Don't report errors when HTTP parser is in idle state. Clients | 1437 _state |= _HttpConnectionBase.READ_CLOSED; |
1387 // can close the connection and cause a connection reset by peer | 1438 } |
1388 // error which is OK. | 1439 |
1389 if (e != null && !_httpParser.isIdle) { | 1440 void _onError(e) { |
1390 onError(e); | 1441 onError(e); |
1391 // Propagate the error to the streams. | 1442 // Propagate the error to the streams. |
1392 if (_request != null && _request._streamErrorHandler != null) { | 1443 if (_request != null && _request._streamErrorHandler != null) { |
1393 _request._streamErrorHandler(e); | 1444 _request._streamErrorHandler(e); |
1394 } | |
1395 if (_response != null && _response._streamErrorHandler != null) { | |
1396 _response._streamErrorHandler(e); | |
1397 } | |
1398 } | 1445 } |
1399 | 1446 if (_response != null && _response._streamErrorHandler != null) { |
1400 // If currently not processing any request close the socket when | 1447 _response._streamErrorHandler(e); |
1401 // we are done writing the response. | |
1402 if (_httpParser.isIdle) { | |
1403 // If the httpParser is idle and we get an error from the | |
1404 // connection we deal with that as a closed connection and not | |
1405 // as an error. When the client disappears we get a connection | |
1406 // reset by peer and that is OK. | |
1407 if (e != null) { | |
1408 onClosed(); | |
1409 } else { | |
1410 _socket.outputStream.onClosed = () { | |
1411 _destroy(); | |
1412 onClosed(); | |
1413 }; | |
1414 // If the client closes and we are done writing the response | |
1415 // the connection should be closed. | |
1416 if (_response == null) _close(); | |
1417 } | |
1418 } else { | |
1419 // Processing a request. | |
1420 if (e == null) { | |
1421 // Indicate connection close to the HTTP parser. | |
1422 _httpParser.connectionClosed(); | |
1423 } | |
1424 } | 1448 } |
| 1449 if (_socket != null) _socket.close(); |
1425 } | 1450 } |
1426 | 1451 |
1427 void _onRequestStart(String method, String uri, String version) { | 1452 void _onRequestStart(String method, String uri, String version) { |
| 1453 _state = _HttpConnectionBase.ACTIVE; |
1428 // Create new request and response objects for this request. | 1454 // Create new request and response objects for this request. |
1429 _request = new _HttpRequest(this); | 1455 _request = new _HttpRequest(this); |
1430 _response = new _HttpResponse(this); | 1456 _response = new _HttpResponse(this); |
1431 _request._onRequestStart(method, uri, version); | 1457 _request._onRequestStart(method, uri, version); |
1432 _request._protocolVersion = version; | 1458 _request._protocolVersion = version; |
1433 _response._protocolVersion = version; | 1459 _response._protocolVersion = version; |
1434 _response._headResponse = method == "HEAD"; | 1460 _response._headResponse = method == "HEAD"; |
1435 } | 1461 } |
1436 | 1462 |
1437 void _onResponseStart(int statusCode, String reasonPhrase, String version) { | |
1438 // TODO(sgjesse): Error handling. | |
1439 } | |
1440 | |
1441 void _onHeaderReceived(String name, String value) { | 1463 void _onHeaderReceived(String name, String value) { |
1442 _request._onHeaderReceived(name, value); | 1464 _request._onHeaderReceived(name, value); |
1443 } | 1465 } |
1444 | 1466 |
1445 void _onHeadersComplete() { | 1467 void _onHeadersComplete() { |
1446 _request._onHeadersComplete(); | 1468 _request._onHeadersComplete(); |
1447 _response.persistentConnection = _httpParser.persistentConnection; | 1469 _response.persistentConnection = _httpParser.persistentConnection; |
1448 if (onRequestReceived != null) { | 1470 if (onRequestReceived != null) { |
1449 onRequestReceived(_request, _response); | 1471 onRequestReceived(_request, _response); |
1450 } | 1472 } |
1451 } | 1473 } |
1452 | 1474 |
1453 void _onDataReceived(List<int> data) { | 1475 void _onDataReceived(List<int> data) { |
1454 _request._onDataReceived(data); | 1476 _request._onDataReceived(data); |
1455 } | 1477 } |
1456 | 1478 |
| 1479 void _checkDone() { |
| 1480 if (_isAllDone) { |
| 1481 // If we are done writing the response, and either the client |
| 1482 // has closed or the connection is not persistent, we must |
| 1483 // close. Also if using HTTP 1.0 and the content length was not |
| 1484 // known we must close to indicate end of body. |
| 1485 bool close = |
| 1486 !_response.persistentConnection || |
| 1487 (_response._protocolVersion == "1.0" && _response._contentLength < 0); |
| 1488 _request = null; |
| 1489 _response = null; |
| 1490 if (_isReadClosed || close) { |
| 1491 _server._closeQueue.add(this); |
| 1492 } else { |
| 1493 _state = _HttpConnectionBase.IDLE; |
| 1494 } |
| 1495 } |
| 1496 } |
| 1497 |
1457 void _onDataEnd(bool close) { | 1498 void _onDataEnd(bool close) { |
1458 _request._onDataEnd(); | 1499 _request._onDataEnd(); |
| 1500 _state |= _HttpConnectionBase.REQUEST_DONE; |
| 1501 _checkDone(); |
1459 } | 1502 } |
1460 | 1503 |
1461 void _responseDone() { | 1504 void _responseClosed() { |
1462 // If the connection is closing then close the output stream to | 1505 _state |= _HttpConnectionBase.RESPONSE_DONE; |
1463 // fully close the socket. | 1506 _checkDone(); |
1464 if (_closing) { | |
1465 _socket.outputStream.onClosed = () { | |
1466 _socket.close(); | |
1467 onClosed(); | |
1468 }; | |
1469 } | |
1470 _response = null; | |
1471 } | 1507 } |
1472 | 1508 |
1473 HttpServer _server; | 1509 HttpServer _server; |
1474 HttpRequest _request; | 1510 HttpRequest _request; |
1475 HttpResponse _response; | 1511 HttpResponse _response; |
1476 | 1512 |
1477 // Callbacks. | 1513 // Callbacks. |
1478 Function onRequestReceived; | 1514 Function onRequestReceived; |
1479 Function onClosed; | |
1480 Function onError; | 1515 Function onError; |
1481 } | 1516 } |
1482 | 1517 |
1483 | 1518 |
1484 class _RequestHandlerRegistration { | 1519 class _RequestHandlerRegistration { |
1485 _RequestHandlerRegistration(Function this._matcher, Function this._handler); | 1520 _RequestHandlerRegistration(Function this._matcher, Function this._handler); |
1486 Function _matcher; | 1521 Function _matcher; |
1487 Function _handler; | 1522 Function _handler; |
1488 } | 1523 } |
1489 | 1524 |
1490 // HTTP server waiting for socket connections. The connections are | 1525 // HTTP server waiting for socket connections. The connections are |
1491 // managed by the server and as requests are received the request. | 1526 // managed by the server and as requests are received the request. |
1492 class _HttpServer implements HttpServer { | 1527 class _HttpServer implements HttpServer { |
1493 _HttpServer() : _connections = new Set<_HttpConnection>(), | 1528 _HttpServer() : _connections = new Set<_HttpConnection>(), |
1494 _handlers = new List<_RequestHandlerRegistration>(); | 1529 _handlers = new List<_RequestHandlerRegistration>(), |
| 1530 _closeQueue = new _CloseQueue(); |
1495 | 1531 |
1496 void listen(String host, int port, {int backlog: 128}) { | 1532 void listen(String host, int port, {int backlog: 128}) { |
1497 listenOn(new ServerSocket(host, port, backlog)); | 1533 listenOn(new ServerSocket(host, port, backlog)); |
1498 _closeServer = true; | 1534 _closeServer = true; |
1499 } | 1535 } |
1500 | 1536 |
1501 void listenOn(ServerSocket serverSocket) { | 1537 void listenOn(ServerSocket serverSocket) { |
1502 void onConnection(Socket socket) { | 1538 void onConnection(Socket socket) { |
1503 // Accept the client connection. | 1539 // Accept the client connection. |
1504 _HttpConnection connection = new _HttpConnection(this); | 1540 _HttpConnection connection = new _HttpConnection(this); |
(...skipping 20 matching lines...) Expand all Loading... |
1525 void handler(HttpRequest request, HttpResponse response)) { | 1561 void handler(HttpRequest request, HttpResponse response)) { |
1526 _handlers.add(new _RequestHandlerRegistration(matcher, handler)); | 1562 _handlers.add(new _RequestHandlerRegistration(matcher, handler)); |
1527 } | 1563 } |
1528 | 1564 |
1529 void set defaultRequestHandler( | 1565 void set defaultRequestHandler( |
1530 void handler(HttpRequest request, HttpResponse response)) { | 1566 void handler(HttpRequest request, HttpResponse response)) { |
1531 _defaultHandler = handler; | 1567 _defaultHandler = handler; |
1532 } | 1568 } |
1533 | 1569 |
1534 void close() { | 1570 void close() { |
| 1571 _closeQueue.shutdown(); |
1535 if (_sessionManagerInstance != null) { | 1572 if (_sessionManagerInstance != null) { |
1536 _sessionManagerInstance.close(); | 1573 _sessionManagerInstance.close(); |
1537 _sessionManagerInstance = null; | 1574 _sessionManagerInstance = null; |
1538 } | 1575 } |
1539 if (_server != null && _closeServer) { | 1576 if (_server != null && _closeServer) { |
1540 _server.close(); | 1577 _server.close(); |
1541 } | 1578 } |
1542 _server = null; | 1579 _server = null; |
1543 for (_HttpConnection connection in _connections) { | 1580 for (_HttpConnection connection in _connections) { |
1544 connection._destroy(); | 1581 connection._destroy(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1595 return _sessionManagerInstance; | 1632 return _sessionManagerInstance; |
1596 } | 1633 } |
1597 | 1634 |
1598 | 1635 |
1599 ServerSocket _server; // The server listen socket. | 1636 ServerSocket _server; // The server listen socket. |
1600 bool _closeServer = false; | 1637 bool _closeServer = false; |
1601 Set<_HttpConnection> _connections; // Set of currently connected clients. | 1638 Set<_HttpConnection> _connections; // Set of currently connected clients. |
1602 List<_RequestHandlerRegistration> _handlers; | 1639 List<_RequestHandlerRegistration> _handlers; |
1603 Object _defaultHandler; | 1640 Object _defaultHandler; |
1604 Function _onError; | 1641 Function _onError; |
| 1642 _CloseQueue _closeQueue; |
1605 _HttpSessionManager _sessionManagerInstance; | 1643 _HttpSessionManager _sessionManagerInstance; |
1606 } | 1644 } |
1607 | 1645 |
1608 | 1646 |
1609 class _HttpClientRequest | 1647 class _HttpClientRequest |
1610 extends _HttpRequestResponseBase implements HttpClientRequest { | 1648 extends _HttpRequestResponseBase implements HttpClientRequest { |
1611 _HttpClientRequest(String this._method, | 1649 _HttpClientRequest(String this._method, |
1612 Uri this._uri, | 1650 Uri this._uri, |
1613 _HttpClientConnection connection) | 1651 _HttpClientConnection connection) |
1614 : super(connection) { | 1652 : super(connection) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1652 _httpConnection._flush(); | 1690 _httpConnection._flush(); |
1653 } | 1691 } |
1654 | 1692 |
1655 void _streamClose() { | 1693 void _streamClose() { |
1656 _ensureHeadersSent(); | 1694 _ensureHeadersSent(); |
1657 _state = DONE; | 1695 _state = DONE; |
1658 // Stop tracking no pending write events. | 1696 // Stop tracking no pending write events. |
1659 _httpConnection._onNoPendingWrites = null; | 1697 _httpConnection._onNoPendingWrites = null; |
1660 // Ensure that any trailing data is written. | 1698 // Ensure that any trailing data is written. |
1661 _writeDone(); | 1699 _writeDone(); |
1662 _connection._requestDone(); | 1700 _connection._requestClosed(); |
1663 } | 1701 } |
1664 | 1702 |
1665 void _streamSetNoPendingWriteHandler(callback()) { | 1703 void _streamSetNoPendingWriteHandler(callback()) { |
1666 if (_state != DONE) { | 1704 if (_state != DONE) { |
1667 _httpConnection._onNoPendingWrites = callback; | 1705 _httpConnection._onNoPendingWrites = callback; |
1668 } | 1706 } |
1669 } | 1707 } |
1670 | 1708 |
1671 void _streamSetCloseHandler(callback()) { | 1709 void _streamSetCloseHandler(callback()) { |
1672 // TODO(sgjesse): Handle this. | 1710 // TODO(sgjesse): Handle this. |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1767 return _cookies; | 1805 return _cookies; |
1768 } | 1806 } |
1769 | 1807 |
1770 InputStream get inputStream { | 1808 InputStream get inputStream { |
1771 if (_inputStream == null) { | 1809 if (_inputStream == null) { |
1772 _inputStream = new _HttpInputStream(this); | 1810 _inputStream = new _HttpInputStream(this); |
1773 } | 1811 } |
1774 return _inputStream; | 1812 return _inputStream; |
1775 } | 1813 } |
1776 | 1814 |
1777 void _onRequestStart(String method, String uri, String version) { | |
1778 // TODO(sgjesse): Error handling | |
1779 } | |
1780 | |
1781 void _onResponseStart(int statusCode, String reasonPhrase, String version) { | 1815 void _onResponseStart(int statusCode, String reasonPhrase, String version) { |
1782 _statusCode = statusCode; | 1816 _statusCode = statusCode; |
1783 _reasonPhrase = reasonPhrase; | 1817 _reasonPhrase = reasonPhrase; |
1784 } | 1818 } |
1785 | 1819 |
1786 void _onHeaderReceived(String name, String value) { | 1820 void _onHeaderReceived(String name, String value) { |
1787 _headers.add(name, value); | 1821 _headers.add(name, value); |
1788 } | 1822 } |
1789 | 1823 |
1790 void _handleUnauthorized() { | 1824 void _handleUnauthorized() { |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1899 _connection._onResponse(this); | 1933 _connection._onResponse(this); |
1900 } | 1934 } |
1901 } | 1935 } |
1902 | 1936 |
1903 void _onDataReceived(List<int> data) { | 1937 void _onDataReceived(List<int> data) { |
1904 _buffer.add(data); | 1938 _buffer.add(data); |
1905 if (_inputStream != null) _inputStream._dataReceived(); | 1939 if (_inputStream != null) _inputStream._dataReceived(); |
1906 } | 1940 } |
1907 | 1941 |
1908 void _onDataEnd() { | 1942 void _onDataEnd() { |
1909 _connection._responseDone(); | |
1910 if (_inputStream != null) { | 1943 if (_inputStream != null) { |
1911 _inputStream._closeReceived(); | 1944 _inputStream._closeReceived(); |
1912 } else { | 1945 } else { |
1913 inputStream._streamMarkedClosed = true; | 1946 inputStream._streamMarkedClosed = true; |
1914 } | 1947 } |
1915 } | 1948 } |
1916 | 1949 |
1917 // Delegate functions for the HttpInputStream implementation. | 1950 // Delegate functions for the HttpInputStream implementation. |
1918 int _streamAvailable() { | 1951 int _streamAvailable() { |
1919 return _buffer.length; | 1952 return _buffer.length; |
(...skipping 19 matching lines...) Expand all Loading... |
1939 _HttpClientConnection _connection; | 1972 _HttpClientConnection _connection; |
1940 _HttpInputStream _inputStream; | 1973 _HttpInputStream _inputStream; |
1941 _BufferList _buffer; | 1974 _BufferList _buffer; |
1942 | 1975 |
1943 Function _streamErrorHandler; | 1976 Function _streamErrorHandler; |
1944 } | 1977 } |
1945 | 1978 |
1946 | 1979 |
1947 class _HttpClientConnection | 1980 class _HttpClientConnection |
1948 extends _HttpConnectionBase implements HttpClientConnection { | 1981 extends _HttpConnectionBase implements HttpClientConnection { |
1949 static const int NONE = 0; | |
1950 static const int REQUEST_DONE = 1; | |
1951 static const int RESPONSE_DONE = 2; | |
1952 static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE; | |
1953 | 1982 |
1954 _HttpClientConnection(_HttpClient this._client); | 1983 _HttpClientConnection(_HttpClient this._client) { |
| 1984 _httpParser = new _HttpParser.responseParser(); |
| 1985 } |
1955 | 1986 |
1956 void _connectionEstablished(_SocketConnection socketConn) { | 1987 void _connectionEstablished(_SocketConnection socketConn) { |
1957 super._connectionEstablished(socketConn._socket); | 1988 super._connectionEstablished(socketConn._socket); |
1958 _socketConn = socketConn; | 1989 _socketConn = socketConn; |
1959 // Register HTTP parser callbacks. | 1990 // Register HTTP parser callbacks. |
1960 _httpParser.requestStart = | 1991 _httpParser.responseStart = _onResponseStart; |
1961 (method, uri, version) => _onRequestStart(method, uri, version); | 1992 _httpParser.headerReceived = _onHeaderReceived; |
1962 _httpParser.responseStart = | 1993 _httpParser.headersComplete = _onHeadersComplete; |
1963 (statusCode, reasonPhrase, version) => | 1994 _httpParser.dataReceived = _onDataReceived; |
1964 _onResponseStart(statusCode, reasonPhrase, version); | 1995 _httpParser.dataEnd = _onDataEnd; |
1965 _httpParser.headerReceived = | 1996 _httpParser.error = _onError; |
1966 (name, value) => _onHeaderReceived(name, value); | 1997 _httpParser.closed = _onClosed; |
1967 _httpParser.headersComplete = () => _onHeadersComplete(); | 1998 _httpParser.requestStart = (method, uri, version) { assert(false); }; |
1968 _httpParser.dataReceived = (data) => _onDataReceived(data); | 1999 _state = _HttpConnectionBase.ACTIVE; |
1969 _httpParser.dataEnd = (closed) => _onDataEnd(closed); | |
1970 _httpParser.error = (e) => _onError(e); | |
1971 } | 2000 } |
1972 | 2001 |
1973 bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE; | |
1974 bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE; | |
1975 bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE; | |
1976 | |
1977 void _checkSocketDone() { | 2002 void _checkSocketDone() { |
1978 if (_isAllDone) { | 2003 if (_isAllDone) { |
1979 if (!_closing) { | 2004 // If we are done writing the response, and either the server |
| 2005 // has closed or the connection is not persistent, we must |
| 2006 // close. |
| 2007 if (_isReadClosed || !_response.persistentConnection) { |
| 2008 this.onClosed = () { |
| 2009 _client._closedSocketConnection(_socketConn); |
| 2010 }; |
| 2011 _client._closeQueue.add(this); |
| 2012 } else { |
1980 _client._returnSocketConnection(_socketConn); | 2013 _client._returnSocketConnection(_socketConn); |
1981 } | 2014 _socket = null; |
1982 _socket = null; | 2015 _socketConn = null; |
1983 _socketConn = null; | 2016 assert(_pendingRedirect == null || _pendingRetry == null); |
1984 assert(_pendingRedirect == null || _pendingRetry == null); | 2017 if (_pendingRedirect != null) { |
1985 if (_pendingRedirect != null) { | 2018 _doRedirect(_pendingRedirect); |
1986 _doRedirect(_pendingRedirect); | 2019 _pendingRedirect = null; |
1987 _pendingRedirect = null; | 2020 } else if (_pendingRetry != null) { |
1988 } else if (_pendingRetry != null) { | 2021 _doRetry(_pendingRetry); |
1989 _doRetry(_pendingRetry); | 2022 _pendingRetry = null; |
1990 _pendingRetry = null; | 2023 } |
1991 } | 2024 } |
1992 } | 2025 } |
1993 } | 2026 } |
1994 | 2027 |
1995 void _requestDone() { | 2028 void _requestClosed() { |
1996 _state |= REQUEST_DONE; | 2029 _state |= _HttpConnectionBase.REQUEST_DONE; |
1997 _checkSocketDone(); | 2030 _checkSocketDone(); |
1998 } | 2031 } |
1999 | 2032 |
2000 void _responseDone() { | |
2001 if (_closing) { | |
2002 if (_socket != null) { | |
2003 _socket.close(); | |
2004 } | |
2005 } | |
2006 _state |= RESPONSE_DONE; | |
2007 _checkSocketDone(); | |
2008 } | |
2009 | |
2010 HttpClientRequest open(String method, Uri uri) { | 2033 HttpClientRequest open(String method, Uri uri) { |
2011 _method = method; | 2034 _method = method; |
2012 // Tell the HTTP parser the method it is expecting a response to. | 2035 // Tell the HTTP parser the method it is expecting a response to. |
2013 _httpParser.responseToMethod = method; | 2036 _httpParser.responseToMethod = method; |
2014 _request = new _HttpClientRequest(method, uri, this); | 2037 _request = new _HttpClientRequest(method, uri, this); |
2015 _response = new _HttpClientResponse(this); | 2038 _response = new _HttpClientResponse(this); |
2016 return _request; | 2039 return _request; |
2017 } | 2040 } |
2018 | 2041 |
2019 DetachedSocket detachSocket() { | 2042 DetachedSocket detachSocket() { |
2020 return _detachSocket(); | 2043 return _detachSocket(); |
2021 } | 2044 } |
2022 | 2045 |
2023 void _onConnectionClosed(e) { | 2046 void _onClosed() { |
| 2047 _state |= _HttpConnectionBase.READ_CLOSED; |
| 2048 } |
| 2049 |
| 2050 void _onError(e) { |
2024 // Socket is closed either due to an error or due to normal socket close. | 2051 // Socket is closed either due to an error or due to normal socket close. |
2025 if (e != null) { | 2052 if (_onErrorCallback != null) { |
2026 if (_onErrorCallback != null) { | 2053 _onErrorCallback(e); |
2027 _onErrorCallback(e); | 2054 } else { |
2028 } else { | 2055 throw e; |
2029 throw e; | |
2030 } | |
2031 } | 2056 } |
2032 _closing = true; | 2057 // Propagate the error to the streams. |
2033 if (e != null) { | 2058 if (_response != null && _response._streamErrorHandler != null) { |
2034 // Propagate the error to the streams. | 2059 _response._streamErrorHandler(e); |
2035 if (_response != null && _response._streamErrorHandler != null) { | 2060 } |
2036 _response._streamErrorHandler(e); | 2061 if (_socketConn != null) { |
2037 } | 2062 _client._closeSocketConnection(_socketConn); |
2038 _responseDone(); | |
2039 } else { | |
2040 // If there was no socket error the socket was closed | |
2041 // normally. Indicate closing to the HTTP Parser as there might | |
2042 // still be an HTTP error. | |
2043 _httpParser.connectionClosed(); | |
2044 } | 2063 } |
2045 } | 2064 } |
2046 | 2065 |
2047 void _onRequestStart(String method, String uri, String version) { | |
2048 // TODO(sgjesse): Error handling. | |
2049 } | |
2050 | |
2051 void _onResponseStart(int statusCode, String reasonPhrase, String version) { | 2066 void _onResponseStart(int statusCode, String reasonPhrase, String version) { |
2052 _response._onResponseStart(statusCode, reasonPhrase, version); | 2067 _response._onResponseStart(statusCode, reasonPhrase, version); |
2053 } | 2068 } |
2054 | 2069 |
2055 void _onHeaderReceived(String name, String value) { | 2070 void _onHeaderReceived(String name, String value) { |
2056 _response._onHeaderReceived(name, value); | 2071 _response._onHeaderReceived(name, value); |
2057 } | 2072 } |
2058 | 2073 |
2059 void _onHeadersComplete() { | 2074 void _onHeadersComplete() { |
2060 _response._onHeadersComplete(); | 2075 _response._onHeadersComplete(); |
2061 } | 2076 } |
2062 | 2077 |
2063 void _onDataReceived(List<int> data) { | 2078 void _onDataReceived(List<int> data) { |
2064 _response._onDataReceived(data); | 2079 _response._onDataReceived(data); |
2065 } | 2080 } |
2066 | 2081 |
2067 void _onDataEnd(bool close) { | 2082 void _onDataEnd(bool close) { |
2068 if (close) _closing = true; | |
2069 _response._onDataEnd(); | 2083 _response._onDataEnd(); |
| 2084 _state |= _HttpConnectionBase.RESPONSE_DONE; |
| 2085 _checkSocketDone(); |
2070 } | 2086 } |
2071 | 2087 |
2072 void set onRequest(void handler(HttpClientRequest request)) { | 2088 void set onRequest(void handler(HttpClientRequest request)) { |
2073 _onRequest = handler; | 2089 _onRequest = handler; |
2074 } | 2090 } |
2075 | 2091 |
2076 void set onResponse(void handler(HttpClientResponse response)) { | 2092 void set onResponse(void handler(HttpClientResponse response)) { |
2077 _onResponse = handler; | 2093 _onResponse = handler; |
2078 } | 2094 } |
2079 | 2095 |
2080 void set onError(void callback(e)) { | 2096 void set onError(void callback(e)) { |
2081 _onErrorCallback = callback; | 2097 _onErrorCallback = callback; |
2082 } | 2098 } |
2083 | 2099 |
2084 void _doRetry(_RedirectInfo retry) { | 2100 void _doRetry(_RedirectInfo retry) { |
2085 assert(_socketConn == null); | 2101 assert(_socketConn == null); |
2086 _request = null; | 2102 _request = null; |
2087 _response = null; | 2103 _response = null; |
2088 | 2104 |
2089 // Retry the URL using the same connection instance. | 2105 // Retry the URL using the same connection instance. |
2090 _state = NONE; | 2106 _state = _HttpConnectionBase.IDLE; |
2091 _client._openUrl(retry.method, retry.location, this); | 2107 _client._openUrl(retry.method, retry.location, this); |
2092 } | 2108 } |
2093 | 2109 |
2094 void _retry() { | 2110 void _retry() { |
2095 var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); | 2111 var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); |
2096 // The actual retry is postponed until both response and request | 2112 // The actual retry is postponed until both response and request |
2097 // are done. | 2113 // are done. |
2098 if (_isAllDone) { | 2114 if (_isAllDone) { |
2099 _doRetry(retry); | 2115 _doRetry(retry); |
2100 } else { | 2116 } else { |
(...skipping 23 matching lines...) Expand all Loading... |
2124 // request are done. | 2140 // request are done. |
2125 if (_isAllDone) { | 2141 if (_isAllDone) { |
2126 _doRedirect(redirect); | 2142 _doRedirect(redirect); |
2127 } else { | 2143 } else { |
2128 // Prepare for redirect. | 2144 // Prepare for redirect. |
2129 assert(_pendingRetry == null); | 2145 assert(_pendingRetry == null); |
2130 _pendingRedirect = redirect; | 2146 _pendingRedirect = redirect; |
2131 } | 2147 } |
2132 } | 2148 } |
2133 | 2149 |
2134 int _state = NONE; | |
2135 | |
2136 List<RedirectInfo> get redirects => _redirects; | 2150 List<RedirectInfo> get redirects => _redirects; |
2137 | 2151 |
2138 Function _onRequest; | 2152 Function _onRequest; |
2139 Function _onResponse; | 2153 Function _onResponse; |
2140 Function _onErrorCallback; | 2154 Function _onErrorCallback; |
2141 | 2155 |
2142 _HttpClient _client; | 2156 _HttpClient _client; |
2143 _SocketConnection _socketConn; | 2157 _SocketConnection _socketConn; |
2144 HttpClientRequest _request; | 2158 HttpClientRequest _request; |
2145 HttpClientResponse _response; | 2159 HttpClientResponse _response; |
(...skipping 19 matching lines...) Expand all Loading... |
2165 int this._port, | 2179 int this._port, |
2166 Socket this._socket); | 2180 Socket this._socket); |
2167 | 2181 |
2168 void _markReturned() { | 2182 void _markReturned() { |
2169 _socket.onData = null; | 2183 _socket.onData = null; |
2170 _socket.onClosed = null; | 2184 _socket.onClosed = null; |
2171 _socket.onError = null; | 2185 _socket.onError = null; |
2172 _returnTime = new Date.now(); | 2186 _returnTime = new Date.now(); |
2173 } | 2187 } |
2174 | 2188 |
| 2189 void _close() { |
| 2190 _socket.onData = null; |
| 2191 _socket.onClosed = null; |
| 2192 _socket.onError = null; |
| 2193 _socket.close(); |
| 2194 } |
| 2195 |
2175 Duration _idleTime(Date now) => now.difference(_returnTime); | 2196 Duration _idleTime(Date now) => now.difference(_returnTime); |
2176 | 2197 |
2177 int get hashCode => _socket.hashCode; | 2198 int get hashCode => _socket.hashCode; |
2178 | 2199 |
2179 String _host; | 2200 String _host; |
2180 int _port; | 2201 int _port; |
2181 Socket _socket; | 2202 Socket _socket; |
2182 Date _returnTime; | 2203 Date _returnTime; |
2183 } | 2204 } |
2184 | 2205 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2234 final String host; | 2255 final String host; |
2235 final int port; | 2256 final int port; |
2236 final bool isDirect; | 2257 final bool isDirect; |
2237 } | 2258 } |
2238 | 2259 |
2239 class _HttpClient implements HttpClient { | 2260 class _HttpClient implements HttpClient { |
2240 static const int DEFAULT_EVICTION_TIMEOUT = 60000; | 2261 static const int DEFAULT_EVICTION_TIMEOUT = 60000; |
2241 | 2262 |
2242 _HttpClient() : _openSockets = new Map(), | 2263 _HttpClient() : _openSockets = new Map(), |
2243 _activeSockets = new Set(), | 2264 _activeSockets = new Set(), |
| 2265 _closeQueue = new _CloseQueue(), |
2244 credentials = new List<_Credentials>(), | 2266 credentials = new List<_Credentials>(), |
2245 _shutdown = false; | 2267 _shutdown = false; |
2246 | 2268 |
2247 HttpClientConnection open( | 2269 HttpClientConnection open( |
2248 String method, String host, int port, String path) { | 2270 String method, String host, int port, String path) { |
2249 // TODO(sgjesse): The path set here can contain both query and | 2271 // TODO(sgjesse): The path set here can contain both query and |
2250 // fragment. They should be cracked and set correctly. | 2272 // fragment. They should be cracked and set correctly. |
2251 return _open(method, new Uri.fromComponents( | 2273 return _open(method, new Uri.fromComponents( |
2252 scheme: "http", domain: host, port: port, path: path)); | 2274 scheme: "http", domain: host, port: port, path: path)); |
2253 } | 2275 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2292 } | 2314 } |
2293 | 2315 |
2294 void addCredentials( | 2316 void addCredentials( |
2295 Uri url, String realm, HttpClientCredentials cr) { | 2317 Uri url, String realm, HttpClientCredentials cr) { |
2296 credentials.add(new _Credentials(url, realm, cr)); | 2318 credentials.add(new _Credentials(url, realm, cr)); |
2297 } | 2319 } |
2298 | 2320 |
2299 set findProxy(String f(Uri uri)) => _findProxy = f; | 2321 set findProxy(String f(Uri uri)) => _findProxy = f; |
2300 | 2322 |
2301 void shutdown() { | 2323 void shutdown() { |
2302 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { | 2324 _closeQueue.shutdown(); |
2303 while (!connections.isEmpty) { | 2325 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { |
2304 _SocketConnection socketConn = connections.removeFirst(); | 2326 while (!connections.isEmpty) { |
2305 socketConn._socket.close(); | 2327 _SocketConnection socketConn = connections.removeFirst(); |
2306 } | 2328 socketConn._socket.close(); |
2307 }); | 2329 } |
2308 _activeSockets.forEach((_SocketConnection socketConn) { | 2330 }); |
2309 socketConn._socket.close(); | 2331 _activeSockets.forEach((_SocketConnection socketConn) { |
2310 }); | 2332 socketConn._socket.close(); |
| 2333 }); |
2311 if (_evictionTimer != null) _cancelEvictionTimer(); | 2334 if (_evictionTimer != null) _cancelEvictionTimer(); |
2312 _shutdown = true; | 2335 _shutdown = true; |
2313 } | 2336 } |
2314 | 2337 |
2315 void _cancelEvictionTimer() { | 2338 void _cancelEvictionTimer() { |
2316 _evictionTimer.cancel(); | 2339 _evictionTimer.cancel(); |
2317 _evictionTimer = null; | 2340 _evictionTimer = null; |
2318 } | 2341 } |
2319 | 2342 |
2320 String _connectionKey(String host, int port) { | 2343 String _connectionKey(String host, int port) { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2496 if (_openSockets.isEmpty) _cancelEvictionTimer(); | 2519 if (_openSockets.isEmpty) _cancelEvictionTimer(); |
2497 } | 2520 } |
2498 _evictionTimer = new Timer.repeating(10000, _handleEviction); | 2521 _evictionTimer = new Timer.repeating(10000, _handleEviction); |
2499 } | 2522 } |
2500 | 2523 |
2501 // Return connection. | 2524 // Return connection. |
2502 _activeSockets.remove(socketConn); | 2525 _activeSockets.remove(socketConn); |
2503 sockets.addFirst(socketConn); | 2526 sockets.addFirst(socketConn); |
2504 } | 2527 } |
2505 | 2528 |
| 2529 void _closeSocketConnection(_SocketConnection socketConn) { |
| 2530 socketConn._close(); |
| 2531 _activeSockets.remove(socketConn); |
| 2532 } |
| 2533 |
| 2534 void _closedSocketConnection(_SocketConnection socketConn) { |
| 2535 _activeSockets.remove(socketConn); |
| 2536 } |
| 2537 |
2506 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { | 2538 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { |
2507 // Look for credentials. | 2539 // Look for credentials. |
2508 _Credentials cr = | 2540 _Credentials cr = |
2509 credentials.reduce(null, (_Credentials prev, _Credentials value) { | 2541 credentials.reduce(null, (_Credentials prev, _Credentials value) { |
2510 if (value.applies(url, scheme)) { | 2542 if (value.applies(url, scheme)) { |
2511 if (prev == null) return value; | 2543 if (prev == null) return value; |
2512 return value.uri.path.length > prev.uri.path.length ? value : prev; | 2544 return value.uri.path.length > prev.uri.path.length ? value : prev; |
2513 } else { | 2545 } else { |
2514 return prev; | 2546 return prev; |
2515 } | 2547 } |
2516 }); | 2548 }); |
2517 return cr; | 2549 return cr; |
2518 } | 2550 } |
2519 | 2551 |
2520 void _removeCredentials(_Credentials cr) { | 2552 void _removeCredentials(_Credentials cr) { |
2521 int index = credentials.indexOf(cr); | 2553 int index = credentials.indexOf(cr); |
2522 if (index != -1) { | 2554 if (index != -1) { |
2523 credentials.removeAt(index); | 2555 credentials.removeAt(index); |
2524 } | 2556 } |
2525 } | 2557 } |
2526 | 2558 |
2527 Function _onOpen; | 2559 Function _onOpen; |
2528 Map<String, Queue<_SocketConnection>> _openSockets; | 2560 Map<String, Queue<_SocketConnection>> _openSockets; |
2529 Set<_SocketConnection> _activeSockets; | 2561 Set<_SocketConnection> _activeSockets; |
| 2562 _CloseQueue _closeQueue; |
2530 List<_Credentials> credentials; | 2563 List<_Credentials> credentials; |
2531 Timer _evictionTimer; | 2564 Timer _evictionTimer; |
2532 Function _findProxy; | 2565 Function _findProxy; |
2533 Function _authenticate; | 2566 Function _authenticate; |
2534 bool _shutdown; // Has this HTTP client been shutdown? | 2567 bool _shutdown; // Has this HTTP client been shutdown? |
2535 } | 2568 } |
2536 | 2569 |
2537 | 2570 |
2538 class _HttpConnectionInfo implements HttpConnectionInfo { | 2571 class _HttpConnectionInfo implements HttpConnectionInfo { |
2539 String remoteHost; | 2572 String remoteHost; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2655 | 2688 |
2656 | 2689 |
2657 class _RedirectInfo implements RedirectInfo { | 2690 class _RedirectInfo implements RedirectInfo { |
2658 const _RedirectInfo(int this.statusCode, | 2691 const _RedirectInfo(int this.statusCode, |
2659 String this.method, | 2692 String this.method, |
2660 Uri this.location); | 2693 Uri this.location); |
2661 final int statusCode; | 2694 final int statusCode; |
2662 final String method; | 2695 final String method; |
2663 final Uri location; | 2696 final Uri location; |
2664 } | 2697 } |
OLD | NEW |