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"); |