[io] Fix a bug where NUL was allowed in HTTP headers.
Bug:https://github.com/dart-lang/sdk/issues/56636
Change-Id: I88c579cfaaf0884cb3b582084b8739b060d8f439
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/402541
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Brian Quinlan <bquinlan@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 75607d9..2ef801d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -223,6 +223,11 @@
release. Users should migrate to using `dart:js_interop` and `package:web`.
See [#59716][].
+#### `dart:io`
+
+- `HttpException` will be thrown by `HttpClient` and `HttpServer` if a `NUL`
+ (`0x00`) appears in a received HTTP header value.
+
#### `dart:svg`
- `dart:svg` is marked deprecated and will be removed in an upcoming release.
diff --git a/sdk/lib/_http/http_parser.dart b/sdk/lib/_http/http_parser.dart
index f877013..0267ac4 100644
--- a/sdk/lib/_http/http_parser.dart
+++ b/sdk/lib/_http/http_parser.dart
@@ -683,7 +683,7 @@
_state = _State.HEADER_VALUE_FOLD_OR_END;
} else if (byte != _CharCode.SP && byte != _CharCode.HT) {
// Start of new header value.
- _addWithValidation(_headerValue, byte);
+ _addToHeaderValueWithValidation(_headerValue, byte);
_state = _State.HEADER_VALUE;
}
break;
@@ -694,7 +694,7 @@
} else if (byte == _CharCode.LF) {
_state = _State.HEADER_VALUE_FOLD_OR_END;
} else {
- _addWithValidation(_headerValue, byte);
+ _addToHeaderValueWithValidation(_headerValue, byte);
}
break;
@@ -710,7 +710,7 @@
// prior to interpreting the field value or forwarding the
// message downstream."
// See https://www.rfc-editor.org/rfc/rfc7230#section-3.2.4
- _addWithValidation(_headerValue, _CharCode.SP);
+ _addToHeaderValueWithValidation(_headerValue, _CharCode.SP);
_state = _State.HEADER_VALUE_START; // Strips leading whitespace.
} else {
String headerField = String.fromCharCodes(_headerField);
@@ -1117,6 +1117,16 @@
}
}
+ void _addToHeaderValueWithValidation(List<int> list, int byte) {
+ // From RFC-9110:
+ // Field values containing CR, LF, or NUL characters are invalid and
+ // dangerous.
+ if (byte == 0 || byte == _CharCode.LF || byte == _CharCode.CR) {
+ throw HttpException("Illegal value $byte in HTTP header");
+ }
+ _addWithValidation(list, byte);
+ }
+
void _addWithValidation(List<int> list, int byte) {
_headersReceivedSize++;
if (_headersReceivedSize < _headerTotalSizeLimit) {
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index c073aa6..7f79737 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -34,15 +34,18 @@
}
void _testParseRequest(
- String request, String expectedMethod, String expectedUri,
- {int expectedTransferLength = 0,
- int expectedBytesReceived = 0,
- Map<String, String?>? expectedHeaders = null,
- bool chunked = false,
- bool upgrade = false,
- int unparsedLength = 0,
- bool connectionClose = false,
- String expectedVersion = "1.1"}) {
+ String request,
+ String expectedMethod,
+ String expectedUri, {
+ int expectedTransferLength = 0,
+ int expectedBytesReceived = 0,
+ Map<String, String?>? expectedHeaders = null,
+ bool chunked = false,
+ bool upgrade = false,
+ int unparsedLength = 0,
+ bool connectionClose = false,
+ String expectedVersion = "1.1",
+ }) {
late StreamController<Uint8List> controller;
void reset() {
_HttpParser httpParser = new _HttpParser.requestParser();
@@ -71,33 +74,41 @@
Expect.equals(-1, incoming.transferLength);
}
if (expectedHeaders != null) {
- expectedHeaders.forEach((String name, String? value) =>
- Expect.equals(value, headers?[name]?[0]));
+ expectedHeaders.forEach(
+ (String name, String? value) =>
+ Expect.equals(value, headers?[name]?[0]),
+ );
}
- incoming.listen((List<int> data) {
- Expect.isFalse(upgraded);
- bytesReceived += data.length;
- }, onDone: () {
- port2.close();
- Expect.equals(expectedMethod, method);
- Expect.stringEquals(expectedUri, uri.toString());
- Expect.equals(expectedVersion, headers!.protocolVersion);
- if (upgrade) {
- Expect.equals(0, bytesReceived);
- // port1 is closed by the listener on the detached data.
- } else {
- Expect.equals(expectedBytesReceived, bytesReceived);
- }
- });
+ incoming.listen(
+ (List<int> data) {
+ Expect.isFalse(upgraded);
+ bytesReceived += data.length;
+ },
+ onDone: () {
+ port2.close();
+ Expect.equals(expectedMethod, method);
+ Expect.stringEquals(expectedUri, uri.toString());
+ Expect.equals(expectedVersion, headers!.protocolVersion);
+ if (upgrade) {
+ Expect.equals(0, bytesReceived);
+ // port1 is closed by the listener on the detached data.
+ } else {
+ Expect.equals(expectedBytesReceived, bytesReceived);
+ }
+ },
+ );
if (upgraded) {
port1.close();
- httpParser.detachIncoming().listen((List<int> data) {
- unparsedBytesReceived += data.length;
- }, onDone: () {
- Expect.equals(unparsedLength, unparsedBytesReceived);
- port2.close();
- });
+ httpParser.detachIncoming().listen(
+ (List<int> data) {
+ unparsedBytesReceived += data.length;
+ },
+ onDone: () {
+ Expect.equals(unparsedLength, unparsedBytesReceived);
+ port2.close();
+ },
+ );
}
incoming.dataDone.then((_) {
@@ -118,42 +129,54 @@
// Test parsing the request three times delivering the data in
// different chunks.
- List<int> requestData =
- new Uint8List.fromList(transform(request).codeUnits);
+ List<int> requestData = new Uint8List.fromList(
+ transform(request).codeUnits,
+ );
testWrite(requestData);
testWrite(requestData, 10);
testWrite(requestData, 1);
}
void _testParseRequestLean(
- String request, String expectedMethod, String expectedUri,
- {int expectedTransferLength = 0,
- int expectedBytesReceived = 0,
- Map<String, String>? expectedHeaders = null,
- bool chunked = false,
- bool upgrade = false,
- int unparsedLength = 0,
- bool connectionClose = false,
- String expectedVersion = "1.1"}) {
- _testParseRequest(request, expectedMethod, expectedUri,
- expectedTransferLength: expectedTransferLength,
- expectedBytesReceived: expectedBytesReceived,
- expectedHeaders: expectedHeaders,
- chunked: chunked,
- upgrade: upgrade,
- unparsedLength: unparsedLength,
- connectionClose: connectionClose,
- expectedVersion: expectedVersion);
+ String request,
+ String expectedMethod,
+ String expectedUri, {
+ int expectedTransferLength = 0,
+ int expectedBytesReceived = 0,
+ Map<String, String>? expectedHeaders = null,
+ bool chunked = false,
+ bool upgrade = false,
+ int unparsedLength = 0,
+ bool connectionClose = false,
+ String expectedVersion = "1.1",
+ }) {
+ _testParseRequest(
+ request,
+ expectedMethod,
+ expectedUri,
+ expectedTransferLength: expectedTransferLength,
+ expectedBytesReceived: expectedBytesReceived,
+ expectedHeaders: expectedHeaders,
+ chunked: chunked,
+ upgrade: upgrade,
+ unparsedLength: unparsedLength,
+ connectionClose: connectionClose,
+ expectedVersion: expectedVersion,
+ );
// Same test but with only \n instead of \r\n terminating each header line.
- _testParseRequest(request.replaceAll('\r', ''), expectedMethod, expectedUri,
- expectedTransferLength: expectedTransferLength,
- expectedBytesReceived: expectedBytesReceived,
- expectedHeaders: expectedHeaders,
- chunked: chunked,
- upgrade: upgrade,
- unparsedLength: unparsedLength,
- connectionClose: connectionClose,
- expectedVersion: expectedVersion);
+ _testParseRequest(
+ request.replaceAll('\r', ''),
+ expectedMethod,
+ expectedUri,
+ expectedTransferLength: expectedTransferLength,
+ expectedBytesReceived: expectedBytesReceived,
+ expectedHeaders: expectedHeaders,
+ chunked: chunked,
+ upgrade: upgrade,
+ unparsedLength: unparsedLength,
+ connectionClose: connectionClose,
+ expectedVersion: expectedVersion,
+ );
}
void _testParseInvalidRequest(String request) {
@@ -182,9 +205,11 @@
void testWrite(List<int> requestData, [int chunkSize = -1]) {
if (chunkSize == -1) chunkSize = requestData.length;
reset();
- for (int pos = 0;
- pos < requestData.length && !errorCalled;
- pos += chunkSize) {
+ for (
+ int pos = 0;
+ pos < requestData.length && !errorCalled;
+ pos += chunkSize
+ ) {
int end = min(requestData.length, pos + chunkSize);
controller.add(requestData.sublist(pos, end) as Uint8List);
}
@@ -193,25 +218,29 @@
// Test parsing the request three times delivering the data in
// different chunks.
- List<int> requestData =
- new Uint8List.fromList(transform(request).codeUnits);
+ List<int> requestData = new Uint8List.fromList(
+ transform(request).codeUnits,
+ );
testWrite(requestData);
testWrite(requestData, 10);
testWrite(requestData, 1);
}
void _testParseResponse(
- String response, int expectedStatusCode, String expectedReasonPhrase,
- {int expectedTransferLength = 0,
- int expectedBytesReceived = 0,
- Map<String, String>? expectedHeaders = null,
- bool chunked = false,
- bool close = false,
- String? responseToMethod = null,
- bool connectionClose = false,
- bool upgrade = false,
- int unparsedLength = 0,
- String expectedVersion = "1.1"}) {
+ String response,
+ int expectedStatusCode,
+ String expectedReasonPhrase, {
+ int expectedTransferLength = 0,
+ int expectedBytesReceived = 0,
+ Map<String, String>? expectedHeaders = null,
+ bool chunked = false,
+ bool close = false,
+ String? responseToMethod = null,
+ bool connectionClose = false,
+ bool upgrade = false,
+ int unparsedLength = 0,
+ String expectedVersion = "1.1",
+ }) {
late StreamController<Uint8List> controller;
bool upgraded;
@@ -265,14 +294,17 @@
}
Expect.equals(upgrade, httpParser.upgrade);
headersCompleteCalled = true;
- incoming.listen((List<int> data) {
- Expect.isTrue(headersCompleteCalled);
- bytesReceived += data.length;
- }, onDone: () {
- dataEndCalled = true;
- dataEndClose = close;
- whenDone();
- });
+ incoming.listen(
+ (List<int> data) {
+ Expect.isTrue(headersCompleteCalled);
+ bytesReceived += data.length;
+ },
+ onDone: () {
+ dataEndCalled = true;
+ dataEndClose = close;
+ whenDone();
+ },
+ );
}, onDone: whenDone);
}
@@ -288,8 +320,9 @@
// Test parsing the request three times delivering the data in
// different chunks.
- List<int> responseData =
- new Uint8List.fromList(transform(response).codeUnits);
+ List<int> responseData = new Uint8List.fromList(
+ transform(response).codeUnits,
+ );
testWrite(responseData);
testWrite(responseData, 10);
testWrite(responseData, 1);
@@ -306,10 +339,13 @@
var port = new ReceivePort();
httpParser.listenToStream(controller.stream);
var subscription = httpParser.listen((incoming) {
- incoming.listen((data) {}, onError: (e) {
- Expect.isFalse(errorCalled);
- errorCalled = true;
- });
+ incoming.listen(
+ (data) {},
+ onError: (e) {
+ Expect.isFalse(errorCalled);
+ errorCalled = true;
+ },
+ );
});
subscription.onError((e) {
Expect.isFalse(errorCalled);
@@ -321,9 +357,11 @@
});
errorCalled = false;
- for (int pos = 0;
- pos < requestData.length && !errorCalled;
- pos += chunkSize) {
+ for (
+ int pos = 0;
+ pos < requestData.length && !errorCalled;
+ pos += chunkSize
+ ) {
int end = min(requestData.length, pos + chunkSize);
controller.add(requestData.sublist(pos, end) as Uint8List);
}
@@ -332,8 +370,9 @@
// Test parsing the request three times delivering the data in
// different chunks.
- List<int> responseData =
- new Uint8List.fromList(transform(response).codeUnits);
+ List<int> responseData = new Uint8List.fromList(
+ transform(response).codeUnits,
+ );
testWrite(responseData);
testWrite(responseData, 10);
testWrite(responseData, 1);
@@ -350,7 +389,7 @@
// WebDAV methods from RFC 5323.
"SEARCH",
// Methods with HTTP prefix.
- "H", "HT", "HTT", "HTTP", "HX", "HTX", "HTTX", "HTTPX"
+ "H", "HT", "HTT", "HTTP", "HX", "HTX", "HTTX", "HTTPX",
];
methods = ['GET'];
methods.forEach((method) {
@@ -360,8 +399,13 @@
_testParseRequestLean(request, method, "/index.html");
});
request = "GET / HTTP/1.0\r\n\r\n";
- _testParseRequestLean(request, "GET", "/",
- expectedVersion: "1.0", connectionClose: true);
+ _testParseRequestLean(
+ request,
+ "GET",
+ "/",
+ expectedVersion: "1.0",
+ connectionClose: true,
+ );
request = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n";
_testParseRequestLean(request, "GET", "/", expectedVersion: "1.0");
@@ -480,8 +524,13 @@
Content-Length: 10\r
\r
0123456789""";
- _testParseRequestLean(request, "POST", "/test",
- expectedTransferLength: 10, expectedBytesReceived: 10);
+ _testParseRequestLean(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: 10,
+ expectedBytesReceived: 10,
+ );
// Test connection close header.
request = "GET /test HTTP/1.1\r\nConnection: close\r\n\r\n";
@@ -497,8 +546,14 @@
5\r
56789\r
0\r\n\r\n""";
- _testParseRequest(request, "POST", "/test",
- expectedTransferLength: -1, expectedBytesReceived: 10, chunked: true);
+ _testParseRequest(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 10,
+ chunked: true,
+ );
// Test LWS around chunked encoding header value.
request = """
@@ -510,8 +565,14 @@
5\r
56789\r
0\r\n\r\n""";
- _testParseRequest(request, "POST", "/test",
- expectedTransferLength: -1, expectedBytesReceived: 10, chunked: true);
+ _testParseRequest(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 10,
+ chunked: true,
+ );
// Test upper and lower case hex digits in chunked encoding.
request = """
@@ -523,8 +584,14 @@
1e\r
012345678901234567890123456789\r
0\r\n\r\n""";
- _testParseRequest(request, "POST", "/test",
- expectedTransferLength: -1, expectedBytesReceived: 60, chunked: true);
+ _testParseRequest(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 60,
+ chunked: true,
+ );
// Test chunk extensions in chunked encoding.
request = """
@@ -536,8 +603,14 @@
1E;yyy=zzz\r
012345678901234567890123456789\r
0\r\n\r\n""";
- _testParseRequest(request, "POST", "/test",
- expectedTransferLength: -1, expectedBytesReceived: 60, chunked: true);
+ _testParseRequest(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 60,
+ chunked: true,
+ );
// Content-Length and "Transfer-Encoding: chunked" are specified.
request = """
@@ -550,14 +623,15 @@
5\r
56789\r
0\r\n\r\n""";
- _testParseRequest(request, "POST", "/test",
- expectedTransferLength: -1,
- expectedBytesReceived: 10,
- chunked: true,
- expectedHeaders: {
- 'content-length': null,
- 'transfer-encoding': 'chunked'
- });
+ _testParseRequest(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 10,
+ chunked: true,
+ expectedHeaders: {'content-length': null, 'transfer-encoding': 'chunked'},
+ );
request = """
POST /test HTTP/1.1\r
@@ -569,14 +643,15 @@
5\r
56789\r
0\r\n\r\n""";
- _testParseRequest(request, "POST", "/test",
- expectedTransferLength: -1,
- expectedBytesReceived: 10,
- chunked: true,
- expectedHeaders: {
- 'content-length': null,
- 'transfer-encoding': 'chunked'
- });
+ _testParseRequest(
+ request,
+ "POST",
+ "/test",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 10,
+ chunked: true,
+ expectedHeaders: {'content-length': null, 'transfer-encoding': 'chunked'},
+ );
// Test HTTP upgrade.
request = """
@@ -586,8 +661,14 @@
\r\n\x01\x01\x01\x01\x01\x02\x02\x02\x02\xFF""";
headers = new Map();
headers["upgrade"] = "irc/1.2";
- _testParseRequest(request, "GET", "/irc",
- expectedHeaders: headers, upgrade: true, unparsedLength: 10);
+ _testParseRequest(
+ request,
+ "GET",
+ "/irc",
+ expectedHeaders: headers,
+ upgrade: true,
+ unparsedLength: 10,
+ );
// Test HTTP upgrade with protocol data.
request = """
@@ -597,8 +678,13 @@
\r\n""";
headers = new Map();
headers["upgrade"] = "irc/1.2";
- _testParseRequest(request, "GET", "/irc",
- expectedHeaders: headers, upgrade: true);
+ _testParseRequest(
+ request,
+ "GET",
+ "/irc",
+ expectedHeaders: headers,
+ upgrade: true,
+ );
// Test websocket upgrade.
request = """
@@ -616,8 +702,13 @@
headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ==";
headers["origin"] = "http://example.com";
headers["sec-websocket-version"] = "13";
- _testParseRequest(request, "GET", "/chat",
- expectedHeaders: headers, upgrade: true);
+ _testParseRequest(
+ request,
+ "GET",
+ "/chat",
+ expectedHeaders: headers,
+ upgrade: true,
+ );
// Test websocket upgrade with protocol data. NOTE: When using the
// WebSocket protocol this should never happen as the client
@@ -639,8 +730,14 @@
headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ==";
headers["origin"] = "http://example.com";
headers["sec-websocket-version"] = "13";
- _testParseRequest(request, "GET", "/chat",
- expectedHeaders: headers, upgrade: true, unparsedLength: 7);
+ _testParseRequest(
+ request,
+ "GET",
+ "/chat",
+ expectedHeaders: headers,
+ upgrade: true,
+ unparsedLength: 7,
+ );
}
void testParseResponse() {
@@ -653,32 +750,59 @@
_testParseResponse(response, 100, "Continue");
response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n";
- _testParseResponse(response, 100, "Continue",
- expectedTransferLength: 10, expectedBytesReceived: 0);
+ _testParseResponse(
+ response,
+ 100,
+ "Continue",
+ expectedTransferLength: 10,
+ expectedBytesReceived: 0,
+ );
response = "HTTP/1.1 100 Continue\r\nContent-Length: \t 10 \t \r\n\r\n";
- _testParseResponse(response, 100, "Continue",
- expectedTransferLength: 10, expectedBytesReceived: 0);
+ _testParseResponse(
+ response,
+ 100,
+ "Continue",
+ expectedTransferLength: 10,
+ expectedBytesReceived: 0,
+ );
- response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n"
+ response =
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n"
"Connection: Close\r\n\r\n";
_testParseResponse(response, 200, "OK", connectionClose: true);
response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n";
- _testParseResponse(response, 200, "OK",
- expectedVersion: "1.0", connectionClose: true);
+ _testParseResponse(
+ response,
+ 200,
+ "OK",
+ expectedVersion: "1.0",
+ connectionClose: true,
+ );
- response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n"
+ response =
+ "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n"
"Connection: Keep-Alive\r\n\r\n";
_testParseResponse(response, 200, "OK", expectedVersion: "1.0");
response = "HTTP/1.1 204 No Content\r\nContent-Length: 11\r\n\r\n";
- _testParseResponse(response, 204, "No Content",
- expectedTransferLength: 11, expectedBytesReceived: 0);
+ _testParseResponse(
+ response,
+ 204,
+ "No Content",
+ expectedTransferLength: 11,
+ expectedBytesReceived: 0,
+ );
response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n";
- _testParseResponse(response, 304, "Not Modified",
- expectedTransferLength: 12, expectedBytesReceived: 0);
+ _testParseResponse(
+ response,
+ 304,
+ "Not Modified",
+ expectedTransferLength: 12,
+ expectedBytesReceived: 0,
+ );
response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
_testParseResponse(response, 200, "OK");
@@ -698,11 +822,15 @@
headers = new Map();
headers["content-length"] = "20";
headers["content-type"] = "text/html";
- _testParseResponse(response, 200, "OK",
- responseToMethod: "HEAD",
- expectedTransferLength: 20,
- expectedBytesReceived: 0,
- expectedHeaders: headers);
+ _testParseResponse(
+ response,
+ 200,
+ "OK",
+ responseToMethod: "HEAD",
+ expectedTransferLength: 20,
+ expectedBytesReceived: 0,
+ expectedHeaders: headers,
+ );
// _testParseRequestLean encodes the request as ISO-8859-1. Test that the
// HTTP parser decodes header values as ISO-8859-1.
@@ -722,8 +850,13 @@
Content-Length: 20\r
\r
01234567890123456789""";
- _testParseResponse(response, 200, "OK",
- expectedTransferLength: 20, expectedBytesReceived: 20);
+ _testParseResponse(
+ response,
+ 200,
+ "OK",
+ expectedTransferLength: 20,
+ expectedBytesReceived: 20,
+ );
// Test upper and lower case hex digits in chunked encoding.
response = """
@@ -735,8 +868,14 @@
1f\r
0123456789012345678901234567890\r
0\r\n\r\n""";
- _testParseResponse(response, 200, "OK",
- expectedTransferLength: -1, expectedBytesReceived: 57, chunked: true);
+ _testParseResponse(
+ response,
+ 200,
+ "OK",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 57,
+ chunked: true,
+ );
// Test connection close header.
response = """
@@ -754,11 +893,15 @@
01234567890123456789012345
0123456789012345678901234567890
""";
- _testParseResponse(response, 200, "OK",
- expectedTransferLength: -1,
- expectedBytesReceived: 59,
- close: true,
- connectionClose: true);
+ _testParseResponse(
+ response,
+ 200,
+ "OK",
+ expectedTransferLength: -1,
+ expectedBytesReceived: 59,
+ close: true,
+ connectionClose: true,
+ );
// Test HTTP upgrade.
response = """
@@ -768,8 +911,13 @@
\r\n""";
headers = new Map();
headers["upgrade"] = "irc/1.2";
- _testParseResponse(response, 101, "Switching Protocols",
- expectedHeaders: headers, upgrade: true);
+ _testParseResponse(
+ response,
+ 101,
+ "Switching Protocols",
+ expectedHeaders: headers,
+ upgrade: true,
+ );
// Test HTTP upgrade with protocol data.
response = """
@@ -779,8 +927,14 @@
\r\n\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xA0\xB0\xC0\xD0\xE0\xF0""";
headers = new Map();
headers["upgrade"] = "irc/1.2";
- _testParseResponse(response, 101, "Switching Protocols",
- expectedHeaders: headers, upgrade: true, unparsedLength: 16);
+ _testParseResponse(
+ response,
+ 101,
+ "Switching Protocols",
+ expectedHeaders: headers,
+ upgrade: true,
+ unparsedLength: 16,
+ );
// Test websocket upgrade.
response = """
@@ -792,8 +946,13 @@
headers = new Map();
headers["upgrade"] = "websocket";
headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
- _testParseResponse(response, 101, "Switching Protocols",
- expectedHeaders: headers, upgrade: true);
+ _testParseResponse(
+ response,
+ 101,
+ "Switching Protocols",
+ expectedHeaders: headers,
+ upgrade: true,
+ );
// Test websocket upgrade with protocol data.
response = """
@@ -805,8 +964,14 @@
headers = new Map();
headers["upgrade"] = "websocket";
headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
- _testParseResponse(response, 101, "Switching Protocols",
- expectedHeaders: headers, upgrade: true, unparsedLength: 4);
+ _testParseResponse(
+ response,
+ 101,
+ "Switching Protocols",
+ expectedHeaders: headers,
+ upgrade: true,
+ unparsedLength: 4,
+ );
}
void testParseInvalidRequest() {
@@ -881,6 +1046,12 @@
response = "HTTP/1.1 200 OK\r\nbadheader\r\n\r\n";
_testParseInvalidResponse(response);
+ response = "HTTP/1.1 200 OK\r\nbadvalue: \x00\r\n\r\n";
+ _testParseInvalidResponse(response);
+
+ response = "HTTP/1.1 200 OK\r\nbadvalue: bad\x00value\r\n\r\n";
+ _testParseInvalidResponse(response);
+
response = """
HTTP/1.1 200 OK\r
Transfer-Encoding: chunked\r