Slightly speed up http-parser and http-header-writing.

BUG=
R=sgjesse@google.com

Review URL: https://codereview.chromium.org//173683002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32850 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ajohnsen@google.com 2014-02-20 14:47:25 +00:00
parent 9635777fe0
commit 04c6eca951
3 changed files with 54 additions and 39 deletions

View file

@ -396,25 +396,31 @@ class _HttpHeaders implements HttpHeaders {
}
// Format headers.
_headers.forEach((String name, List<String> values) {
for (String name in _headers.keys) {
List<String> values = _headers[name];
bool fold = _foldHeader(name);
var nameData = name.codeUnits;
write(nameData);
write(const [_CharCode.COLON, _CharCode.SP]);
buffer[offset++] = _CharCode.COLON;
buffer[offset++] = _CharCode.SP;
for (int i = 0; i < values.length; i++) {
if (i > 0) {
if (fold) {
write(const [_CharCode.COMMA, _CharCode.SP]);
buffer[offset++] = _CharCode.COMMA;
buffer[offset++] = _CharCode.SP;
} else {
write(const [_CharCode.CR, _CharCode.LF]);
buffer[offset++] = _CharCode.CR;
buffer[offset++] = _CharCode.LF;
write(nameData);
write(const [_CharCode.COLON, _CharCode.SP]);
buffer[offset++] = _CharCode.COLON;
buffer[offset++] = _CharCode.SP;
}
}
write(values[i].codeUnits);
}
write(const [_CharCode.CR, _CharCode.LF]);
});
buffer[offset++] = _CharCode.CR;
buffer[offset++] = _CharCode.LF;
}
return offset;
}

View file

@ -1333,7 +1333,7 @@ class _HttpClientConnection {
}
// Start sending the request (lazy, delayed until the user provides
// data).
_httpParser.responseToMethod = method;
_httpParser.isHead = method == "HEAD";
_streamFuture = outgoing.done
.then((s) {
// Request sent, set up response completer.

View file

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