| Index: sdk/lib/io/http_parser.dart
|
| diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
|
| index 4e3ede1d0be829e57ba573a1901bb873ef32cb85..2888138174a0c1b0fd665256d6202b2d1ea9987c 100644
|
| --- a/sdk/lib/io/http_parser.dart
|
| +++ b/sdk/lib/io/http_parser.dart
|
| @@ -247,10 +247,11 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| int _httpVersionIndex;
|
| int _messageType;
|
| int _statusCode = 0;
|
| - List _method_or_status_code;
|
| - List _uri_or_reason_phrase;
|
| - List _headerField;
|
| - List _headerValue;
|
| + 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;
|
| @@ -258,8 +259,7 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| bool _connectionUpgrade;
|
| bool _chunked;
|
|
|
| - bool _noMessageBody;
|
| - String _responseToMethod; // Indicates the method used for the request.
|
| + bool _noMessageBody = false;
|
| int _remainingContent = -1;
|
|
|
| _HttpHeaders _headers;
|
| @@ -374,7 +374,7 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| if (!_isTokenChar(byte)) {
|
| throw new HttpException("Invalid request method");
|
| }
|
| - _method_or_status_code.add(byte);
|
| + _method.add(byte);
|
| if (!_requestParser) {
|
| throw new HttpException("Invalid response line");
|
| }
|
| @@ -399,12 +399,12 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| } else {
|
| // Did not parse HTTP version. Expect method instead.
|
| for (int i = 0; i < _httpVersionIndex; i++) {
|
| - _method_or_status_code.add(_Const.HTTP[i]);
|
| + _method.add(_Const.HTTP[i]);
|
| }
|
| if (byte == _CharCode.SP) {
|
| _state = _State.REQUEST_LINE_URI;
|
| } else {
|
| - _method_or_status_code.add(byte);
|
| + _method.add(byte);
|
| _httpVersion = _HttpVersion.UNDETERMINED;
|
| if (!_requestParser) {
|
| throw new HttpException("Invalid response line");
|
| @@ -449,7 +449,7 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| byte == _CharCode.LF) {
|
| throw new HttpException("Invalid request method");
|
| }
|
| - _method_or_status_code.add(byte);
|
| + _method.add(byte);
|
| }
|
| break;
|
|
|
| @@ -500,19 +500,17 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
|
|
| case _State.RESPONSE_LINE_STATUS_CODE:
|
| if (byte == _CharCode.SP) {
|
| - if (_method_or_status_code.length != 3) {
|
| - throw new HttpException("Invalid response status code");
|
| - }
|
| _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 {
|
| - if (byte < 0x30 && 0x39 < byte) {
|
| + _statusCodeLength++;
|
| + if ((byte < 0x30 && 0x39 < byte) || _statusCodeLength > 3) {
|
| throw new HttpException("Invalid response status code");
|
| } else {
|
| - _method_or_status_code.add(byte);
|
| + _statusCode = _statusCode * 10 + byte - 0x30;
|
| }
|
| }
|
| break;
|
| @@ -531,14 +529,14 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| case _State.RESPONSE_LINE_ENDING:
|
| _expect(byte, _CharCode.LF);
|
| _messageType == _MessageType.RESPONSE;
|
| - _statusCode = int.parse(
|
| - new String.fromCharCodes(_method_or_status_code));
|
| if (_statusCode < 100 || _statusCode > 599) {
|
| throw new HttpException("Invalid response status code");
|
| } else {
|
| // Check whether this response will never have a body.
|
| - _noMessageBody = _statusCode <= 199 || _statusCode == 204 ||
|
| - _statusCode == 304;
|
| + if (_statusCode <= 199 || _statusCode == 204 ||
|
| + _statusCode == 304) {
|
| + _noMessageBody = true;
|
| + }
|
| }
|
| _state = _State.HEADER_START;
|
| break;
|
| @@ -595,13 +593,14 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| String headerField = new String.fromCharCodes(_headerField);
|
| String headerValue = new String.fromCharCodes(_headerValue);
|
| if (headerField == "transfer-encoding" &&
|
| - headerValue.toLowerCase() == "chunked") {
|
| + _caseInsensitiveCompare("chunked".codeUnits, _headerValue)) {
|
| _chunked = true;
|
| }
|
| if (headerField == "connection") {
|
| List<String> tokens = _tokenizeFieldValue(headerValue);
|
| for (int i = 0; i < tokens.length; i++) {
|
| - if (tokens[i].toLowerCase() == "upgrade") {
|
| + if (_caseInsensitiveCompare("upgrade".codeUnits,
|
| + tokens[i].codeUnits)) {
|
| _connectionUpgrade = true;
|
| }
|
| _headers._add(headerField, tokens[i]);
|
| @@ -646,7 +645,7 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| _createIncoming(_transferLength);
|
| if (_requestParser) {
|
| _incoming.method =
|
| - new String.fromCharCodes(_method_or_status_code);
|
| + new String.fromCharCodes(_method);
|
| _incoming.uri =
|
| Uri.parse(
|
| new String.fromCharCodes(_uri_or_reason_phrase));
|
| @@ -655,7 +654,7 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| _incoming.reasonPhrase =
|
| new String.fromCharCodes(_uri_or_reason_phrase);
|
| }
|
| - _method_or_status_code.clear();
|
| + _method.clear();
|
| _uri_or_reason_phrase.clear();
|
| if (_connectionUpgrade) {
|
| _incoming.upgraded = true;
|
| @@ -666,8 +665,7 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| return;
|
| }
|
| if (_transferLength == 0 ||
|
| - (_messageType == _MessageType.RESPONSE &&
|
| - (_noMessageBody || _responseToMethod == "HEAD"))) {
|
| + (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
|
| _reset();
|
| var tmp = _incoming;
|
| _closeIncoming();
|
| @@ -866,7 +864,9 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED;
|
| bool get persistentConnection => _persistentConnection;
|
|
|
| - void set responseToMethod(String method) { _responseToMethod = method; }
|
| + void set isHead(bool value) {
|
| + if (value) _noMessageBody = true;
|
| + }
|
|
|
| _HttpDetachedIncoming detachIncoming() {
|
| // Simulate detached by marking as upgraded.
|
| @@ -887,12 +887,13 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| if (_state == _State.UPGRADED) return;
|
| _state = _State.START;
|
| _messageType = _MessageType.UNDETERMINED;
|
| - _headerField = new List();
|
| - _headerValue = new List();
|
| - _method_or_status_code = new List();
|
| - _uri_or_reason_phrase = new List();
|
| + _headerField.clear();
|
| + _headerValue.clear();
|
| + _method.clear();
|
| + _uri_or_reason_phrase.clear();
|
|
|
| _statusCode = 0;
|
| + _statusCodeLength = 0;
|
|
|
| _httpVersion = _HttpVersion.UNDETERMINED;
|
| _transferLength = -1;
|
| @@ -901,7 +902,6 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| _chunked = false;
|
|
|
| _noMessageBody = false;
|
| - _responseToMethod = null;
|
| _remainingContent = -1;
|
|
|
| _headers = null;
|
| @@ -940,6 +940,15 @@ class _HttpParser extends Stream<_HttpIncoming> {
|
| return (aCode <= byte && byte <= zCode) ? byte + delta : byte;
|
| }
|
|
|
| + // 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] != _toLowerCase(value[i])) return false;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| int _expect(int val1, int val2) {
|
| if (val1 != val2) {
|
| throw new HttpException("Failed to parse HTTP");
|
|
|