33565cd64a
1. Change the argument on all onError handlers from Exception to Dynamic 2. Throw an exception if an error ocours and there is no error handler present for handling it. For sockets there is the complication that an error on a socket is reported to the socket error handler, and each of the stream error handlers. The solution to this is to throw an exception if there was no error handler on either the socket or one of the streams. Fixed a number of bugs in tests revealed by errors no longer being silently ignored. R=ager@google.com BUG=none TEST=tests/standalone/src/io/* Review URL: https://chromiumcodereview.appspot.com//10173024 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@6994 260f80e4-7a28-3924-810f-c04153c831b5
142 lines
3.7 KiB
Dart
142 lines
3.7 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
class _ChunkedInputStream implements ChunkedInputStream {
|
|
_ChunkedInputStream(InputStream this._input, [int chunkSize])
|
|
: _chunkSize = chunkSize, _bufferList = new _BufferList() {
|
|
if (_chunkSize === null) {
|
|
_chunkSize = 0;
|
|
}
|
|
_input.onClosed = _onClosed;
|
|
}
|
|
|
|
List<int> read() {
|
|
if (_closed) return null;
|
|
var result = _bufferList.readBytes(_chunkSize);
|
|
if (result == null) {
|
|
_readData();
|
|
result = _bufferList.readBytes(_chunkSize);
|
|
}
|
|
if (result == null && _inputClosed) {
|
|
if (_bufferList.length == 0) {
|
|
result = null;
|
|
} else {
|
|
result = _bufferList.readBytes(_bufferList.length);
|
|
}
|
|
}
|
|
_checkInstallDataHandler();
|
|
return result;
|
|
}
|
|
|
|
int get chunkSize() => _chunkSize;
|
|
|
|
void set chunkSize(int chunkSize) {
|
|
_chunkSize = chunkSize;
|
|
_checkInstallDataHandler();
|
|
_checkScheduleCallback();
|
|
}
|
|
|
|
bool get closed() => _closed;
|
|
|
|
void set onData(void callback()) {
|
|
_clientDataHandler = callback;
|
|
_checkInstallDataHandler();
|
|
}
|
|
|
|
void set onClosed(void callback()) {
|
|
_clientCloseHandler = callback;
|
|
}
|
|
|
|
void set onError(void callback(e)) {
|
|
_input.onError = callback;
|
|
}
|
|
|
|
void _onData() {
|
|
_readData();
|
|
if (_bufferList.length >= _chunkSize && _clientDataHandler !== null) {
|
|
_clientDataHandler();
|
|
}
|
|
_checkScheduleCallback();
|
|
_checkInstallDataHandler();
|
|
}
|
|
|
|
void _readData() {
|
|
List<int> data = _input.read();
|
|
if (data !== null) {
|
|
_bufferList.add(data);
|
|
}
|
|
}
|
|
|
|
void _onClosed() {
|
|
_inputClosed = true;
|
|
if (_bufferList.length == 0 && _clientCloseHandler !== null) {
|
|
_clientCloseHandler();
|
|
_closed = true;
|
|
} else {
|
|
_checkScheduleCallback();
|
|
}
|
|
}
|
|
|
|
void _checkInstallDataHandler() {
|
|
if (_clientDataHandler === null) {
|
|
_input.onData = null;
|
|
} else {
|
|
if (_bufferList.length < _chunkSize && !_inputClosed) {
|
|
_input.onData = _onData;
|
|
} else {
|
|
_input.onData = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _checkScheduleCallback() {
|
|
// TODO(sgjesse): Find a better way of scheduling callbacks from
|
|
// the event loop.
|
|
void issueDataCallback(Timer timer) {
|
|
_scheduledDataCallback = null;
|
|
if (_clientDataHandler !== null) {
|
|
_clientDataHandler();
|
|
_checkScheduleCallback();
|
|
}
|
|
}
|
|
|
|
void issueCloseCallback(Timer timer) {
|
|
_scheduledCloseCallback = null;
|
|
if (!_closed) {
|
|
if (_clientCloseHandler !== null) _clientCloseHandler();
|
|
_closed = true;
|
|
}
|
|
}
|
|
|
|
// Schedule data callback if enough data in buffer.
|
|
if ((_bufferList.length >= _chunkSize ||
|
|
(_bufferList.length > 0 && _inputClosed)) &&
|
|
_clientDataHandler !== null &&
|
|
_scheduledDataCallback == null) {
|
|
_scheduledDataCallback = new Timer(0, issueDataCallback);
|
|
}
|
|
|
|
// Schedule close callback if no more data and input is closed.
|
|
if (_bufferList.length == 0 &&
|
|
_inputClosed &&
|
|
!_closed &&
|
|
_scheduledCloseCallback == null) {
|
|
if (_scheduledDataCallback != null) {
|
|
_scheduledDataCallback.cancel();
|
|
}
|
|
_scheduledCloseCallback = new Timer(0, issueCloseCallback);
|
|
}
|
|
}
|
|
|
|
InputStream _input;
|
|
_BufferList _bufferList;
|
|
int _chunkSize;
|
|
bool _inputClosed = false; // Is the underlying input stream closed?
|
|
bool _closed = false; // Has the close handler been called?.
|
|
Timer _scheduledDataCallback;
|
|
Timer _scheduledCloseCallback;
|
|
Function _clientDataHandler;
|
|
Function _clientCloseHandler;
|
|
}
|