Chromium Code Reviews| 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 |