Chromium Code Reviews| Index: samples/chat/http_impl.dart |
| diff --git a/samples/chat/http_impl.dart b/samples/chat/http_impl.dart |
| index 84557b815badf394bafa8432dc075907b09629db..c37594cb0467c92d3972506351888994ba73abc4 100644 |
| --- a/samples/chat/http_impl.dart |
| +++ b/samples/chat/http_impl.dart |
| @@ -406,93 +406,12 @@ class HTTPParser { |
| int _remainingContent; |
| // Callbacks. |
| - var requestStart; |
| - var responseStart; |
| - var headerReceived; |
| - var headersComplete; |
| - var dataReceived; |
| - var dataEnd; |
| -} |
| - |
| - |
| -// Utility class which can deliver bytes one by one from a number of |
| -// buffers added. |
| -class _BufferList { |
| - _BufferList() : _index = 0, _length = 0, _buffers = new Queue(); |
| - |
| - void add(List<int> buffer) { |
| - _buffers.addLast(buffer); |
| - _length += buffer.length; |
| - } |
| - |
| - int next() { |
| - int value = _buffers.first()[_index++]; |
| - _length--; |
| - if (_index == _buffers.first().length) { |
| - _buffers.removeFirst(); |
| - _index = 0; |
| - } |
| - return value; |
| - } |
| - |
| - int get length() => _length; |
| - |
| - int _length; |
| - Queue<List<int>> _buffers; |
| - int _index; |
| -} |
| - |
| - |
| -// Utility class for decoding UTF-8 from data delivered as a stream of |
| -// bytes. |
| -class _UTF8Decoder { |
| - _UTF8Decoder() |
| - : _bufferList = new _BufferList(), |
| - _result = new StringBuffer(); |
| - |
| - // Add UTF-8 encoded data. |
| - int writeList(List<int> buffer) { |
| - _bufferList.add(buffer); |
| - // Only process as much data as we know is safe. |
| - while (_bufferList.length >= 4) { |
| - _processNext(); |
| - } |
| - } |
| - |
| - // Return the decoded string. |
| - String toString() { |
| - // Process any leftover data. |
| - while (_bufferList.length > 0) { |
| - _processNext(); |
| - } |
| - return _result.toString(); |
| - } |
| - |
| - // Process the next UTF-8 encoded character. |
| - void _processNext() { |
| - int value = _bufferList.next() & 0xFF; |
| - if ((value & 0x80) == 0x80) { |
| - int additionalBytes; |
| - if ((value & 0xe0) == 0xc0) { // 110xxxxx |
| - value = value & 0x1F; |
| - additionalBytes = 1; |
| - } else if ((value & 0xf0) == 0xe0) { // 1110xxxx |
| - value = value & 0x0F; |
| - additionalBytes = 2; |
| - } else { // 11110xxx |
| - value = value & 0x07; |
| - additionalBytes = 3; |
| - } |
| - for (int i = 0; i < additionalBytes; i++) { |
| - int byte = _bufferList.next(); |
| - value = value << 6 | (byte & 0x3F); |
| - } |
| - } |
| - _result.addCharCode(value); |
| - } |
| - |
| - _BufferList _bufferList; |
| - StringBuffer _result; |
| + Function requestStart; |
| + Function responseStart; |
| + Function headerReceived; |
| + Function headersComplete; |
| + Function dataReceived; |
| + Function dataEnd; |
| } |
| @@ -544,8 +463,8 @@ class _UTF8Encoder { |
| } |
| -class _HTTPRequestOrResponse { |
| - _HTTPRequestOrResponse(_HTTPConnectionBase this._httpConnection) |
| +class _HTTPRequestResponseBase { |
| + _HTTPRequestResponseBase(_HTTPConnectionBase this._httpConnection) |
| : _contentLength = -1, |
| _keepAlive = false, |
| _headers = new Map(); |
| @@ -641,23 +560,6 @@ class _HTTPRequestOrResponse { |
| _httpConnection.outputStream.write(SP); |
| } |
| - void _dataReceivedHandler(List<int> data) { |
| - // If no data received handler exists collect data as a string. |
| - if (dataReceived != null) { |
| - dataReceived(data); |
| - } else { |
| - if (_decoder == null) _decoder = new _UTF8Decoder(); |
| - _decoder.writeList(data); |
| - } |
| - } |
| - |
| - void _dataEndHandler() { |
| - if (dataEnd != null) { |
| - // Pass the string collected if any. |
| - dataEnd(_decoder != null ? _decoder.toString() : null); |
| - } |
| - } |
| - |
| _HTTPConnectionBase _httpConnection; |
| Map<String, String> _headers; |
| @@ -666,17 +568,11 @@ class _HTTPRequestOrResponse { |
| // used. |
| int _contentLength; |
| bool _keepAlive; |
| - |
| - _UTF8Decoder _decoder; |
| - |
| - // Callbacks. |
| - var dataReceived; |
| - var dataEnd; |
| } |
| // Parsed HTTP request providing information on the HTTP headers. |
| -class _HTTPRequest extends _HTTPRequestOrResponse implements HTTPRequest { |
| +class _HTTPRequest extends _HTTPRequestResponseBase implements HTTPRequest { |
| _HTTPRequest(_HTTPConnection connection) : super(connection); |
| String get method() => _method; |
| @@ -686,6 +582,13 @@ class _HTTPRequest extends _HTTPRequestOrResponse implements HTTPRequest { |
| String get queryString() => _queryString; |
| Map get queryParameters() => _queryParameters; |
| + InputStream get inputStream() { |
| + if (_inputStream == null) { |
| + _inputStream = new _HTTPInputStream(this); |
| + } |
| + return _inputStream; |
| + } |
| + |
| void _requestStartHandler(String method, String uri) { |
| _method = method; |
| _uri = uri; |
| @@ -697,7 +600,17 @@ class _HTTPRequest extends _HTTPRequestOrResponse implements HTTPRequest { |
| } |
| void _headersCompleteHandler() { |
| - // Nothing to do. |
| + // Prepare for receiving data. |
| + _buffer = new _BufferList(); |
| + } |
| + |
| + void _dataReceivedHandler(List<int> data) { |
| + _buffer.add(data); |
| + if (_inputStream != null) _inputStream._dataReceived(); |
| + } |
| + |
| + void _dataEndHandler() { |
| + if (_inputStream != null) _inputStream._closeReceived(); |
| } |
| // Escaped characters in uri are expected to have been parsed. |
| @@ -715,16 +628,34 @@ class _HTTPRequest extends _HTTPRequestOrResponse implements HTTPRequest { |
| } |
| } |
| + /* |
| + * Delegate functions for the HTTPInputStream implementation. |
|
Mads Ager (google)
2012/02/28 12:27:40
Just use '//' style comment?
Søren Gjesse
2012/02/28 13:03:42
Done.
|
| + */ |
| + int _streamAvailable() { |
| + return _buffer.length; |
| + } |
| + |
| + List<int> _streamRead(int bytesToRead) { |
| + return _buffer.readBytes(bytesToRead); |
| + } |
| + |
| + int _streamReadInto(List<int> buffer, int offset, int len) { |
| + List<int> data = _buffer.readBytes(len); |
| + buffer.setRange(offset, data.length, data); |
| + } |
| + |
| String _method; |
| String _uri; |
| String _path; |
| String _queryString; |
| Map<String, String> _queryParameters; |
| + _HTTPInputStream _inputStream; |
| + _BufferList _buffer; |
| } |
| // HTTP response object for sending a HTTP response. |
| -class _HTTPResponse extends _HTTPRequestOrResponse implements HTTPResponse { |
| +class _HTTPResponse extends _HTTPRequestResponseBase implements HTTPResponse { |
| static final int START = 0; |
| static final int HEADERS_SENT = 1; |
| static final int DONE = 2; |
| @@ -781,16 +712,22 @@ class _HTTPResponse extends _HTTPRequestOrResponse implements HTTPResponse { |
| } |
| void _streamClose() { |
| + _state = DONE; |
| // Stop tracking no pending write events. |
| _httpConnection.outputStream.noPendingWriteHandler = null; |
| - |
| // Ensure that any trailing data is written. |
| _writeDone(); |
| - _state = DONE; |
| + // If the connection is closing then close the output stream to |
| + // fully close the socket. |
| + if (_httpConnection._closing) { |
| + _httpConnection.outputStream.close(); |
| + } |
| } |
| void _streamSetNoPendingWriteHandler(callback()) { |
| - _httpConnection.outputStream.noPendingWriteHandler = callback; |
| + if (_state != DONE) { |
| + _httpConnection.outputStream.noPendingWriteHandler = callback; |
| + } |
| } |
| void _streamSetCloseHandler(callback()) { |
| @@ -894,29 +831,75 @@ class _HTTPResponse extends _HTTPRequestOrResponse implements HTTPResponse { |
| } |
| +class _HTTPInputStream extends _BaseDataInputStream implements InputStream { |
| + _HTTPInputStream(_HTTPRequestResponseBase this._requestOrResponse) { |
| + _checkScheduleCallbacks(); |
| + } |
| + |
| + int available() { |
| + return _requestOrResponse._streamAvailable(); |
| + } |
| + |
| + void pipe(OutputStream output, [bool close = true]) { |
| + _pipe(this, output, close: close); |
| + } |
| + |
| + List<int> _read(int bytesToRead) { |
| + List<int> result = _requestOrResponse._streamRead(bytesToRead); |
| + _checkScheduleCallbacks(); |
| + return result; |
| + } |
| + |
| + int _readInto(List<int> buffer, int offset, int len) { |
| + List<int> result = _requestOrResponse._streamReadInto(buffer, offset, len); |
| + _checkScheduleCallbacks(); |
| + return result; |
| + } |
| + |
| + void _close() { |
| + // TODO(sgjesse): Handle this. |
| + } |
| + |
| + void _dataReceived() { |
| + super._dataReceived(); |
| + } |
| + |
| + _HTTPRequestResponseBase _requestOrResponse; |
| +} |
| + |
| + |
| class _HTTPOutputStream implements OutputStream { |
| - _HTTPOutputStream(_HTTPRequestOrResponse this._requestOrResponse); |
| + _HTTPOutputStream(_HTTPRequestResponseBase this._requestOrResponse); |
| - bool write(List<int> buffer, [bool copyBuffer = true]) => |
| - _requestOrResponse._streamWrite(buffer, copyBuffer); |
| + bool write(List<int> buffer, [bool copyBuffer = true]) { |
| + return _requestOrResponse._streamWrite(buffer, copyBuffer); |
| + } |
| - bool writeFrom(List<int> buffer, [int offset = 0, int len]) => |
| - _requestOrResponse._streamWriteFrom(buffer, offset, len); |
| + bool writeFrom(List<int> buffer, [int offset = 0, int len]) { |
| + return _requestOrResponse._streamWriteFrom(buffer, offset, len); |
| + } |
| - void close() => _requestOrResponse._streamClose(); |
| + void close() { |
| + _requestOrResponse._streamClose(); |
| + } |
| - void destroy() { throw "Not implemented"; } |
| + void destroy() { |
| + throw "Not implemented"; |
| + } |
| - void set noPendingWriteHandler(void callback()) => |
| - _requestOrResponse._streamSetNoPendingWriteHandler(callback); |
| + void set noPendingWriteHandler(void callback()) { |
| + _requestOrResponse._streamSetNoPendingWriteHandler(callback); |
| + } |
| - void set closeHandler(void callback()) => |
| - _requestOrResponse._streamSetCloseHandler(callback); |
| + void set closeHandler(void callback()) { |
| + _requestOrResponse._streamSetCloseHandler(callback); |
| + } |
| - void set errorHandler(void callback()) => |
| - _requestOrResponse._streamSetErrorHandler(callback); |
| + void set errorHandler(void callback()) { |
| + _requestOrResponse._streamSetErrorHandler(callback); |
| + } |
| - _HTTPRequestOrResponse _requestOrResponse; |
| + _HTTPRequestResponseBase _requestOrResponse; |
| } |
| @@ -933,7 +916,6 @@ class _HTTPConnectionBase { |
| } |
| OutputStream get outputStream() { |
| - if (_socket == null) throw new HTTPException("Connection closed"); |
| return _socket.outputStream; |
| } |
| @@ -955,9 +937,9 @@ class _HTTPConnectionBase { |
| } |
| void _closeHandler() { |
| - _socket.close(); |
| - // Set to null to avoid further write attempts. |
| - _socket = null; |
| + // Client closed socket for writing. Socket should still be open |
| + // for writing the response. |
| + _closing = true; |
| if (_disconnectHandlerCallback != null) _disconnectHandlerCallback(); |
| } |
| @@ -978,6 +960,7 @@ class _HTTPConnectionBase { |
| } |
| Socket _socket; |
| + bool _closing = false; // Is the socket closed by the client? |
| HTTPParser _httpParser; |
| Queue _sendBuffers; |
| @@ -1102,7 +1085,7 @@ class _HTTPServer implements HTTPServer { |
| class _HTTPClientRequest |
| - extends _HTTPRequestOrResponse implements HTTPClientRequest { |
| + extends _HTTPRequestResponseBase implements HTTPClientRequest { |
| static final int START = 0; |
| static final int HEADERS_SENT = 1; |
| static final int DONE = 2; |
| @@ -1158,13 +1141,22 @@ class _HTTPClientRequest |
| } |
| void _streamClose() { |
| + _state = DONE; |
| + // Stop tracking no pending write events. |
| + _httpConnection.outputStream.noPendingWriteHandler = null; |
| // Ensure that any trailing data is written. |
| _writeDone(); |
| - _state = DONE; |
| + // If the connection is closing then close the output stream to |
| + // fully close the socket. |
| + if (_httpConnection._closing) { |
| + _httpConnection.outputStream.close(); |
| + } |
| } |
| void _streamSetNoPendingWriteHandler(callback()) { |
| - _httpConnection.outputStream.noPendingWriteHandler = callback; |
| + if (_state != DONE) { |
| + _httpConnection.outputStream.noPendingWriteHandler = callback; |
| + } |
| } |
| void _streamSetCloseHandler(callback()) { |
| @@ -1214,7 +1206,7 @@ class _HTTPClientRequest |
| class _HTTPClientResponse |
| - extends _HTTPRequestOrResponse implements HTTPClientResponse { |
| + extends _HTTPRequestResponseBase implements HTTPClientResponse { |
| _HTTPClientResponse(_HTTPClientConnection connection) |
| : super(connection) { |
| _connection = connection; |
| @@ -1224,6 +1216,13 @@ class _HTTPClientResponse |
| int get reasonPhrase() { return _reasonPhrase; } |
| Map get headers() => _headers; |
| + InputStream get inputStream() { |
| + if (_inputStream == null) { |
| + _inputStream = new _HTTPInputStream(this); |
| + } |
| + return _inputStream; |
| + } |
| + |
| void _requestStartHandler(String method, String uri) { |
| // TODO(sgjesse): Error handling |
| } |
| @@ -1238,16 +1237,44 @@ class _HTTPClientResponse |
| } |
| void _headersCompleteHandler() { |
| + _buffer = new _BufferList(); |
| if (_connection._responseHandler != null) { |
| _connection._responseHandler(this); |
| } |
| } |
| + void _dataReceivedHandler(List<int> data) { |
| + _buffer.add(data); |
| + if (_inputStream != null) _inputStream._dataReceived(); |
| + } |
| + |
| + void _dataEndHandler() { |
| + if (_inputStream != null) _inputStream._closeReceived(); |
| + } |
| + |
| + /* |
| + * Delegate functions for the HTTPInputStream implementation. |
|
Mads Ager (google)
2012/02/28 12:27:40
Maybe just use '//' comment.
Søren Gjesse
2012/02/28 13:03:42
Done.
|
| + */ |
| + int _streamAvailable() { |
| + return _buffer.length; |
| + } |
| + |
| + List<int> _streamRead(int bytesToRead) { |
| + return _buffer.readBytes(bytesToRead); |
| + } |
| + |
| + int _streamReadInto(List<int> buffer, int offset, int len) { |
| + List<int> data = _buffer.readBytes(len); |
| + buffer.setRange(offset, data.length, data); |
| + return data.length; |
| + } |
| + |
| int _statusCode; |
| String _reasonPhrase; |
| _HTTPClientConnection _connection; |
| - var _responseReceived; |
| + _HTTPInputStream _inputStream; |
| + _BufferList _buffer; |
| } |