| Index: sdk/lib/io/http_parser.dart
|
| diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
|
| index 09f06eaee38b5cff19d0d0095850d4c2a9ac0ddc..e7415cf49e33e90a216bbad1d559f65363a8afe2 100644
|
| --- a/sdk/lib/io/http_parser.dart
|
| +++ b/sdk/lib/io/http_parser.dart
|
| @@ -334,6 +334,74 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| }
|
| }
|
|
|
| + // 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)
|
| @@ -487,8 +555,13 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| throw new HttpException("Invalid response line");
|
| }
|
| } else {
|
| - _expect(byte, _CharCode.CR);
|
| - _state = _State.REQUEST_LINE_ENDING;
|
| + if (byte == _CharCode.CR) {
|
| + _state = _State.REQUEST_LINE_ENDING;
|
| + } else {
|
| + _expect(byte, _CharCode.LF);
|
| + _messageType = _MessageType.REQUEST;
|
| + _state = _State.HEADER_START;
|
| + }
|
| }
|
| break;
|
|
|
| @@ -545,6 +618,12 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| _headers = new _HttpHeaders(version);
|
| if (byte == _CharCode.CR) {
|
| _state = _State.HEADER_ENDING;
|
| + } else if (byte == _CharCode.LF) {
|
| + if (_headersEnd()) {
|
| + return;
|
| + } else {
|
| + break;
|
| + }
|
| } else {
|
| // Start of new header field.
|
| _headerField.add(_toLowerCaseByte(byte));
|
| @@ -566,6 +645,8 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| 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);
|
| @@ -576,6 +657,8 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| 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);
|
| }
|
| @@ -613,6 +696,12 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
|
|
| if (byte == _CharCode.CR) {
|
| _state = _State.HEADER_ENDING;
|
| + } else if (byte == _CharCode.LF) {
|
| + if (_headersEnd()) {
|
| + return;
|
| + } else {
|
| + break;
|
| + }
|
| } else {
|
| // Start of new header field.
|
| _headerField.add(_toLowerCaseByte(byte));
|
| @@ -623,67 +712,11 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
|
|
| case _State.HEADER_ENDING:
|
| _expect(byte, _CharCode.LF);
|
| - _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);
|
| + if (_headersEnd()) {
|
| return;
|
| - }
|
| - if (_transferLength == 0 ||
|
| - (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
|
| - _reset();
|
| - var tmp = _incoming;
|
| - _closeIncoming();
|
| - _controller.add(tmp);
|
| - break;
|
| - } 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;
|
| + break;
|
| }
|
| - _parserCalled = false;
|
| - _controller.add(_incoming);
|
| return;
|
|
|
| case _State.CHUNK_SIZE_STARTING_CR:
|
|
|