Version 1.22.0-dev.9.1
Cherry-pick 1d6bd5255d14ed822eb0f2e58a7b2013309e9c23 to dev
diff --git a/sdk/lib/io/bytes_builder.dart b/sdk/lib/io/bytes_builder.dart
index 1b61d30..2dca39d 100644
--- a/sdk/lib/io/bytes_builder.dart
+++ b/sdk/lib/io/bytes_builder.dart
@@ -83,22 +83,24 @@
// Start with 1024 bytes.
static const int _INIT_SIZE = 1024;
- static final _emptyList = new Uint8List(0);
-
int _length = 0;
Uint8List _buffer;
- _CopyingBytesBuilder([int initialCapacity = 0])
- : _buffer = (initialCapacity <= 0)
- ? _emptyList
- : new Uint8List(_pow2roundup(initialCapacity));
-
void add(List<int> bytes) {
int bytesLength = bytes.length;
if (bytesLength == 0) return;
int required = _length + bytesLength;
- if (_buffer.length < required) {
- _grow(required);
+ if (_buffer == null) {
+ int size = _pow2roundup(required);
+ size = max(size, _INIT_SIZE);
+ _buffer = new Uint8List(size);
+ } else if (_buffer.length < required) {
+ // We will create a list in the range of 2-4 times larger than
+ // required.
+ int size = _pow2roundup(required) * 2;
+ var newBuffer = new Uint8List(size);
+ newBuffer.setRange(0, _buffer.length, _buffer);
+ _buffer = newBuffer;
}
assert(_buffer.length >= required);
if (bytes is Uint8List) {
@@ -111,40 +113,17 @@
_length = required;
}
- void addByte(int byte) {
- if (_buffer.length == _length) {
- // The grow algorithm always at least doubles.
- // If we added one to _length it would quadruple unnecessarily.
- _grow(_length);
- }
- assert(_buffer.length > _length);
- _buffer[_length] = byte;
- _length++;
- }
-
- void _grow(int required) {
- // We will create a list in the range of 2-4 times larger than
- // required.
- int newSize = required * 2;
- if (newSize < _INIT_SIZE) {
- newSize = _INIT_SIZE;
- } else {
- newSize = _pow2roundup(newSize);
- }
- var newBuffer = new Uint8List(newSize);
- newBuffer.setRange(0, _buffer.length, _buffer);
- _buffer = newBuffer;
- }
+ void addByte(int byte) { add([byte]); }
List<int> takeBytes() {
- if (_length == 0) return _emptyList;
+ if (_buffer == null) return new Uint8List(0);
var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
clear();
return buffer;
}
List<int> toBytes() {
- if (_length == 0) return _emptyList;
+ if (_buffer == null) return new Uint8List(0);
return new Uint8List.fromList(
new Uint8List.view(_buffer.buffer, 0, _length));
}
@@ -157,11 +136,10 @@
void clear() {
_length = 0;
- _buffer = _emptyList;
+ _buffer = null;
}
- static int _pow2roundup(int x) {
- assert(x > 0);
+ int _pow2roundup(int x) {
--x;
x |= x >> 1;
x |= x >> 2;
@@ -188,15 +166,12 @@
_length += typedBytes.length;
}
- void addByte(int byte) {
- _chunks.add(new Uint8List(1)..[0] = byte);
- _length++;
- }
+ void addByte(int byte) { add([byte]); }
List<int> takeBytes() {
- if (_length == 0) return _CopyingBytesBuilder._emptyList;
+ if (_chunks.length == 0) return new Uint8List(0);
if (_chunks.length == 1) {
- var buffer = _chunks[0];
+ var buffer = _chunks.single;
clear();
return buffer;
}
@@ -211,7 +186,7 @@
}
List<int> toBytes() {
- if (_length == 0) return _CopyingBytesBuilder._emptyList;
+ if (_chunks.length == 0) return new Uint8List(0);
var buffer = new Uint8List(_length);
int offset = 0;
for (var chunk in _chunks) {
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 40df48a..3769b3f 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -465,32 +465,42 @@
_mutable = false;
}
- void _build(BytesBuilder builder) {
+ int _write(Uint8List buffer, int offset) {
+ void write(List<int> bytes) {
+ int len = bytes.length;
+ for (int i = 0; i < len; i++) {
+ buffer[offset + i] = bytes[i];
+ }
+ offset += len;
+ }
+
+ // Format headers.
for (String name in _headers.keys) {
List<String> values = _headers[name];
bool fold = _foldHeader(name);
var nameData = name.codeUnits;
- builder.add(nameData);
- builder.addByte(_CharCode.COLON);
- builder.addByte(_CharCode.SP);
+ write(nameData);
+ buffer[offset++] = _CharCode.COLON;
+ buffer[offset++] = _CharCode.SP;
for (int i = 0; i < values.length; i++) {
if (i > 0) {
if (fold) {
- builder.addByte(_CharCode.COMMA);
- builder.addByte(_CharCode.SP);
+ buffer[offset++] = _CharCode.COMMA;
+ buffer[offset++] = _CharCode.SP;
} else {
- builder.addByte(_CharCode.CR);
- builder.addByte(_CharCode.LF);
- builder.add(nameData);
- builder.addByte(_CharCode.COLON);
- builder.addByte(_CharCode.SP);
+ buffer[offset++] = _CharCode.CR;
+ buffer[offset++] = _CharCode.LF;
+ write(nameData);
+ buffer[offset++] = _CharCode.COLON;
+ buffer[offset++] = _CharCode.SP;
}
}
- builder.add(values[i].codeUnits);
+ write(values[i].codeUnits);
}
- builder.addByte(_CharCode.CR);
- builder.addByte(_CharCode.LF);
+ buffer[offset++] = _CharCode.CR;
+ buffer[offset++] = _CharCode.LF;
}
+ return offset;
}
String toString() {
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index ac7d67a..a965afa 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -574,20 +574,29 @@
}
void _writeHeader() {
- BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
+ Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+ 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") {
- buffer.add(_Const.HTTP11);
+ write(_Const.HTTP11);
} else {
- buffer.add(_Const.HTTP10);
+ write(_Const.HTTP10);
}
- buffer.addByte(_CharCode.SP);
- buffer.add(statusCode.toString().codeUnits);
- buffer.addByte(_CharCode.SP);
- buffer.add(reasonPhrase.codeUnits);
- buffer.addByte(_CharCode.CR);
- buffer.addByte(_CharCode.LF);
+ 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) {
@@ -621,11 +630,10 @@
headers._finalize();
// Write headers.
- headers._build(buffer);
- buffer.addByte(_CharCode.CR);
- buffer.addByte(_CharCode.LF);
- Uint8List headerBytes = buffer.takeBytes();
- _outgoing.setHeader(headerBytes, headerBytes.length);
+ offset = headers._write(buffer, offset);
+ buffer[offset++] = _CharCode.CR;
+ buffer[offset++] = _CharCode.LF;
+ _outgoing.setHeader(buffer, offset);
}
String _findReasonPhrase(int statusCode) {
@@ -813,18 +821,27 @@
}
void _writeHeader() {
- BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
+ Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+ 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 the request method.
- buffer.add(method.codeUnits);
- buffer.addByte(_CharCode.SP);
+ write(method.codeUnits);
+ buffer[offset++] = _CharCode.SP;
// Write the request URI.
- buffer.add(_requestUri().codeUnits);
- buffer.addByte(_CharCode.SP);
+ write(_requestUri().codeUnits);
+ buffer[offset++] = _CharCode.SP;
// Write HTTP/1.1.
- buffer.add(_Const.HTTP11);
- buffer.addByte(_CharCode.CR);
- buffer.addByte(_CharCode.LF);
+ write(_Const.HTTP11);
+ buffer[offset++] = _CharCode.CR;
+ buffer[offset++] = _CharCode.LF;
// Add the cookies to the headers.
if (!cookies.isEmpty) {
@@ -839,11 +856,10 @@
headers._finalize();
// Write headers.
- headers._build(buffer);
- buffer.addByte(_CharCode.CR);
- buffer.addByte(_CharCode.LF);
- Uint8List headerBytes = buffer.takeBytes();
- _outgoing.setHeader(headerBytes, headerBytes.length);
+ offset = headers._write(buffer, offset);
+ buffer[offset++] = _CharCode.CR;
+ buffer[offset++] = _CharCode.LF;
+ _outgoing.setHeader(buffer, offset);
}
}
@@ -919,6 +935,18 @@
// Returns either a future or 'null', if it was able to write headers
// immediately.
Future writeHeaders({bool drainRequest: true, bool setOutgoing: true}) {
+ Future write() {
+ try {
+ outbound._writeHeader();
+ } catch (_) {
+ // Headers too large.
+ return new Future.error(new HttpException(
+ "Headers size exceeded the of '$_OUTGOING_BUFFER_SIZE'"
+ " bytes"));
+ }
+ return null;
+ }
+
if (headersWritten) return null;
headersWritten = true;
Future drainFuture;
@@ -947,22 +975,22 @@
} else {
drainRequest = false;
}
- if (!ignoreBody) {
- if (setOutgoing) {
- int contentLength = outbound.headers.contentLength;
- if (outbound.headers.chunkedTransferEncoding) {
- chunked = true;
- if (gzip) this.gzip = true;
- } else if (contentLength >= 0) {
- this.contentLength = contentLength;
- }
- }
- if (drainFuture != null) {
- return drainFuture.then((_) => outbound._writeHeader());
+ if (ignoreBody) {
+ return write();
+ }
+ if (setOutgoing) {
+ int contentLength = outbound.headers.contentLength;
+ if (outbound.headers.chunkedTransferEncoding) {
+ chunked = true;
+ if (gzip) this.gzip = true;
+ } else if (contentLength >= 0) {
+ this.contentLength = contentLength;
}
}
- outbound._writeHeader();
- return null;
+ if (drainFuture != null) {
+ return drainFuture.then((_) => write());
+ }
+ return write();
}
@@ -1132,6 +1160,7 @@
void setHeader(List<int> data, int length) {
assert(_length == 0);
+ assert(data.length == _OUTGOING_BUFFER_SIZE);
_buffer = data;
_length = length;
}
diff --git a/tests/standalone/io/http_client_request_test.dart b/tests/standalone/io/http_client_request_test.dart
index cd2a7be..9015b9f 100644
--- a/tests/standalone/io/http_client_request_test.dart
+++ b/tests/standalone/io/http_client_request_test.dart
@@ -108,8 +108,25 @@
}
+void testBadHeaders() {
+ asyncStart();
+ testClientRequest((request) {
+ var value = "a";
+ for (int i = 0; i < 8 * 1024; i++) {
+ value += 'a';
+ }
+ request.headers.set('name', value);
+ request.done.catchError((error) {
+ asyncEnd();
+ }, test: (e) => e is HttpException);
+ return request.close();
+ });
+}
+
+
void main() {
testResponseDone();
testBadResponseAdd();
testBadResponseClose();
+ testBadHeaders();
}
diff --git a/tests/standalone/io/http_server_response_test.dart b/tests/standalone/io/http_server_response_test.dart
index a6c06af..c3c0afb 100644
--- a/tests/standalone/io/http_server_response_test.dart
+++ b/tests/standalone/io/http_server_response_test.dart
@@ -281,6 +281,20 @@
}
+void testBadHeaders() {
+ testServerRequest((server, request) {
+ var value = "a";
+ for (int i = 0; i < 8 * 1024; i++) {
+ value += 'a';
+ }
+ request.response.headers.set('name', value);
+ request.response.close().catchError((error) {
+ server.close();
+ }, test: (e) => e is HttpException);
+ });
+}
+
+
void testWriteCharCode() {
testServerRequest((server, request) {
// Test that default is latin-1 (only 2 bytes).
@@ -301,5 +315,6 @@
testBadResponseAdd();
testBadResponseClose();
testIgnoreRequestData();
+ testBadHeaders();
testWriteCharCode();
}
diff --git a/tools/VERSION b/tools/VERSION
index eaf108ed..d8a18f8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 22
PATCH 0
PRERELEASE 9
-PRERELEASE_PATCH 0
+PRERELEASE_PATCH 1