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