| Index: sdk/lib/io/http_impl.dart
|
| diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
|
| index 458333d3475d6d05bb43804d600e0bd42901e3ad..7f7a73825dc91337f65b66bcd3a054584e2d1ba0 100644
|
| --- a/sdk/lib/io/http_impl.dart
|
| +++ b/sdk/lib/io/http_impl.dart
|
| @@ -4,6 +4,8 @@
|
|
|
| part of dart.io;
|
|
|
| +const int _HEADERS_BUFFER_SIZE = 8 * 1024;
|
| +
|
| class _HttpIncoming extends Stream<List<int>> {
|
| final int _transferLength;
|
| final Completer _dataCompleter = new Completer();
|
| @@ -479,6 +481,15 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
| Future<T> get done => _dataSink.done;
|
|
|
| Future _writeHeaders({bool drainRequest: true}) {
|
| + void write() {
|
| + try {
|
| + _writeHeader();
|
| + } catch (error) {
|
| + // Headers too large.
|
| + throw new HttpException(
|
| + "Headers size exceeded the of '$_HEADERS_BUFFER_SIZE' bytes");
|
| + }
|
| + }
|
| if (_headersWritten) return new Future.value();
|
| _headersWritten = true;
|
| headers._synchronize(); // Be sure the 'chunked' option is updated.
|
| @@ -503,10 +514,10 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
| return response._httpRequest.drain()
|
| // TODO(ajohnsen): Timeout on drain?
|
| .catchError((_) {}) // Ignore errors.
|
| - .then((_) => _writeHeader());
|
| + .then((_) => write());
|
| }
|
| }
|
| - return new Future.sync(_writeHeader);
|
| + return new Future.sync(write);
|
| }
|
|
|
| Future _addStream(Stream<List<int>> stream) {
|
| @@ -549,10 +560,10 @@ abstract class _HttpOutboundMessage<T> implements IOSink {
|
| return _headersSink.done;
|
| }
|
| }
|
| - return _writeHeaders().then((_) => _headersSink.close());
|
| + return _writeHeaders().whenComplete(_headersSink.close);
|
| }
|
|
|
| - void _writeHeader(); // TODO(ajohnsen): Better name.
|
| + void _writeHeader();
|
| }
|
|
|
|
|
| @@ -769,21 +780,29 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| }
|
|
|
| void _writeHeader() {
|
| - var builder = new BytesBuilder();
|
| - writeSP() => builder.add(const [_CharCode.SP]);
|
| - writeCRLF() => builder.add(const [_CharCode.CR, _CharCode.LF]);
|
| + Uint8List buffer = _httpRequest._httpConnection._headersBuffer;
|
| + int offset = 0;
|
| +
|
| + void write(List<int> bytes) {
|
| + int len = bytes.length;
|
| + for (int i = 0; i < len; i++) {
|
| + buffer[offset + i] = bytes[i];
|
| + }
|
| + offset += len;
|
| + }
|
|
|
| // Write status line.
|
| if (headers.protocolVersion == "1.1") {
|
| - builder.add(_Const.HTTP11);
|
| + write(_Const.HTTP11);
|
| } else {
|
| - builder.add(_Const.HTTP10);
|
| + write(_Const.HTTP10);
|
| }
|
| - writeSP();
|
| - builder.add(statusCode.toString().codeUnits);
|
| - writeSP();
|
| - builder.add(reasonPhrase.codeUnits);
|
| - writeCRLF();
|
| + buffer[offset++] = _CharCode.SP;
|
| + write(statusCode.toString().codeUnits);
|
| + buffer[offset++] = _CharCode.SP;
|
| + write(reasonPhrase.codeUnits);
|
| + buffer[offset++] = _CharCode.CR;
|
| + buffer[offset++] = _CharCode.LF;
|
|
|
| var session = _httpRequest._session;
|
| if (session != null && !session._destroyed) {
|
| @@ -816,9 +835,10 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| headers._finalize();
|
|
|
| // Write headers.
|
| - headers._write(builder);
|
| - writeCRLF();
|
| - _headersSink.add(builder.takeBytes());
|
| + offset = headers._write(buffer, offset);
|
| + buffer[offset++] = _CharCode.CR;
|
| + buffer[offset++] = _CharCode.LF;
|
| + _headersSink.add(new Uint8List.view(buffer.buffer, 0, offset));
|
| }
|
|
|
| String _findReasonPhrase(int statusCode) {
|
| @@ -1012,21 +1032,27 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| }
|
|
|
| void _writeHeader() {
|
| - var builder = new BytesBuilder();
|
| -
|
| - writeSP() => builder.add(const [_CharCode.SP]);
|
| + Uint8List buffer = _httpClientConnection._headersBuffer;
|
| + int offset = 0;
|
|
|
| - writeCRLF() => builder.add(const [_CharCode.CR, _CharCode.LF]);
|
| + void write(List<int> bytes) {
|
| + int len = bytes.length;
|
| + for (int i = 0; i < len; i++) {
|
| + buffer[offset + i] = bytes[i];
|
| + }
|
| + offset += len;
|
| + }
|
|
|
| // Write the request method.
|
| - builder.add(method.codeUnits);
|
| - writeSP();
|
| + write(method.codeUnits);
|
| + buffer[offset++] = _CharCode.SP;
|
| // Write the request URI.
|
| - builder.add(_requestUri().codeUnits);
|
| - writeSP();
|
| + write(_requestUri().codeUnits);
|
| + buffer[offset++] = _CharCode.SP;
|
| // Write HTTP/1.1.
|
| - builder.add(_Const.HTTP11);
|
| - writeCRLF();
|
| + write(_Const.HTTP11);
|
| + buffer[offset++] = _CharCode.CR;
|
| + buffer[offset++] = _CharCode.LF;
|
|
|
| // Add the cookies to the headers.
|
| if (!cookies.isEmpty) {
|
| @@ -1043,9 +1069,10 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| headers._finalize();
|
|
|
| // Write headers.
|
| - headers._write(builder);
|
| - writeCRLF();
|
| - _headersSink.add(builder.takeBytes());
|
| + offset = headers._write(buffer, offset);
|
| + buffer[offset++] = _CharCode.CR;
|
| + buffer[offset++] = _CharCode.LF;
|
| + _headersSink.add(new Uint8List.view(buffer.buffer, 0, offset));
|
| }
|
| }
|
|
|
| @@ -1209,6 +1236,7 @@ class _HttpClientConnection {
|
| Timer _idleTimer;
|
| bool closed = false;
|
| Uri _currentUri;
|
| + final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE);
|
|
|
| Completer<_HttpIncoming> _nextResponseCompleter;
|
| Future _streamFuture;
|
| @@ -1858,6 +1886,7 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> {
|
| final _HttpParser _httpParser;
|
| StreamSubscription _subscription;
|
| Timer _idleTimer;
|
| + final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE);
|
|
|
| Future _streamFuture;
|
|
|
| @@ -2528,3 +2557,5 @@ String _getHttpVersion() {
|
| version = version.substring(0, index);
|
| return 'Dart/$version (dart:io)';
|
| }
|
| +
|
| +
|
|
|