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