| Index: sdk/lib/io/http_impl.dart
|
| diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
|
| index a145e39b086b163f6d638dee158a2a33208a6d4d..7db646bc24097854bc8e2fdfed802ca1dda69f62 100644
|
| --- a/sdk/lib/io/http_impl.dart
|
| +++ b/sdk/lib/io/http_impl.dart
|
| @@ -332,7 +332,7 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
|
|
| _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing)
|
| : _outgoing = outgoing,
|
| - _ioSink = new IOSink(outgoing),
|
| + _ioSink = new IOSink(outgoing, encoding: Encoding.ASCII),
|
| headers = new _HttpHeaders(protocolVersion);
|
|
|
| int get contentLength => headers.contentLength;
|
| @@ -345,38 +345,85 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
| headers.persistentConnection = p;
|
| }
|
|
|
| - Future<T> consume(Stream<List<int>> stream) {
|
| + Encoding get encoding {
|
| + var charset;
|
| + if (headers.contentType != null && headers.contentType.charset != null) {
|
| + charset = headers.contentType.charset;
|
| + } else {
|
| + charset = "iso-8859-1";
|
| + }
|
| + return Encoding.fromName(charset);
|
| + }
|
| +
|
| + void set encoding(Encoding value) {
|
| + throw new StateError("IOSink encoding is not mutable");
|
| + }
|
| +
|
| + void write(Object obj) {
|
| _writeHeaders();
|
| - if (_ignoreBody) return new Future.immediate(this);
|
| + if (_ignoreBody) return;
|
| + // This comment is copied from runtime/lib/string_buffer_patch.dart.
|
| + // TODO(srdjan): The following four lines could be replaced by
|
| + // '$obj', but apparently this is too slow on the Dart VM.
|
| + String string;
|
| + if (obj is String) {
|
| + string = obj;
|
| + } else {
|
| + string = obj.toString();
|
| + if (string is! String) {
|
| + throw new ArgumentError('toString() did not return a string');
|
| + }
|
| + }
|
| + if (string.isEmpty) return;
|
| if (_chunked) {
|
| - // Transform when chunked.
|
| - stream = stream.transform(new _ChunkedTransformer());
|
| + _ChunkedTransformer._addChunk(_encodeString(string, encoding),
|
| + _ioSink.writeBytes);
|
| + } else {
|
| + _ioSink.write(string);
|
| }
|
| - return _ioSink.consume(stream).then((_) => this);
|
| }
|
|
|
| - void add(List<int> data) {
|
| + void writeAll(Iterable objects) {
|
| + for (Object obj in objects) write(obj);
|
| + }
|
| +
|
| + void writeln(Object obj) {
|
| + write(obj);
|
| + write("\n");
|
| + }
|
| +
|
| + void writeCharCode(int charCode) {
|
| + write(new String.fromCharCode(charCode));
|
| + }
|
| +
|
| + void writeBytes(List<int> data) {
|
| _writeHeaders();
|
| if (_ignoreBody || data.length == 0) return;
|
| if (_chunked) {
|
| - _ChunkedTransformer._addChunk(data, _ioSink.add);
|
| + _ChunkedTransformer._addChunk(data, _ioSink.writeBytes);
|
| } else {
|
| - _ioSink.add(data);
|
| + _ioSink.writeBytes(data);
|
| }
|
| }
|
|
|
| - void addString(String string, [Encoding encoding = Encoding.UTF_8]) {
|
| - add(_encodeString(string, encoding));
|
| + Future<T> consume(Stream<List<int>> stream) {
|
| + _writeHeaders();
|
| + if (_ignoreBody) return new Future.immediate(this);
|
| + if (_chunked) {
|
| + // Transform when chunked.
|
| + stream = stream.transform(new _ChunkedTransformer());
|
| + }
|
| + return _ioSink.consume(stream).then((_) => this);
|
| }
|
|
|
| - Future<T> addStream(Stream<List<int>> stream) {
|
| + Future<T> writeStream(Stream<List<int>> stream) {
|
| _writeHeaders();
|
| if (_ignoreBody) return new Future.immediate(this);
|
| if (_chunked) {
|
| // Transform when chunked.
|
| stream = stream.transform(new _ChunkedTransformer(writeEnd: false));
|
| }
|
| - return _ioSink.addStream(stream).then((_) => this);
|
| + return _ioSink.writeStream(stream).then((_) => this);
|
| }
|
|
|
| void close() {
|
| @@ -388,7 +435,7 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
| _writeHeaders();
|
| if (!_ignoreBody) {
|
| if (_chunked) {
|
| - _ChunkedTransformer._addChunk([], _ioSink.add);
|
| + _ChunkedTransformer._addChunk([], _ioSink.writeBytes);
|
| }
|
| }
|
| _ioSink.close();
|
| @@ -399,7 +446,9 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
| void _writeHeaders() {
|
| if (_headersWritten) return;
|
| _headersWritten = true;
|
| + _ioSink.encoding = Encoding.ASCII;
|
| _writeHeader();
|
| + _ioSink.encoding = encoding;
|
| if (_ignoreBody) {
|
| _ioSink.close();
|
| return;
|
| @@ -452,19 +501,19 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
|
|
|
| void _writeHeader() {
|
| - writeSP() => _ioSink.add([_CharCode.SP]);
|
| - writeCRLF() => _ioSink.add([_CharCode.CR, _CharCode.LF]);
|
| + writeSP() => _ioSink.writeBytes([_CharCode.SP]);
|
| + writeCRLF() => _ioSink.writeBytes([_CharCode.CR, _CharCode.LF]);
|
|
|
| // Write status line.
|
| if (headers.protocolVersion == "1.1") {
|
| - _ioSink.add(_Const.HTTP11);
|
| + _ioSink.writeBytes(_Const.HTTP11);
|
| } else {
|
| - _ioSink.add(_Const.HTTP10);
|
| + _ioSink.writeBytes(_Const.HTTP10);
|
| }
|
| writeSP();
|
| - _ioSink.addString(statusCode.toString());
|
| + _ioSink.write(statusCode.toString());
|
| writeSP();
|
| - _ioSink.addString(reasonPhrase);
|
| + _ioSink.write(reasonPhrase);
|
| writeCRLF();
|
|
|
| var session = _httpRequest._session;
|
| @@ -645,10 +694,10 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientRequest>
|
| }
|
|
|
| void _writeHeader() {
|
| - writeSP() => _ioSink.add([_CharCode.SP]);
|
| - writeCRLF() => _ioSink.add([_CharCode.CR, _CharCode.LF]);
|
| + writeSP() => _ioSink.writeBytes([_CharCode.SP]);
|
| + writeCRLF() => _ioSink.writeBytes([_CharCode.CR, _CharCode.LF]);
|
|
|
| - _ioSink.addString(method);
|
| + _ioSink.write(method);
|
| writeSP();
|
| // Send the path for direct connections and the whole URL for
|
| // proxy connections.
|
| @@ -662,12 +711,12 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientRequest>
|
| path = "${path}?${uri.query}";
|
| }
|
| }
|
| - _ioSink.addString(path);
|
| + _ioSink.write(path);
|
| } else {
|
| - _ioSink.addString(uri.toString());
|
| + _ioSink.write(uri.toString());
|
| }
|
| writeSP();
|
| - _ioSink.add(_Const.HTTP11);
|
| + _ioSink.writeBytes(_Const.HTTP11);
|
| writeCRLF();
|
|
|
| // Add the cookies to the headers.
|
| @@ -775,7 +824,8 @@ class _DataValidatorTransformer
|
| _controller.signalError(new HttpException(
|
| "Content size exceeds specified contentLength. "
|
| "$_bytesWritten bytes written while expected "
|
| - "$expectedTransferLength."));
|
| + "$expectedTransferLength. "
|
| + "[${new String.fromCharCodes(data)}]"));
|
| _controller.close();
|
| return;
|
| }
|
| @@ -901,7 +951,7 @@ class _HttpClientConnection {
|
| // Sending request, set up response completer.
|
| _nextResponseCompleter = new Completer();
|
|
|
| - var requestFuture = _socket.addStream(stream)
|
| + var requestFuture = _socket.writeStream(stream)
|
| .catchError((e) {
|
| destroy();
|
| throw e;
|
| @@ -1228,7 +1278,7 @@ class _HttpConnection {
|
| outgoing);
|
| var request = new _HttpRequest(response, incoming, _httpServer, this);
|
| outgoing.onStream((stream) {
|
| - return _streamFuture = _socket.addStream(stream)
|
| + return _streamFuture = _socket.writeStream(stream)
|
| .then((_) {
|
| if (_state == _DETACHED) return;
|
| if (response.persistentConnection &&
|
| @@ -1509,24 +1559,40 @@ class _DetachedSocket extends Stream<List<int>> implements Socket {
|
| unsubscribeOnError: unsubscribeOnError);
|
| }
|
|
|
| - Future<Socket> consume(Stream<List<int>> stream) {
|
| - return _socket.consume(stream);
|
| + Encoding get encoding => _socket.encoding;
|
| +
|
| + void set encoding(Encoding value) {
|
| + _socket.encoding = value;
|
| }
|
|
|
| - Future<Socket> addStream(Stream<List<int>> stream) {
|
| - return _socket.addStream(stream);
|
| + void write(Object obj) => _socket.write(obj);
|
| +
|
| + void writeln(Object obj) => _socket.writeln(obj);
|
| +
|
| + void writeCharCode(int charCode) => _socket.writeCharCode(charCode);
|
| +
|
| + void writeAll(Iterable objects) => _socket.writeAll(objects);
|
| +
|
| + void writeBytes(List<int> bytes) => _socket.writeBytes(bytes);
|
| +
|
| + Future<Socket> consume(Stream<List<int>> stream) {
|
| + return _socket.consume(stream);
|
| }
|
|
|
| - void addString(String string, [Encoding encoding = Encoding.UTF_8]) {
|
| - return _socket.addString(string, encoding);
|
| + Future<Socket> writeStream(Stream<List<int>> stream) {
|
| + return _socket.writeStream(stream);
|
| }
|
|
|
| void destroy() => _socket.destroy();
|
| - void add(List<int> data) => _socket.add(data);
|
| +
|
| void close() => _socket.close();
|
| +
|
| Future<Socket> get done => _socket.done;
|
| +
|
| int get port => _socket.port;
|
| +
|
| String get remoteHost => _socket.remoteHost;
|
| +
|
| int get remotePort => _socket.remotePort;
|
| }
|
|
|
|
|