Index: sdk/lib/io/http_parser.dart |
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart |
index a5549c5d3a519fceace71023d934c2330baab503..61e0a64a588e34fc9111455ccda531969c1bc8bb 100644 |
--- a/sdk/lib/io/http_parser.dart |
+++ b/sdk/lib/io/http_parser.dart |
@@ -116,11 +116,12 @@ class _MessageType { |
* 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 call to |
- * [:writeList:] causing the upgrade will return with the number of |
- * bytes parsed as HTTP. Any unparsed bytes is part of the protocol |
- * the connection is upgrading to and should be handled according to |
- * that protocol. |
+ * 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 { |
_HttpParser() { |
@@ -136,9 +137,7 @@ class _HttpParser { |
// 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 ] |
- int writeList(List<int> buffer, int offset, int count) { |
- int index = offset; |
- int lastIndex = offset + count; |
+ void _parse() { |
try { |
if (_state == _State.CLOSED) { |
throw new HttpParserException("Data on closed connection"); |
@@ -149,10 +148,11 @@ class _HttpParser { |
if (_state == _State.FAILURE) { |
throw new HttpParserException("Data on failed connection"); |
} |
- while ((index < lastIndex) && |
+ while (_buffer != null && |
+ _index < _lastIndex && |
_state != _State.FAILURE && |
_state != _State.UPGRADED) { |
- int byte = buffer[index]; |
+ int byte = _buffer[_index++]; |
switch (_state) { |
case _State.START: |
if (byte == _Const.HTTP[0]) { |
@@ -325,7 +325,9 @@ class _HttpParser { |
statusCode <= 199 || statusCode == 204 || statusCode == 304; |
} |
if (responseStart != null) { |
- responseStart(statusCode, _uri_or_reason_phrase.toString(), version); |
+ responseStart(statusCode, |
+ _uri_or_reason_phrase.toString(), |
+ version); |
} |
_method_or_status_code.clear(); |
_uri_or_reason_phrase.clear(); |
@@ -438,8 +440,6 @@ class _HttpParser { |
} |
if (_connectionUpgrade) { |
_state = _State.UPGRADED; |
- _unparsedData = |
- buffer.getRange(index + 1, count - (index + 1 - offset)); |
if (headersComplete != null) headersComplete(); |
} else { |
if (headersComplete != null) headersComplete(); |
@@ -513,22 +513,23 @@ class _HttpParser { |
case _State.BODY: |
// The body is not handled one byte at a time but in blocks. |
- int dataAvailable = lastIndex - index; |
+ _index--; |
+ int dataAvailable = _lastIndex - _index; |
List<int> data; |
if (_remainingContent == null || |
dataAvailable <= _remainingContent) { |
data = new Uint8List(dataAvailable); |
- data.setRange(0, dataAvailable, buffer, index); |
+ data.setRange(0, dataAvailable, _buffer, _index); |
} else { |
data = new Uint8List(_remainingContent); |
- data.setRange(0, _remainingContent, buffer, index); |
+ data.setRange(0, _remainingContent, _buffer, _index); |
} |
if (dataReceived != null) dataReceived(data); |
if (_remainingContent != null) { |
_remainingContent -= data.length; |
} |
- index += data.length; |
+ _index += data.length; |
if (_remainingContent == 0) { |
if (!_chunked) { |
_bodyEnd(); |
@@ -537,9 +538,6 @@ class _HttpParser { |
_state = _State.CHUNK_SIZE_STARTING_CR; |
} |
} |
- |
- // Hack - as we always do index++ below. |
- index--; |
break; |
case _State.FAILURE: |
@@ -552,9 +550,6 @@ class _HttpParser { |
assert(false); |
break; |
} |
- |
- // Move to the next byte. |
- index++; |
} |
} catch (e) { |
// Report the error through the error callback if any. Otherwise |
@@ -567,8 +562,17 @@ class _HttpParser { |
} |
} |
- // Return the number of bytes parsed. |
- return index - offset; |
+ // If all data is parsed or not needed due to failure there is no |
+ // need to hold on to the buffer. |
+ if (_state != _State.UPGRADED) _releaseBuffer(); |
+ } |
+ |
+ void writeList(List<int> buffer, int offset, int count) { |
+ assert(_buffer == null); |
+ _buffer = buffer; |
+ _index = offset; |
+ _lastIndex = offset + count; |
+ _parse(); |
} |
void connectionClosed() { |
@@ -623,7 +627,13 @@ class _HttpParser { |
bool get isIdle => _state == _State.START; |
- List<int> get unparsedData => _unparsedData; |
+ List<int> readUnparsedData() { |
+ if (_buffer == null) return []; |
+ if (_index == _lastIndex) return []; |
+ var result = _buffer.getRange(_index, _lastIndex - _index); |
+ _releaseBuffer(); |
+ return result; |
+ } |
void _bodyEnd() { |
if (dataEnd != null) { |
@@ -650,6 +660,12 @@ class _HttpParser { |
_remainingContent = null; |
} |
+ _releaseBuffer() { |
+ _buffer = null; |
+ _index = null; |
+ _lastIndex = null; |
+ } |
+ |
bool _isTokenChar(int byte) { |
return byte > 31 && byte < 128 && _Const.SEPARATORS.indexOf(byte) == -1; |
} |
@@ -696,6 +712,11 @@ class _HttpParser { |
} |
} |
+ // The data that is currently being parsed. |
+ List<int> _buffer; |
+ int _index; |
+ int _lastIndex; |
+ |
int _state; |
int _httpVersionIndex; |
int _messageType; |
@@ -714,7 +735,6 @@ class _HttpParser { |
String _responseToMethod; // Indicates the method used for the request. |
int _remainingContent; |
- List<int> _unparsedData; // Unparsed data after connection upgrade. |
// Callbacks. |
Function requestStart; |
Function responseStart; |