dart-sdk/tests/standalone/io/http_parser_test.dart
Leaf Petersen 131da0516b Refactor standalone tests to avoid including platform library code via parts
Add testing only stubs to dart:_http, and make it available for use in
the standalone tests so that the tests can stop including platform
library code directly using "part" directives (which can cause
surprising breakage, since the same code gets included twice via
different uris).

TEST=Existing tests

Change-Id: I1b5a5061008ef36980bd21b46a9d0fd701286f66
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262780
Reviewed-by: Kallen Tu <kallentu@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
2022-10-29 00:29:09 +00:00

835 lines
26 KiB
Dart

// Copyright (c) 2013, 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.
import "dart:async";
import "dart:isolate";
import "dart:math";
import "dart:typed_data";
// ignore: IMPORT_INTERNAL_LIBRARY
import "dart:_http" show TestingClass$_HttpHeaders, TestingClass$_HttpParser;
import "package:expect/expect.dart";
typedef _HttpHeaders = TestingClass$_HttpHeaders;
typedef _HttpParser = TestingClass$_HttpParser;
class HttpParserTest {
final String Function(String) transform;
HttpParserTest(this.transform);
static void runAllTests() {
final testCRLF = HttpParserTest((String s) => s);
testCRLF.testParseRequest();
testCRLF.testParseResponse();
testCRLF.testParseInvalidRequest();
testCRLF.testParseInvalidResponse();
// Ensure http parser is CR?LF tolerant.
final testLF = HttpParserTest((String s) => s.replaceAll('\r', ''));
testLF.testParseRequest();
testLF.testParseResponse();
testLF.testParseInvalidRequest();
testLF.testParseInvalidResponse();
}
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"}) {
late StreamController<Uint8List> controller;
void reset() {
_HttpParser httpParser = new _HttpParser.requestParser();
controller = new StreamController(sync: true);
var port1 = new ReceivePort();
var port2 = new ReceivePort();
String? method = null;
Uri? uri = null;
_HttpHeaders? headers = null;
int bytesReceived = 0;
int unparsedBytesReceived = 0;
bool upgraded = false;
httpParser.listenToStream(controller.stream);
var subscription = httpParser.listen((incoming) {
method = incoming.method;
uri = incoming.uri;
headers = incoming.headers;
upgraded = incoming.upgraded;
Expect.equals(upgrade, upgraded);
if (!chunked) {
Expect.equals(expectedTransferLength, incoming.transferLength);
} else {
Expect.equals(-1, incoming.transferLength);
}
if (expectedHeaders != null) {
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);
}
});
if (upgraded) {
port1.close();
httpParser.detachIncoming().listen((List<int> data) {
unparsedBytesReceived += data.length;
}, onDone: () {
Expect.equals(unparsedLength, unparsedBytesReceived);
port2.close();
});
}
incoming.dataDone.then((_) {
port1.close();
});
});
}
void testWrite(List<int> requestData, [int chunkSize = -1]) {
if (chunkSize == -1) chunkSize = requestData.length;
reset();
for (int pos = 0; pos < requestData.length; pos += chunkSize) {
int end = min(requestData.length, pos + chunkSize);
controller.add(requestData.sublist(pos, end) as Uint8List);
}
controller.close();
}
// Test parsing the request three times delivering the data in
// different chunks.
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);
// 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);
}
void _testParseInvalidRequest(String request) {
_HttpParser httpParser;
bool errorCalled = false;
late StreamController<Uint8List> controller;
void reset() {
httpParser = new _HttpParser.requestParser();
controller = new StreamController(sync: true);
var port = new ReceivePort();
httpParser.listenToStream(controller.stream);
var subscription = httpParser.listen((incoming) {
Expect.fail("Expected request");
});
subscription.onError((e) {
errorCalled = true;
});
subscription.onDone(() {
port.close();
Expect.isTrue(errorCalled);
});
errorCalled = false;
}
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) {
int end = min(requestData.length, pos + chunkSize);
controller.add(requestData.sublist(pos, end) as Uint8List);
}
controller.close();
}
// Test parsing the request three times delivering the data in
// different chunks.
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"}) {
late StreamController<Uint8List> controller;
bool upgraded;
void reset() {
_HttpParser httpParser;
bool headersCompleteCalled = false;
bool dataEndCalled = false;
bool? dataEndClose = null;
int statusCode = -1;
String? reasonPhrase = null;
_HttpHeaders? headers = null;
int bytesReceived = 0;
httpParser = new _HttpParser.responseParser();
controller = new StreamController(sync: true);
var port = new ReceivePort();
httpParser.listenToStream(controller.stream);
int doneCallCount = 0;
// Called when done parsing entire message and done parsing body.
// Only executed when both are done.
void whenDone() {
doneCallCount++;
if (doneCallCount < 2) return;
Expect.equals(expectedVersion, headers!.protocolVersion);
Expect.equals(expectedStatusCode, statusCode);
Expect.equals(expectedReasonPhrase, reasonPhrase);
Expect.isTrue(headersCompleteCalled);
Expect.equals(expectedBytesReceived, bytesReceived);
if (!upgrade) {
Expect.isTrue(dataEndCalled);
if (close) Expect.isTrue(dataEndClose);
Expect.equals(dataEndClose, connectionClose);
}
}
var subscription = httpParser.listen((incoming) {
port.close();
statusCode = incoming.statusCode!;
reasonPhrase = incoming.reasonPhrase;
headers = incoming.headers;
Expect.isFalse(headersCompleteCalled);
if (!chunked && !close) {
Expect.equals(expectedTransferLength, incoming.transferLength);
} else {
Expect.equals(-1, incoming.transferLength);
}
if (expectedHeaders != null) {
expectedHeaders.forEach((String name, String value) {
Expect.equals(value, headers![name]![0]);
});
}
Expect.equals(upgrade, httpParser.upgrade);
headersCompleteCalled = true;
incoming.listen((List<int> data) {
Expect.isTrue(headersCompleteCalled);
bytesReceived += data.length;
}, onDone: () {
dataEndCalled = true;
dataEndClose = close;
whenDone();
});
}, onDone: whenDone);
}
void testWrite(List<int> requestData, [int chunkSize = -1]) {
if (chunkSize == -1) chunkSize = requestData.length;
reset();
for (int pos = 0; pos < requestData.length; pos += chunkSize) {
int end = min(requestData.length, pos + chunkSize);
controller.add(requestData.sublist(pos, end) as Uint8List);
}
if (close) controller.close();
}
// Test parsing the request three times delivering the data in
// different chunks.
List<int> responseData =
new Uint8List.fromList(transform(response).codeUnits);
testWrite(responseData);
testWrite(responseData, 10);
testWrite(responseData, 1);
}
void _testParseInvalidResponse(String response, [bool close = false]) {
void testWrite(List<int> requestData, [int chunkSize = -1]) {
_HttpParser httpParser = new _HttpParser.responseParser();
StreamController<Uint8List> controller = new StreamController(sync: true);
bool errorCalled = false;
if (chunkSize == -1) chunkSize = requestData.length;
var port = new ReceivePort();
httpParser.listenToStream(controller.stream);
var subscription = httpParser.listen((incoming) {
incoming.listen((data) {}, onError: (e) {
Expect.isFalse(errorCalled);
errorCalled = true;
});
});
subscription.onError((e) {
Expect.isFalse(errorCalled);
errorCalled = true;
});
subscription.onDone(() {
port.close();
Expect.isTrue(errorCalled);
});
errorCalled = false;
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);
}
controller.close();
}
// Test parsing the request three times delivering the data in
// different chunks.
List<int> responseData =
new Uint8List.fromList(transform(response).codeUnits);
testWrite(responseData);
testWrite(responseData, 10);
testWrite(responseData, 1);
}
void testParseRequest() {
String request;
Map<String, String> headers;
var methods = [
// RFC 2616 methods.
"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT",
// WebDAV methods from RFC 4918.
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK",
// WebDAV methods from RFC 5323.
"SEARCH",
// Methods with HTTP prefix.
"H", "HT", "HTT", "HTTP", "HX", "HTX", "HTTX", "HTTPX"
];
methods = ['GET'];
methods.forEach((method) {
request = "$method / HTTP/1.1\r\n\r\n";
_testParseRequestLean(request, method, "/");
request = "$method /index.html HTTP/1.1\r\n\r\n";
_testParseRequestLean(request, method, "/index.html");
});
request = "GET / HTTP/1.0\r\n\r\n";
_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");
request = """
POST /test HTTP/1.1\r
AAA: AAA\r
\r
""";
_testParseRequestLean(request, "POST", "/test");
request = """
POST /test HTTP/1.1\r
\r
""";
_testParseRequestLean(request, "POST", "/test");
request = """
POST /test HTTP/1.1\r
Header-A: AAA\r
X-Header-B: bbb\r
\r
""";
headers = new Map();
headers["header-a"] = "AAA";
headers["x-header-b"] = "bbb";
_testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
Empty-Header-1:\r
Empty-Header-2:\r
\r
\r
""";
headers = new Map();
headers["empty-header-1"] = "";
headers["empty-header-2"] = "";
_testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
Header-A: AAA\r
X-Header-B:\t \t bbb\r
\r
""";
headers = new Map();
headers["header-a"] = "AAA";
headers["x-header-b"] = "bbb";
_testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
Header-A: AA\r
A\r
X-Header-B: b\r
b\r
\t b\r
\r
""";
headers = new Map();
headers["header-a"] = "AAA";
headers["x-header-b"] = "bbb";
_testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
// _testParseRequestLean encodes the request as ISO-8859-1. Test that the
// HTTP parser decodes header values as ISO-8859-1.
request = """
POST /test HTTP/1.1\r
latin1: blåbærgrød\r
\r
""";
headers = new Map();
headers["latin1"] = "blåbærgrød";
_testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
Content-Length: 10\r
\r
0123456789""";
_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";
_testParseRequest(request, "GET", "/test", connectionClose: true);
// Test chunked encoding.
request = """
POST /test HTTP/1.1\r
Transfer-Encoding: chunked\r
\r
5\r
01234\r
5\r
56789\r
0\r\n\r\n""";
_testParseRequest(request, "POST", "/test",
expectedTransferLength: -1, expectedBytesReceived: 10, chunked: true);
// Test upper and lower case hex digits in chunked encoding.
request = """
POST /test HTTP/1.1\r
Transfer-Encoding: chunked\r
\r
1E\r
012345678901234567890123456789\r
1e\r
012345678901234567890123456789\r
0\r\n\r\n""";
_testParseRequest(request, "POST", "/test",
expectedTransferLength: -1, expectedBytesReceived: 60, chunked: true);
// Test chunk extensions in chunked encoding.
request = """
POST /test HTTP/1.1\r
Transfer-Encoding: chunked\r
\r
1E;xxx\r
012345678901234567890123456789\r
1E;yyy=zzz\r
012345678901234567890123456789\r
0\r\n\r\n""";
_testParseRequest(request, "POST", "/test",
expectedTransferLength: -1, expectedBytesReceived: 60, chunked: true);
// Test HTTP upgrade.
request = """
GET /irc HTTP/1.1\r
Upgrade: irc/1.2\r
Connection: Upgrade\r
\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);
// Test HTTP upgrade with protocol data.
request = """
GET /irc HTTP/1.1\r
Upgrade: irc/1.2\r
Connection: Upgrade\r
\r\n""";
headers = new Map();
headers["upgrade"] = "irc/1.2";
_testParseRequest(request, "GET", "/irc",
expectedHeaders: headers, upgrade: true);
// Test websocket upgrade.
request = """
GET /chat HTTP/1.1\r
Host: server.example.com\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r
Origin: http://example.com\r
Sec-WebSocket-Version: 13\r
\r\n""";
headers = new Map();
headers["host"] = "server.example.com";
headers["upgrade"] = "websocket";
headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ==";
headers["origin"] = "http://example.com";
headers["sec-websocket-version"] = "13";
_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
// should not send protocol data before processing the request
// part of the opening handshake. However the HTTP parser should
// still handle this.
request = """
GET /chat HTTP/1.1\r
Host: server.example.com\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r
Origin: http://example.com\r
Sec-WebSocket-Version: 13\r
\r\n0123456""";
headers = new Map();
headers["host"] = "server.example.com";
headers["upgrade"] = "websocket";
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);
}
void testParseResponse() {
String response;
Map<String, String> headers;
response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
_testParseResponse(response, 100, "Continue");
response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
_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);
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);
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);
response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n";
_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");
response = "HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n";
_testParseResponse(response, 404, "Not found");
response = "HTTP/1.1 500 Server error\r\nContent-Length: 0\r\n\r\n";
_testParseResponse(response, 500, "Server error");
// Test response to HEAD request.
response = """
HTTP/1.1 200 OK\r
Content-Length: 20\r
Content-Type: text/html\r
\r\n""";
headers = new Map();
headers["content-length"] = "20";
headers["content-type"] = "text/html";
_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.
response = """
HTTP/1.1 200 OK\r
Content-Length: 0\r
test-latin1: blåbærgrød\r
\r\n""";
headers = new Map();
headers["content-length"] = "0";
headers["test-latin1"] = "blåbærgrød";
_testParseResponse(response, 200, "OK", expectedHeaders: headers);
// Test content.
response = """
HTTP/1.1 200 OK\r
Content-Length: 20\r
\r
01234567890123456789""";
_testParseResponse(response, 200, "OK",
expectedTransferLength: 20, expectedBytesReceived: 20);
// Test upper and lower case hex digits in chunked encoding.
response = """
HTTP/1.1 200 OK\r
Transfer-Encoding: chunked\r
\r
1A\r
01234567890123456789012345\r
1f\r
0123456789012345678901234567890\r
0\r\n\r\n""";
_testParseResponse(response, 200, "OK",
expectedTransferLength: -1, expectedBytesReceived: 57, chunked: true);
// Test connection close header.
response = """
HTTP/1.1 200 OK\r
Content-Length: 0\r
Connection: close\r
\r\n""";
_testParseResponse(response, 200, "OK", connectionClose: true);
// Test HTTP response without any transfer length indications
// where closing the connections indicates end of body.
response = """
HTTP/1.1 200 OK\r
\r
01234567890123456789012345
0123456789012345678901234567890
""";
_testParseResponse(response, 200, "OK",
expectedTransferLength: -1,
expectedBytesReceived: 59,
close: true,
connectionClose: true);
// Test HTTP upgrade.
response = """
HTTP/1.1 101 Switching Protocols\r
Upgrade: irc/1.2\r
Connection: Upgrade\r
\r\n""";
headers = new Map();
headers["upgrade"] = "irc/1.2";
_testParseResponse(response, 101, "Switching Protocols",
expectedHeaders: headers, upgrade: true);
// Test HTTP upgrade with protocol data.
response = """
HTTP/1.1 101 Switching Protocols\r
Upgrade: irc/1.2\r
Connection: Upgrade\r
\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);
// Test websocket upgrade.
response = """
HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r
\r\n""";
headers = new Map();
headers["upgrade"] = "websocket";
headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
_testParseResponse(response, 101, "Switching Protocols",
expectedHeaders: headers, upgrade: true);
// Test websocket upgrade with protocol data.
response = """
HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r
\r\nABCD""";
headers = new Map();
headers["upgrade"] = "websocket";
headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
_testParseResponse(response, 101, "Switching Protocols",
expectedHeaders: headers, upgrade: true, unparsedLength: 4);
}
void testParseInvalidRequest() {
String request;
request = "GET /\r\n\r\n";
_testParseInvalidRequest(request);
request = "GET / \r\n\r\n";
_testParseInvalidRequest(request);
request = "/ HTTP/1.1\r\n\r\n";
_testParseInvalidRequest(request);
request = "GET HTTP/1.1\r\n\r\n";
_testParseInvalidRequest(request);
request = " / HTTP/1.1\r\n\r\n";
_testParseInvalidRequest(request);
request = "@ / HTTP/1.1\r\n\r\n";
_testParseInvalidRequest(request);
request = "GET / TTP/1.1\r\n\r\n";
_testParseInvalidRequest(request);
request = "GET / HTTP/1.\r\n\r\n";
_testParseInvalidRequest(request);
request = "GET / HTTP/1.1\r\nKeep-Alive: False\r\nbadheader\r\n\r\n";
_testParseInvalidRequest(request);
// Content-Length and "Transfer-Encoding: chunked" are specified (error
// per RFC-7320).
request = """
POST /test HTTP/1.1\r
Content-Length: 7\r
Transfer-Encoding: chunked\r
\r
5\r
01234\r
5\r
56789\r
0\r\n\r\n""";
_testParseInvalidRequest(request);
request = """
POST /test HTTP/1.1\r
Transfer-Encoding: chunked\r
Content-Length: 7\r
\r
5\r
01234\r
5\r
56789\r
0\r\n\r\n""";
_testParseInvalidRequest(request);
}
void testParseInvalidResponse() {
String response;
response = "HTTP/1.1\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 \r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 200\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 200 \r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 OK\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 20A OK\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "200 OK\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1. 200 OK\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 200 O\rK\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 000 OK\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 999 Server Error\r\nContent-Length: 0\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 200 OK\r\nContent-Length: x\r\n\r\n";
_testParseInvalidResponse(response);
response = "HTTP/1.1 200 OK\r\nbadheader\r\n\r\n";
_testParseInvalidResponse(response);
response = """
HTTP/1.1 200 OK\r
Transfer-Encoding: chunked\r
\r
1A\r
01234567890123456789012345\r
1g\r
0123456789012345678901234567890\r
0\r\n\r\n""";
_testParseInvalidResponse(response);
}
}
void main() {
HttpParserTest.runAllTests();
}