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

Unified Diff: pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart

Issue 2698353003: unfork DDC's copy of most SDK libraries (Closed)
Patch Set: revert core_patch Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart b/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart
deleted file mode 100644
index adef61fad5552972e137a0091469ede602a5be1e..0000000000000000000000000000000000000000
--- a/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart
+++ /dev/null
@@ -1,1072 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-// Global constants.
-class _Const {
- // Bytes for "HTTP".
- static const HTTP = const [72, 84, 84, 80];
- // Bytes for "HTTP/1.".
- static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46];
- // Bytes for "HTTP/1.0".
- static const HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48];
- // Bytes for "HTTP/1.1".
- static const HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49];
-
- static const bool T = true;
- static const bool F = false;
- // Loopup-map for the following characters: '()<>@,;:\\"/[]?={} \t'.
- static const SEPARATOR_MAP = const [
- F,F,F,F,F,F,F,F,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,F,T,F,F,
- F,F,F,T,T,F,F,T,F,F,T,F,F,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,
- F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,
- F,F,F,F,F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,
- F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,
- F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,
- F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F];
-}
-
-
-// Frequently used character codes.
-class _CharCode {
- static const int HT = 9;
- static const int LF = 10;
- static const int CR = 13;
- static const int SP = 32;
- static const int AMPERSAND = 38;
- static const int COMMA = 44;
- static const int DASH = 45;
- static const int SLASH = 47;
- static const int ZERO = 48;
- static const int ONE = 49;
- static const int COLON = 58;
- static const int SEMI_COLON = 59;
- static const int EQUAL = 61;
-}
-
-
-// States of the HTTP parser state machine.
-class _State {
- static const int START = 0;
- static const int METHOD_OR_RESPONSE_HTTP_VERSION = 1;
- static const int RESPONSE_HTTP_VERSION = 2;
- static const int REQUEST_LINE_METHOD = 3;
- static const int REQUEST_LINE_URI = 4;
- static const int REQUEST_LINE_HTTP_VERSION = 5;
- static const int REQUEST_LINE_ENDING = 6;
- static const int RESPONSE_LINE_STATUS_CODE = 7;
- static const int RESPONSE_LINE_REASON_PHRASE = 8;
- static const int RESPONSE_LINE_ENDING = 9;
- static const int HEADER_START = 10;
- static const int HEADER_FIELD = 11;
- static const int HEADER_VALUE_START = 12;
- static const int HEADER_VALUE = 13;
- static const int HEADER_VALUE_FOLDING_OR_ENDING = 14;
- static const int HEADER_VALUE_FOLD_OR_END = 15;
- static const int HEADER_ENDING = 16;
-
- static const int CHUNK_SIZE_STARTING_CR = 17;
- static const int CHUNK_SIZE_STARTING_LF = 18;
- static const int CHUNK_SIZE = 19;
- static const int CHUNK_SIZE_EXTENSION = 20;
- static const int CHUNK_SIZE_ENDING = 21;
- static const int CHUNKED_BODY_DONE_CR = 22;
- static const int CHUNKED_BODY_DONE_LF = 23;
- static const int BODY = 24;
- static const int CLOSED = 25;
- static const int UPGRADED = 26;
- static const int FAILURE = 27;
-
- static const int FIRST_BODY_STATE = CHUNK_SIZE_STARTING_CR;
-}
-
-// HTTP version of the request or response being parsed.
-class _HttpVersion {
- static const int UNDETERMINED = 0;
- static const int HTTP10 = 1;
- static const int HTTP11 = 2;
-}
-
-// States of the HTTP parser state machine.
-class _MessageType {
- static const int UNDETERMINED = 0;
- static const int REQUEST = 1;
- static const int RESPONSE = 0;
-}
-
-
-/**
- * The _HttpDetachedStreamSubscription takes a subscription and some extra data,
- * and makes it possible to "inject" the data in from of other data events
- * from the subscription.
- *
- * It does so by overriding pause/resume, so that once the
- * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before
- * resuming the underlaying subscription.
- */
-class _HttpDetachedStreamSubscription implements StreamSubscription<List<int>> {
- StreamSubscription<List<int>> _subscription;
- List<int> _injectData;
- bool _isCanceled = false;
- int _pauseCount = 1;
- Function _userOnData;
- bool _scheduled = false;
-
- _HttpDetachedStreamSubscription(this._subscription,
- this._injectData,
- this._userOnData);
-
- bool get isPaused => _subscription.isPaused;
-
- Future/*<T>*/ asFuture/*<T>*/([/*=T*/ futureValue]) =>
- _subscription.asFuture/*<T>*/(futureValue);
-
- Future cancel() {
- _isCanceled = true;
- _injectData = null;
- return _subscription.cancel();
- }
-
- void onData(void handleData(List<int> data)) {
- _userOnData = handleData;
- _subscription.onData(handleData);
- }
-
- void onDone(void handleDone()) {
- _subscription.onDone(handleDone);
- }
-
- void onError(Function handleError) {
- _subscription.onError(handleError);
- }
-
- void pause([Future resumeSignal]) {
- if (_injectData == null) {
- _subscription.pause(resumeSignal);
- } else {
- _pauseCount++;
- if (resumeSignal != null) {
- resumeSignal.whenComplete(resume);
- }
- }
- }
-
- void resume() {
- if (_injectData == null) {
- _subscription.resume();
- } else {
- _pauseCount--;
- _maybeScheduleData();
- }
- }
-
- void _maybeScheduleData() {
- if (_scheduled) return;
- if (_pauseCount != 0) return;
- _scheduled = true;
- scheduleMicrotask(() {
- _scheduled = false;
- if (_pauseCount > 0 || _isCanceled) return;
- var data = _injectData;
- _injectData = null;
- // To ensure that 'subscription.isPaused' is false, we resume the
- // subscription here. This is fine as potential events are delayed.
- _subscription.resume();
- if (_userOnData != null) {
- _userOnData(data);
- }
- });
- }
-}
-
-
-class _HttpDetachedIncoming extends Stream<List<int>> {
- final StreamSubscription subscription;
- final List<int> bufferedData;
-
- _HttpDetachedIncoming(this.subscription, this.bufferedData);
-
- StreamSubscription<List<int>> listen(void onData(List<int> event),
- {Function onError,
- void onDone(),
- bool cancelOnError}) {
- if (subscription != null) {
- subscription
- ..onData(onData)
- ..onError(onError)
- ..onDone(onDone);
- if (bufferedData == null) {
- return subscription..resume();
- }
- return new _HttpDetachedStreamSubscription(subscription,
- bufferedData,
- onData)
- ..resume();
- } else {
- return new Stream.fromIterable(bufferedData)
- .listen(onData,
- onError: onError,
- onDone: onDone,
- cancelOnError: cancelOnError);
- }
- }
-}
-
-
-/**
- * HTTP parser which parses the data stream given to [consume].
- *
- * If an HTTP parser error occours, the parser will signal an error to either
- * the current _HttpIncoming or the _parser itself.
- *
- * The connection upgrades (e.g. switching from HTTP/1.1 to the
- * WebSocket protocol) is handled in a special way. If connection
- * upgrade is specified in the headers, then on the callback to
- * [:responseStart:] the [:upgrade:] property on the [:HttpParser:]
- * object will be [:true:] indicating that from now on the protocol is
- * not HTTP anymore and no more callbacks will happen, that is
- * [:dataReceived:] and [:dataEnd:] are not called in this case as
- * there is no more HTTP data. After the upgrade the method
- * [:readUnparsedData:] can be used to read any remaining bytes in the
- * HTTP parser which are part of the protocol the connection is
- * upgrading to. These bytes cannot be processed by the HTTP parser
- * and should be handled according to whatever protocol is being
- * upgraded to.
- */
-class _HttpParser extends Stream<_HttpIncoming> {
- // State.
- bool _parserCalled = false;
-
- // The data that is currently being parsed.
- Uint8List _buffer;
- int _index;
-
- final bool _requestParser;
- int _state;
- int _httpVersionIndex;
- int _messageType;
- int _statusCode = 0;
- int _statusCodeLength = 0;
- final List<int> _method = [];
- final List<int> _uri_or_reason_phrase = [];
- final List<int> _headerField = [];
- final List<int> _headerValue = [];
-
- int _httpVersion;
- int _transferLength = -1;
- bool _persistentConnection;
- bool _connectionUpgrade;
- bool _chunked;
-
- bool _noMessageBody = false;
- int _remainingContent = -1;
-
- _HttpHeaders _headers;
-
- // The current incoming connection.
- _HttpIncoming _incoming;
- StreamSubscription _socketSubscription;
- bool _paused = true;
- bool _bodyPaused = false;
- StreamController<_HttpIncoming> _controller;
- StreamController<List<int>> _bodyController;
-
- factory _HttpParser.requestParser() {
- return new _HttpParser._(true);
- }
-
- factory _HttpParser.responseParser() {
- return new _HttpParser._(false);
- }
-
- _HttpParser._(this._requestParser) {
- _controller = new StreamController<_HttpIncoming>(
- sync: true,
- onListen: () {
- _paused = false;
- },
- onPause: () {
- _paused = true;
- _pauseStateChanged();
- },
- onResume: () {
- _paused = false;
- _pauseStateChanged();
- },
- onCancel: () {
- if (_socketSubscription != null) {
- _socketSubscription.cancel();
- }
- });
- _reset();
- }
-
-
- StreamSubscription<_HttpIncoming> listen(void onData(_HttpIncoming event),
- {Function onError,
- void onDone(),
- bool cancelOnError}) {
- return _controller.stream.listen(onData,
- onError: onError,
- onDone: onDone,
- cancelOnError: cancelOnError);
- }
-
- void listenToStream(Stream<List<int>> stream) {
- // Listen to the stream and handle data accordingly. When a
- // _HttpIncoming is created, _dataPause, _dataResume, _dataDone is
- // given to provide a way of controlling the parser.
- // TODO(ajohnsen): Remove _dataPause, _dataResume and _dataDone and clean up
- // how the _HttpIncoming signals the parser.
- _socketSubscription = stream.listen(
- _onData,
- onError: _controller.addError,
- onDone: _onDone);
- }
-
- void _parse() {
- try {
- _doParse();
- } catch (e, s) {
- _state = _State.FAILURE;
- _reportError(e, s);
- }
- }
-
- // Process end of headers. Returns true if the parser should stop
- // parsing and return. This will be in case of either an upgrade
- // request or a request or response with an empty body.
- bool _headersEnd() {
- _headers._mutable = false;
-
- _transferLength = _headers.contentLength;
- // Ignore the Content-Length header if Transfer-Encoding
- // is chunked (RFC 2616 section 4.4)
- if (_chunked) _transferLength = -1;
-
- // If a request message has neither Content-Length nor
- // Transfer-Encoding the message must not have a body (RFC
- // 2616 section 4.3).
- if (_messageType == _MessageType.REQUEST &&
- _transferLength < 0 &&
- _chunked == false) {
- _transferLength = 0;
- }
- if (_connectionUpgrade) {
- _state = _State.UPGRADED;
- _transferLength = 0;
- }
- _createIncoming(_transferLength);
- if (_requestParser) {
- _incoming.method =
- new String.fromCharCodes(_method);
- _incoming.uri =
- Uri.parse(
- new String.fromCharCodes(_uri_or_reason_phrase));
- } else {
- _incoming.statusCode = _statusCode;
- _incoming.reasonPhrase =
- new String.fromCharCodes(_uri_or_reason_phrase);
- }
- _method.clear();
- _uri_or_reason_phrase.clear();
- if (_connectionUpgrade) {
- _incoming.upgraded = true;
- _parserCalled = false;
- var tmp = _incoming;
- _closeIncoming();
- _controller.add(tmp);
- return true;
- }
- if (_transferLength == 0 ||
- (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
- _reset();
- var tmp = _incoming;
- _closeIncoming();
- _controller.add(tmp);
- return false;
- } else if (_chunked) {
- _state = _State.CHUNK_SIZE;
- _remainingContent = 0;
- } else if (_transferLength > 0) {
- _remainingContent = _transferLength;
- _state = _State.BODY;
- } else {
- // Neither chunked nor content length. End of body
- // indicated by close.
- _state = _State.BODY;
- }
- _parserCalled = false;
- _controller.add(_incoming);
- return true;
- }
-
- // From RFC 2616.
- // generic-message = start-line
- // *(message-header CRLF)
- // CRLF
- // [ message-body ]
- // start-line = Request-Line | Status-Line
- // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
- // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
- // message-header = field-name ":" [ field-value ]
- void _doParse() {
- assert(!_parserCalled);
- _parserCalled = true;
- if (_state == _State.CLOSED) {
- throw new HttpException("Data on closed connection");
- }
- if (_state == _State.FAILURE) {
- throw new HttpException("Data on failed connection");
- }
- while (_buffer != null &&
- _index < _buffer.length &&
- _state != _State.FAILURE &&
- _state != _State.UPGRADED) {
- // Depending on _incoming, we either break on _bodyPaused or _paused.
- if ((_incoming != null && _bodyPaused) ||
- (_incoming == null && _paused)) {
- _parserCalled = false;
- return;
- }
- int byte = _buffer[_index++];
- switch (_state) {
- case _State.START:
- if (byte == _Const.HTTP[0]) {
- // Start parsing method or HTTP version.
- _httpVersionIndex = 1;
- _state = _State.METHOD_OR_RESPONSE_HTTP_VERSION;
- } else {
- // Start parsing method.
- if (!_isTokenChar(byte)) {
- throw new HttpException("Invalid request method");
- }
- _method.add(byte);
- if (!_requestParser) {
- throw new HttpException("Invalid response line");
- }
- _state = _State.REQUEST_LINE_METHOD;
- }
- break;
-
- case _State.METHOD_OR_RESPONSE_HTTP_VERSION:
- if (_httpVersionIndex < _Const.HTTP.length &&
- byte == _Const.HTTP[_httpVersionIndex]) {
- // Continue parsing HTTP version.
- _httpVersionIndex++;
- } else if (_httpVersionIndex == _Const.HTTP.length &&
- byte == _CharCode.SLASH) {
- // HTTP/ parsed. As method is a token this cannot be a
- // method anymore.
- _httpVersionIndex++;
- if (_requestParser) {
- throw new HttpException("Invalid request line");
- }
- _state = _State.RESPONSE_HTTP_VERSION;
- } else {
- // Did not parse HTTP version. Expect method instead.
- for (int i = 0; i < _httpVersionIndex; i++) {
- _method.add(_Const.HTTP[i]);
- }
- if (byte == _CharCode.SP) {
- _state = _State.REQUEST_LINE_URI;
- } else {
- _method.add(byte);
- _httpVersion = _HttpVersion.UNDETERMINED;
- if (!_requestParser) {
- throw new HttpException("Invalid response line");
- }
- _state = _State.REQUEST_LINE_METHOD;
- }
- }
- break;
-
- case _State.RESPONSE_HTTP_VERSION:
- if (_httpVersionIndex < _Const.HTTP1DOT.length) {
- // Continue parsing HTTP version.
- _expect(byte, _Const.HTTP1DOT[_httpVersionIndex]);
- _httpVersionIndex++;
- } else if (_httpVersionIndex == _Const.HTTP1DOT.length &&
- byte == _CharCode.ONE) {
- // HTTP/1.1 parsed.
- _httpVersion = _HttpVersion.HTTP11;
- _persistentConnection = true;
- _httpVersionIndex++;
- } else if (_httpVersionIndex == _Const.HTTP1DOT.length &&
- byte == _CharCode.ZERO) {
- // HTTP/1.0 parsed.
- _httpVersion = _HttpVersion.HTTP10;
- _persistentConnection = false;
- _httpVersionIndex++;
- } else if (_httpVersionIndex == _Const.HTTP1DOT.length + 1) {
- _expect(byte, _CharCode.SP);
- // HTTP version parsed.
- _state = _State.RESPONSE_LINE_STATUS_CODE;
- } else {
- throw new HttpException("Invalid response line");
- }
- break;
-
- case _State.REQUEST_LINE_METHOD:
- if (byte == _CharCode.SP) {
- _state = _State.REQUEST_LINE_URI;
- } else {
- if (_Const.SEPARATOR_MAP[byte] ||
- byte == _CharCode.CR ||
- byte == _CharCode.LF) {
- throw new HttpException("Invalid request method");
- }
- _method.add(byte);
- }
- break;
-
- case _State.REQUEST_LINE_URI:
- if (byte == _CharCode.SP) {
- if (_uri_or_reason_phrase.length == 0) {
- throw new HttpException("Invalid request URI");
- }
- _state = _State.REQUEST_LINE_HTTP_VERSION;
- _httpVersionIndex = 0;
- } else {
- if (byte == _CharCode.CR || byte == _CharCode.LF) {
- throw new HttpException("Invalid request URI");
- }
- _uri_or_reason_phrase.add(byte);
- }
- break;
-
- case _State.REQUEST_LINE_HTTP_VERSION:
- if (_httpVersionIndex < _Const.HTTP1DOT.length) {
- _expect(byte, _Const.HTTP11[_httpVersionIndex]);
- _httpVersionIndex++;
- } else if (_httpVersionIndex == _Const.HTTP1DOT.length) {
- if (byte == _CharCode.ONE) {
- // HTTP/1.1 parsed.
- _httpVersion = _HttpVersion.HTTP11;
- _persistentConnection = true;
- _httpVersionIndex++;
- } else if (byte == _CharCode.ZERO) {
- // HTTP/1.0 parsed.
- _httpVersion = _HttpVersion.HTTP10;
- _persistentConnection = false;
- _httpVersionIndex++;
- } else {
- throw new HttpException("Invalid response line");
- }
- } else {
- if (byte == _CharCode.CR) {
- _state = _State.REQUEST_LINE_ENDING;
- } else {
- _expect(byte, _CharCode.LF);
- _messageType = _MessageType.REQUEST;
- _state = _State.HEADER_START;
- }
- }
- break;
-
- case _State.REQUEST_LINE_ENDING:
- _expect(byte, _CharCode.LF);
- _messageType = _MessageType.REQUEST;
- _state = _State.HEADER_START;
- break;
-
- case _State.RESPONSE_LINE_STATUS_CODE:
- if (byte == _CharCode.SP) {
- _state = _State.RESPONSE_LINE_REASON_PHRASE;
- } else if (byte == _CharCode.CR) {
- // Some HTTP servers does not follow the spec. and send
- // \r\n right after the status code.
- _state = _State.RESPONSE_LINE_ENDING;
- } else {
- _statusCodeLength++;
- if ((byte < 0x30 && 0x39 < byte) || _statusCodeLength > 3) {
- throw new HttpException("Invalid response status code");
- } else {
- _statusCode = _statusCode * 10 + byte - 0x30;
- }
- }
- break;
-
- case _State.RESPONSE_LINE_REASON_PHRASE:
- if (byte == _CharCode.CR) {
- _state = _State.RESPONSE_LINE_ENDING;
- } else {
- if (byte == _CharCode.CR || byte == _CharCode.LF) {
- throw new HttpException("Invalid response reason phrase");
- }
- _uri_or_reason_phrase.add(byte);
- }
- break;
-
- case _State.RESPONSE_LINE_ENDING:
- _expect(byte, _CharCode.LF);
- _messageType == _MessageType.RESPONSE;
- if (_statusCode < 100 || _statusCode > 599) {
- throw new HttpException("Invalid response status code");
- } else {
- // Check whether this response will never have a body.
- if (_statusCode <= 199 || _statusCode == 204 ||
- _statusCode == 304) {
- _noMessageBody = true;
- }
- }
- _state = _State.HEADER_START;
- break;
-
- case _State.HEADER_START:
- _headers = new _HttpHeaders(version);
- if (byte == _CharCode.CR) {
- _state = _State.HEADER_ENDING;
- } else if (byte == _CharCode.LF) {
- _state = _State.HEADER_ENDING;
- _index--; // Make the new state see the LF again.
- } else {
- // Start of new header field.
- _headerField.add(_toLowerCaseByte(byte));
- _state = _State.HEADER_FIELD;
- }
- break;
-
- case _State.HEADER_FIELD:
- if (byte == _CharCode.COLON) {
- _state = _State.HEADER_VALUE_START;
- } else {
- if (!_isTokenChar(byte)) {
- throw new HttpException("Invalid header field name");
- }
- _headerField.add(_toLowerCaseByte(byte));
- }
- break;
-
- case _State.HEADER_VALUE_START:
- if (byte == _CharCode.CR) {
- _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
- } else if (byte == _CharCode.LF) {
- _state = _State.HEADER_VALUE_FOLD_OR_END;
- } else if (byte != _CharCode.SP && byte != _CharCode.HT) {
- // Start of new header value.
- _headerValue.add(byte);
- _state = _State.HEADER_VALUE;
- }
- break;
-
- case _State.HEADER_VALUE:
- if (byte == _CharCode.CR) {
- _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
- } else if (byte == _CharCode.LF) {
- _state = _State.HEADER_VALUE_FOLD_OR_END;
- } else {
- _headerValue.add(byte);
- }
- break;
-
- case _State.HEADER_VALUE_FOLDING_OR_ENDING:
- _expect(byte, _CharCode.LF);
- _state = _State.HEADER_VALUE_FOLD_OR_END;
- break;
-
- case _State.HEADER_VALUE_FOLD_OR_END:
- if (byte == _CharCode.SP || byte == _CharCode.HT) {
- _state = _State.HEADER_VALUE_START;
- } else {
- String headerField = new String.fromCharCodes(_headerField);
- String headerValue = new String.fromCharCodes(_headerValue);
- if (headerField == "transfer-encoding" &&
- _caseInsensitiveCompare("chunked".codeUnits, _headerValue)) {
- _chunked = true;
- }
- if (headerField == "connection") {
- List<String> tokens = _tokenizeFieldValue(headerValue);
- for (int i = 0; i < tokens.length; i++) {
- if (_caseInsensitiveCompare("upgrade".codeUnits,
- tokens[i].codeUnits)) {
- _connectionUpgrade = true;
- }
- _headers._add(headerField, tokens[i]);
- }
- } else {
- _headers._add(headerField, headerValue);
- }
- _headerField.clear();
- _headerValue.clear();
-
- if (byte == _CharCode.CR) {
- _state = _State.HEADER_ENDING;
- } else if (byte == _CharCode.LF) {
- _state = _State.HEADER_ENDING;
- _index--; // Make the new state see the LF again.
- } else {
- // Start of new header field.
- _headerField.add(_toLowerCaseByte(byte));
- _state = _State.HEADER_FIELD;
- }
- }
- break;
-
- case _State.HEADER_ENDING:
- _expect(byte, _CharCode.LF);
- if (_headersEnd()) {
- return;
- } else {
- break;
- }
- return;
-
- case _State.CHUNK_SIZE_STARTING_CR:
- _expect(byte, _CharCode.CR);
- _state = _State.CHUNK_SIZE_STARTING_LF;
- break;
-
- case _State.CHUNK_SIZE_STARTING_LF:
- _expect(byte, _CharCode.LF);
- _state = _State.CHUNK_SIZE;
- break;
-
- case _State.CHUNK_SIZE:
- if (byte == _CharCode.CR) {
- _state = _State.CHUNK_SIZE_ENDING;
- } else if (byte == _CharCode.SEMI_COLON) {
- _state = _State.CHUNK_SIZE_EXTENSION;
- } else {
- int value = _expectHexDigit(byte);
- _remainingContent = _remainingContent * 16 + value;
- }
- break;
-
- case _State.CHUNK_SIZE_EXTENSION:
- if (byte == _CharCode.CR) {
- _state = _State.CHUNK_SIZE_ENDING;
- }
- break;
-
- case _State.CHUNK_SIZE_ENDING:
- _expect(byte, _CharCode.LF);
- if (_remainingContent > 0) {
- _state = _State.BODY;
- } else {
- _state = _State.CHUNKED_BODY_DONE_CR;
- }
- break;
-
- case _State.CHUNKED_BODY_DONE_CR:
- _expect(byte, _CharCode.CR);
- _state = _State.CHUNKED_BODY_DONE_LF;
- break;
-
- case _State.CHUNKED_BODY_DONE_LF:
- _expect(byte, _CharCode.LF);
- _reset();
- _closeIncoming();
- break;
-
- case _State.BODY:
- // The body is not handled one byte at a time but in blocks.
- _index--;
- int dataAvailable = _buffer.length - _index;
- if (_remainingContent >= 0 && dataAvailable > _remainingContent) {
- dataAvailable = _remainingContent;
- }
- // Always present the data as a view. This way we can handle all
- // cases like this, and the user will not experince different data
- // typed (which could lead to polymorphic user code).
- List<int> data = new Uint8List.view(_buffer.buffer,
- _buffer.offsetInBytes + _index,
- dataAvailable);
- _bodyController.add(data);
- if (_remainingContent != -1) {
- _remainingContent -= data.length;
- }
- _index += data.length;
- if (_remainingContent == 0) {
- if (!_chunked) {
- _reset();
- _closeIncoming();
- } else {
- _state = _State.CHUNK_SIZE_STARTING_CR;
- }
- }
- break;
-
- case _State.FAILURE:
- // Should be unreachable.
- assert(false);
- break;
-
- default:
- // Should be unreachable.
- assert(false);
- break;
- }
- }
-
- _parserCalled = false;
- if (_buffer != null && _index == _buffer.length) {
- // If all data is parsed release the buffer and resume receiving
- // data.
- _releaseBuffer();
- if (_state != _State.UPGRADED && _state != _State.FAILURE) {
- _socketSubscription.resume();
- }
- }
- }
-
- void _onData(List<int> buffer) {
- _socketSubscription.pause();
- assert(_buffer == null);
- _buffer = buffer;
- _index = 0;
- _parse();
- }
-
- void _onDone() {
- // onDone cancles the subscription.
- _socketSubscription = null;
- if (_state == _State.CLOSED || _state == _State.FAILURE) return;
-
- if (_incoming != null) {
- if (_state != _State.UPGRADED &&
- !(_state == _State.START && !_requestParser) &&
- !(_state == _State.BODY && !_chunked && _transferLength == -1)) {
- _bodyController.addError(
- new HttpException("Connection closed while receiving data"));
- }
- _closeIncoming(true);
- _controller.close();
- return;
- }
- // If the connection is idle the HTTP stream is closed.
- if (_state == _State.START) {
- if (!_requestParser) {
- _reportError(new HttpException(
- "Connection closed before full header was received"));
- }
- _controller.close();
- return;
- }
-
- if (_state == _State.UPGRADED) {
- _controller.close();
- return;
- }
-
- if (_state < _State.FIRST_BODY_STATE) {
- _state = _State.FAILURE;
- // Report the error through the error callback if any. Otherwise
- // throw the error.
- _reportError(new HttpException(
- "Connection closed before full header was received"));
- _controller.close();
- return;
- }
-
- if (!_chunked && _transferLength == -1) {
- _state = _State.CLOSED;
- } else {
- _state = _State.FAILURE;
- // Report the error through the error callback if any. Otherwise
- // throw the error.
- _reportError(new HttpException(
- "Connection closed before full body was received"));
- }
- _controller.close();
- }
-
- String get version {
- switch (_httpVersion) {
- case _HttpVersion.HTTP10:
- return "1.0";
- case _HttpVersion.HTTP11:
- return "1.1";
- }
- return null;
- }
-
- int get messageType => _messageType;
- int get transferLength => _transferLength;
- bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED;
- bool get persistentConnection => _persistentConnection;
-
- void set isHead(bool value) {
- if (value) _noMessageBody = true;
- }
-
- _HttpDetachedIncoming detachIncoming() {
- // Simulate detached by marking as upgraded.
- _state = _State.UPGRADED;
- return new _HttpDetachedIncoming(_socketSubscription,
- readUnparsedData());
- }
-
- List<int> readUnparsedData() {
- if (_buffer == null) return null;
- if (_index == _buffer.length) return null;
- var result = _buffer.sublist(_index);
- _releaseBuffer();
- return result;
- }
-
- void _reset() {
- if (_state == _State.UPGRADED) return;
- _state = _State.START;
- _messageType = _MessageType.UNDETERMINED;
- _headerField.clear();
- _headerValue.clear();
- _method.clear();
- _uri_or_reason_phrase.clear();
-
- _statusCode = 0;
- _statusCodeLength = 0;
-
- _httpVersion = _HttpVersion.UNDETERMINED;
- _transferLength = -1;
- _persistentConnection = false;
- _connectionUpgrade = false;
- _chunked = false;
-
- _noMessageBody = false;
- _remainingContent = -1;
-
- _headers = null;
- }
-
- void _releaseBuffer() {
- _buffer = null;
- _index = null;
- }
-
- static bool _isTokenChar(int byte) {
- return byte > 31 && byte < 128 && !_Const.SEPARATOR_MAP[byte];
- }
-
- static bool _isValueChar(int byte) {
- return (byte > 31 && byte < 128) || (byte == _CharCode.SP) ||
- (byte == _CharCode.HT);
- }
-
- static List<String> _tokenizeFieldValue(String headerValue) {
- List<String> tokens = new List<String>();
- int start = 0;
- int index = 0;
- while (index < headerValue.length) {
- if (headerValue[index] == ",") {
- tokens.add(headerValue.substring(start, index));
- start = index + 1;
- } else if (headerValue[index] == " " || headerValue[index] == "\t") {
- start++;
- }
- index++;
- }
- tokens.add(headerValue.substring(start, index));
- return tokens;
- }
-
- static int _toLowerCaseByte(int x) {
- // Optimized version:
- // - 0x41 is 'A'
- // - 0x7f is ASCII mask
- // - 26 is the number of alpha characters.
- // - 0x20 is the delta between lower and upper chars.
- return (((x - 0x41) & 0x7f) < 26) ? (x | 0x20) : x;
- }
-
- // expected should already be lowercase.
- bool _caseInsensitiveCompare(List<int> expected, List<int> value) {
- if (expected.length != value.length) return false;
- for (int i = 0; i < expected.length; i++) {
- if (expected[i] != _toLowerCaseByte(value[i])) return false;
- }
- return true;
- }
-
- int _expect(int val1, int val2) {
- if (val1 != val2) {
- throw new HttpException("Failed to parse HTTP");
- }
- }
-
- int _expectHexDigit(int byte) {
- if (0x30 <= byte && byte <= 0x39) {
- return byte - 0x30; // 0 - 9
- } else if (0x41 <= byte && byte <= 0x46) {
- return byte - 0x41 + 10; // A - F
- } else if (0x61 <= byte && byte <= 0x66) {
- return byte - 0x61 + 10; // a - f
- } else {
- throw new HttpException("Failed to parse HTTP");
- }
- }
-
- void _createIncoming(int transferLength) {
- assert(_incoming == null);
- assert(_bodyController == null);
- assert(!_bodyPaused);
- var incoming;
- _bodyController = new StreamController<List<int>>(
- sync: true,
- onListen: () {
- if (incoming != _incoming) return;
- assert(_bodyPaused);
- _bodyPaused = false;
- _pauseStateChanged();
- },
- onPause: () {
- if (incoming != _incoming) return;
- assert(!_bodyPaused);
- _bodyPaused = true;
- _pauseStateChanged();
- },
- onResume: () {
- if (incoming != _incoming) return;
- assert(_bodyPaused);
- _bodyPaused = false;
- _pauseStateChanged();
- },
- onCancel: () {
- if (incoming != _incoming) return;
- if (_socketSubscription != null) {
- _socketSubscription.cancel();
- }
- _closeIncoming(true);
- _controller.close();
- });
- incoming = _incoming = new _HttpIncoming(
- _headers, transferLength, _bodyController.stream);
- _bodyPaused = true;
- _pauseStateChanged();
- }
-
- void _closeIncoming([bool closing = false]) {
- // Ignore multiple close (can happen in re-entrance).
- if (_incoming == null) return;
- var tmp = _incoming;
- tmp.close(closing);
- _incoming = null;
- if (_bodyController != null) {
- _bodyController.close();
- _bodyController = null;
- }
- _bodyPaused = false;
- _pauseStateChanged();
- }
-
- void _pauseStateChanged() {
- if (_incoming != null) {
- if (!_bodyPaused && !_parserCalled) {
- _parse();
- }
- } else {
- if (!_paused && !_parserCalled) {
- _parse();
- }
- }
- }
-
- void _reportError(error, [stackTrace]) {
- if (_socketSubscription != null) _socketSubscription.cancel();
- _state = _State.FAILURE;
- _controller.addError(error, stackTrace);
- _controller.close();
- }
-}
« no previous file with comments | « pkg/dev_compiler/tool/input_sdk/lib/io/http_impl.dart ('k') | pkg/dev_compiler/tool/input_sdk/lib/io/http_session.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698