mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:07:11 +00:00
Migrate standalone tests which rely on the pre-nnbd sdk libraries.
Migrate all the tests under standalone/ that include files under sdk/sdk/ as part files to unblock the replacement of the unmigrated sdk/sdk with the contents of the migrated sdk/sdk_nnbd. Change-Id: Ia2e78bbff797f58244d94021d4b9616793bd641d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151036 Commit-Queue: Leaf Petersen <leafp@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Jonas Termansen <sortie@google.com>
This commit is contained in:
parent
9a87cf9174
commit
d2543e32f4
12 changed files with 131 additions and 2173 deletions
|
@ -2,8 +2,6 @@
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
library dart._http;
|
||||||
|
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
@ -13,15 +11,19 @@ import "dart:developer";
|
||||||
import "dart:io";
|
import "dart:io";
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
import "dart:typed_data";
|
import "dart:typed_data";
|
||||||
|
|
||||||
import "package:expect/expect.dart";
|
import "package:expect/expect.dart";
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
import "../../../sdk_nnbd/lib/internal/internal.dart"
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
part "../../../sdk_nnbd/lib/_http/crypto.dart";
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
part "../../../sdk_nnbd/lib/_http/embedder_config.dart";
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
part "../../../sdk_nnbd/lib/_http/http_impl.dart";
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
part "../../../sdk_nnbd/lib/_http/http_date.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_parser.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_headers.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_session.dart";
|
||||||
|
|
||||||
void testParseHttpCookieDate() {
|
void testParseHttpCookieDate() {
|
||||||
Expect.throws(() => HttpDate._parseCookieDate(""));
|
Expect.throws(() => HttpDate._parseCookieDate(""));
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
library dart._http;
|
||||||
|
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
@ -14,48 +12,52 @@ import "dart:io";
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
import "dart:typed_data";
|
import "dart:typed_data";
|
||||||
|
|
||||||
import "package:expect/expect.dart";
|
import "package:expect/expect.dart";
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
import "../../../sdk_nnbd/lib/internal/internal.dart"
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
part "../../../sdk_nnbd/lib/_http/crypto.dart";
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
part "../../../sdk_nnbd/lib/_http/embedder_config.dart";
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
part "../../../sdk_nnbd/lib/_http/http_impl.dart";
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
part "../../../sdk_nnbd/lib/_http/http_date.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_parser.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_headers.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_session.dart";
|
||||||
|
|
||||||
void testMultiValue() {
|
void testMultiValue() {
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
_HttpHeaders headers = new _HttpHeaders("1.1");
|
||||||
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
||||||
headers.add(HttpHeaders.pragmaHeader, "pragma1");
|
headers.add(HttpHeaders.pragmaHeader, "pragma1");
|
||||||
Expect.equals(1, headers[HttpHeaders.pragmaHeader].length);
|
Expect.equals(1, headers[HttpHeaders.pragmaHeader]!.length);
|
||||||
Expect.equals(1, headers["pragma"].length);
|
Expect.equals(1, headers["pragma"]!.length);
|
||||||
Expect.equals(1, headers["Pragma"].length);
|
Expect.equals(1, headers["Pragma"]!.length);
|
||||||
Expect.equals(1, headers["pragma"].length);
|
Expect.equals(1, headers["pragma"]!.length);
|
||||||
Expect.equals("pragma1", headers.value(HttpHeaders.pragmaHeader));
|
Expect.equals("pragma1", headers.value(HttpHeaders.pragmaHeader));
|
||||||
|
|
||||||
headers.add(HttpHeaders.pragmaHeader, "pragma2");
|
headers.add(HttpHeaders.pragmaHeader, "pragma2");
|
||||||
Expect.equals(2, headers[HttpHeaders.pragmaHeader].length);
|
Expect.equals(2, headers[HttpHeaders.pragmaHeader]!.length);
|
||||||
Expect.throws(
|
Expect.throws(
|
||||||
() => headers.value(HttpHeaders.pragmaHeader), (e) => e is HttpException);
|
() => headers.value(HttpHeaders.pragmaHeader), (e) => e is HttpException);
|
||||||
|
|
||||||
headers.add(HttpHeaders.pragmaHeader, ["pragma3", "pragma4"]);
|
headers.add(HttpHeaders.pragmaHeader, ["pragma3", "pragma4"]);
|
||||||
Expect.listEquals(["pragma1", "pragma2", "pragma3", "pragma4"],
|
Expect.listEquals(["pragma1", "pragma2", "pragma3", "pragma4"],
|
||||||
headers[HttpHeaders.pragmaHeader]);
|
headers[HttpHeaders.pragmaHeader]!);
|
||||||
|
|
||||||
headers.remove(HttpHeaders.pragmaHeader, "pragma3");
|
headers.remove(HttpHeaders.pragmaHeader, "pragma3");
|
||||||
Expect.equals(3, headers[HttpHeaders.pragmaHeader].length);
|
Expect.equals(3, headers[HttpHeaders.pragmaHeader]!.length);
|
||||||
Expect.listEquals(
|
Expect.listEquals(
|
||||||
["pragma1", "pragma2", "pragma4"], headers[HttpHeaders.pragmaHeader]);
|
["pragma1", "pragma2", "pragma4"], headers[HttpHeaders.pragmaHeader]!);
|
||||||
|
|
||||||
headers.remove(HttpHeaders.pragmaHeader, "pragma3");
|
headers.remove(HttpHeaders.pragmaHeader, "pragma3");
|
||||||
Expect.equals(3, headers[HttpHeaders.pragmaHeader].length);
|
Expect.equals(3, headers[HttpHeaders.pragmaHeader]!.length);
|
||||||
|
|
||||||
headers.set(HttpHeaders.pragmaHeader, "pragma5");
|
headers.set(HttpHeaders.pragmaHeader, "pragma5");
|
||||||
Expect.equals(1, headers[HttpHeaders.pragmaHeader].length);
|
Expect.equals(1, headers[HttpHeaders.pragmaHeader]!.length);
|
||||||
|
|
||||||
headers.set(HttpHeaders.pragmaHeader, ["pragma6", "pragma7"]);
|
headers.set(HttpHeaders.pragmaHeader, ["pragma6", "pragma7"]);
|
||||||
Expect.equals(2, headers[HttpHeaders.pragmaHeader].length);
|
Expect.equals(2, headers[HttpHeaders.pragmaHeader]!.length);
|
||||||
|
|
||||||
headers.removeAll(HttpHeaders.pragmaHeader);
|
headers.removeAll(HttpHeaders.pragmaHeader);
|
||||||
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
||||||
|
@ -72,13 +74,13 @@ void testDate() {
|
||||||
headers.date = date1;
|
headers.date = date1;
|
||||||
Expect.equals(date1, headers.date);
|
Expect.equals(date1, headers.date);
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.dateHeader));
|
Expect.equals(httpDate1, headers.value(HttpHeaders.dateHeader));
|
||||||
Expect.equals(1, headers[HttpHeaders.dateHeader].length);
|
Expect.equals(1, headers[HttpHeaders.dateHeader]!.length);
|
||||||
headers.add(HttpHeaders.dateHeader, httpDate2);
|
headers.add(HttpHeaders.dateHeader, httpDate2);
|
||||||
Expect.equals(1, headers[HttpHeaders.dateHeader].length);
|
Expect.equals(1, headers[HttpHeaders.dateHeader]!.length);
|
||||||
Expect.equals(date2, headers.date);
|
Expect.equals(date2, headers.date);
|
||||||
Expect.equals(httpDate2, headers.value(HttpHeaders.dateHeader));
|
Expect.equals(httpDate2, headers.value(HttpHeaders.dateHeader));
|
||||||
headers.set(HttpHeaders.dateHeader, httpDate1);
|
headers.set(HttpHeaders.dateHeader, httpDate1);
|
||||||
Expect.equals(1, headers[HttpHeaders.dateHeader].length);
|
Expect.equals(1, headers[HttpHeaders.dateHeader]!.length);
|
||||||
Expect.equals(date1, headers.date);
|
Expect.equals(date1, headers.date);
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.dateHeader));
|
Expect.equals(httpDate1, headers.value(HttpHeaders.dateHeader));
|
||||||
|
|
||||||
|
@ -98,13 +100,13 @@ void testExpires() {
|
||||||
headers.expires = date1;
|
headers.expires = date1;
|
||||||
Expect.equals(date1, headers.expires);
|
Expect.equals(date1, headers.expires);
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.expiresHeader));
|
Expect.equals(httpDate1, headers.value(HttpHeaders.expiresHeader));
|
||||||
Expect.equals(1, headers[HttpHeaders.expiresHeader].length);
|
Expect.equals(1, headers[HttpHeaders.expiresHeader]!.length);
|
||||||
headers.add(HttpHeaders.expiresHeader, httpDate2);
|
headers.add(HttpHeaders.expiresHeader, httpDate2);
|
||||||
Expect.equals(1, headers[HttpHeaders.expiresHeader].length);
|
Expect.equals(1, headers[HttpHeaders.expiresHeader]!.length);
|
||||||
Expect.equals(date2, headers.expires);
|
Expect.equals(date2, headers.expires);
|
||||||
Expect.equals(httpDate2, headers.value(HttpHeaders.expiresHeader));
|
Expect.equals(httpDate2, headers.value(HttpHeaders.expiresHeader));
|
||||||
headers.set(HttpHeaders.expiresHeader, httpDate1);
|
headers.set(HttpHeaders.expiresHeader, httpDate1);
|
||||||
Expect.equals(1, headers[HttpHeaders.expiresHeader].length);
|
Expect.equals(1, headers[HttpHeaders.expiresHeader]!.length);
|
||||||
Expect.equals(date1, headers.expires);
|
Expect.equals(date1, headers.expires);
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.expiresHeader));
|
Expect.equals(httpDate1, headers.value(HttpHeaders.expiresHeader));
|
||||||
|
|
||||||
|
@ -124,13 +126,13 @@ void testIfModifiedSince() {
|
||||||
headers.ifModifiedSince = date1;
|
headers.ifModifiedSince = date1;
|
||||||
Expect.equals(date1, headers.ifModifiedSince);
|
Expect.equals(date1, headers.ifModifiedSince);
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
Expect.equals(httpDate1, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
||||||
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader].length);
|
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader]!.length);
|
||||||
headers.add(HttpHeaders.ifModifiedSinceHeader, httpDate2);
|
headers.add(HttpHeaders.ifModifiedSinceHeader, httpDate2);
|
||||||
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader].length);
|
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader]!.length);
|
||||||
Expect.equals(date2, headers.ifModifiedSince);
|
Expect.equals(date2, headers.ifModifiedSince);
|
||||||
Expect.equals(httpDate2, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
Expect.equals(httpDate2, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
||||||
headers.set(HttpHeaders.ifModifiedSinceHeader, httpDate1);
|
headers.set(HttpHeaders.ifModifiedSinceHeader, httpDate1);
|
||||||
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader].length);
|
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader]!.length);
|
||||||
Expect.equals(date1, headers.ifModifiedSince);
|
Expect.equals(date1, headers.ifModifiedSince);
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
Expect.equals(httpDate1, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
||||||
|
|
||||||
|
@ -156,7 +158,7 @@ void testHost() {
|
||||||
Expect.equals(host, headers.host);
|
Expect.equals(host, headers.host);
|
||||||
Expect.equals(HttpClient.defaultHttpPort, headers.port);
|
Expect.equals(HttpClient.defaultHttpPort, headers.port);
|
||||||
headers.add(HttpHeaders.hostHeader, "$host:4567");
|
headers.add(HttpHeaders.hostHeader, "$host:4567");
|
||||||
Expect.equals(1, headers[HttpHeaders.hostHeader].length);
|
Expect.equals(1, headers[HttpHeaders.hostHeader]!.length);
|
||||||
Expect.equals(host, headers.host);
|
Expect.equals(host, headers.host);
|
||||||
Expect.equals(4567, headers.port);
|
Expect.equals(4567, headers.port);
|
||||||
|
|
||||||
|
@ -247,11 +249,11 @@ void testEnumeration() {
|
||||||
|
|
||||||
void testHeaderValue() {
|
void testHeaderValue() {
|
||||||
void check(HeaderValue headerValue, String value,
|
void check(HeaderValue headerValue, String value,
|
||||||
[Map<String, String> parameters]) {
|
[Map<String, String?>? parameters]) {
|
||||||
Expect.equals(value, headerValue.value);
|
Expect.equals(value, headerValue.value);
|
||||||
if (parameters != null) {
|
if (parameters != null) {
|
||||||
Expect.equals(parameters.length, headerValue.parameters.length);
|
Expect.equals(parameters.length, headerValue.parameters.length);
|
||||||
parameters.forEach((String name, String value) {
|
parameters.forEach((String name, String? value) {
|
||||||
Expect.equals(value, headerValue.parameters[name]);
|
Expect.equals(value, headerValue.parameters[name]);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -327,13 +329,13 @@ void testHeaderValue() {
|
||||||
|
|
||||||
void testContentType() {
|
void testContentType() {
|
||||||
void check(ContentType contentType, String primaryType, String subType,
|
void check(ContentType contentType, String primaryType, String subType,
|
||||||
[Map<String, String> parameters]) {
|
[Map<String, String?>? parameters]) {
|
||||||
Expect.equals(primaryType, contentType.primaryType);
|
Expect.equals(primaryType, contentType.primaryType);
|
||||||
Expect.equals(subType, contentType.subType);
|
Expect.equals(subType, contentType.subType);
|
||||||
Expect.equals("$primaryType/$subType", contentType.value);
|
Expect.equals("$primaryType/$subType", contentType.value);
|
||||||
if (parameters != null) {
|
if (parameters != null) {
|
||||||
Expect.equals(parameters.length, contentType.parameters.length);
|
Expect.equals(parameters.length, contentType.parameters.length);
|
||||||
parameters.forEach((String name, String value) {
|
parameters.forEach((String name, String? value) {
|
||||||
Expect.equals(value, contentType.parameters[name]);
|
Expect.equals(value, contentType.parameters[name]);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -423,13 +425,13 @@ void testKnownContentTypes() {
|
||||||
void testContentTypeCache() {
|
void testContentTypeCache() {
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
_HttpHeaders headers = new _HttpHeaders("1.1");
|
||||||
headers.set(HttpHeaders.contentTypeHeader, "text/html");
|
headers.set(HttpHeaders.contentTypeHeader, "text/html");
|
||||||
Expect.equals("text", headers.contentType.primaryType);
|
Expect.equals("text", headers.contentType?.primaryType);
|
||||||
Expect.equals("html", headers.contentType.subType);
|
Expect.equals("html", headers.contentType?.subType);
|
||||||
Expect.equals("text/html", headers.contentType.value);
|
Expect.equals("text/html", headers.contentType?.value);
|
||||||
headers.set(HttpHeaders.contentTypeHeader, "text/plain; charset=utf-8");
|
headers.set(HttpHeaders.contentTypeHeader, "text/plain; charset=utf-8");
|
||||||
Expect.equals("text", headers.contentType.primaryType);
|
Expect.equals("text", headers.contentType?.primaryType);
|
||||||
Expect.equals("plain", headers.contentType.subType);
|
Expect.equals("plain", headers.contentType?.subType);
|
||||||
Expect.equals("text/plain", headers.contentType.value);
|
Expect.equals("text/plain", headers.contentType?.value);
|
||||||
headers.removeAll(HttpHeaders.contentTypeHeader);
|
headers.removeAll(HttpHeaders.contentTypeHeader);
|
||||||
Expect.isNull(headers.contentType);
|
Expect.isNull(headers.contentType);
|
||||||
}
|
}
|
||||||
|
@ -626,10 +628,10 @@ void testFolding() {
|
||||||
void testLowercaseAdd() {
|
void testLowercaseAdd() {
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
_HttpHeaders headers = new _HttpHeaders("1.1");
|
||||||
headers.add('A', 'a');
|
headers.add('A', 'a');
|
||||||
Expect.equals(headers['a'][0], headers['A'][0]);
|
Expect.equals(headers['a']![0], headers['A']![0]);
|
||||||
Expect.equals(headers['A'][0], 'a');
|
Expect.equals(headers['A']![0], 'a');
|
||||||
headers.add('Foo', 'Foo', preserveHeaderCase: true);
|
headers.add('Foo', 'Foo', preserveHeaderCase: true);
|
||||||
Expect.equals(headers['Foo'][0], 'Foo');
|
Expect.equals(headers['Foo']![0], 'Foo');
|
||||||
// Header field is Foo.
|
// Header field is Foo.
|
||||||
Expect.isTrue(headers.toString().contains('Foo:'));
|
Expect.isTrue(headers.toString().contains('Foo:'));
|
||||||
|
|
||||||
|
@ -650,14 +652,14 @@ void testLowercaseSet() {
|
||||||
// 'Test' should override 'test' entity
|
// 'Test' should override 'test' entity
|
||||||
headers.set('TEST', 'upper cases', preserveHeaderCase: true);
|
headers.set('TEST', 'upper cases', preserveHeaderCase: true);
|
||||||
Expect.isTrue(headers.toString().contains('TEST: upper cases'));
|
Expect.isTrue(headers.toString().contains('TEST: upper cases'));
|
||||||
Expect.equals(1, headers['test'].length);
|
Expect.equals(1, headers['test']!.length);
|
||||||
Expect.equals(headers['test'][0], 'upper cases');
|
Expect.equals(headers['test']![0], 'upper cases');
|
||||||
|
|
||||||
// Latest header will be stored.
|
// Latest header will be stored.
|
||||||
headers.set('Test', 'mixed cases', preserveHeaderCase: true);
|
headers.set('Test', 'mixed cases', preserveHeaderCase: true);
|
||||||
Expect.isTrue(headers.toString().contains('Test: mixed cases'));
|
Expect.isTrue(headers.toString().contains('Test: mixed cases'));
|
||||||
Expect.equals(1, headers['test'].length);
|
Expect.equals(1, headers['test']!.length);
|
||||||
Expect.equals(headers['test'][0], 'mixed cases');
|
Expect.equals(headers['test']![0], 'mixed cases');
|
||||||
}
|
}
|
||||||
|
|
||||||
void testForEach() {
|
void testForEach() {
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
library dart._http;
|
||||||
|
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
@ -14,15 +12,19 @@ import "dart:io";
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
import "dart:typed_data";
|
import "dart:typed_data";
|
||||||
|
|
||||||
import "package:expect/expect.dart";
|
import "package:expect/expect.dart";
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
import "../../../sdk_nnbd/lib/internal/internal.dart"
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
part "../../../sdk_nnbd/lib/_http/crypto.dart";
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
part "../../../sdk_nnbd/lib/_http/embedder_config.dart";
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
part "../../../sdk_nnbd/lib/_http/http_impl.dart";
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
part "../../../sdk_nnbd/lib/_http/http_date.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_parser.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_headers.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_session.dart";
|
||||||
|
|
||||||
class HttpParserTest {
|
class HttpParserTest {
|
||||||
static void runAllTests() {
|
static void runAllTests() {
|
||||||
|
@ -36,26 +38,25 @@ class HttpParserTest {
|
||||||
String request, String expectedMethod, String expectedUri,
|
String request, String expectedMethod, String expectedUri,
|
||||||
{int expectedTransferLength: 0,
|
{int expectedTransferLength: 0,
|
||||||
int expectedBytesReceived: 0,
|
int expectedBytesReceived: 0,
|
||||||
Map<String, String> expectedHeaders: null,
|
Map<String, String>? expectedHeaders: null,
|
||||||
bool chunked: false,
|
bool chunked: false,
|
||||||
bool upgrade: false,
|
bool upgrade: false,
|
||||||
int unparsedLength: 0,
|
int unparsedLength: 0,
|
||||||
bool connectionClose: false,
|
bool connectionClose: false,
|
||||||
String expectedVersion: "1.1"}) {
|
String expectedVersion: "1.1"}) {
|
||||||
StreamController<Uint8List> controller;
|
late StreamController<Uint8List> controller;
|
||||||
void reset() {
|
void reset() {
|
||||||
_HttpParser httpParser = new _HttpParser.requestParser();
|
_HttpParser httpParser = new _HttpParser.requestParser();
|
||||||
controller = new StreamController(sync: true);
|
controller = new StreamController(sync: true);
|
||||||
var port1 = new ReceivePort();
|
var port1 = new ReceivePort();
|
||||||
var port2 = new ReceivePort();
|
var port2 = new ReceivePort();
|
||||||
|
|
||||||
String method;
|
String? method = null;
|
||||||
Uri uri;
|
Uri? uri = null;
|
||||||
_HttpHeaders headers;
|
_HttpHeaders? headers = null;
|
||||||
int contentLength;
|
int bytesReceived = 0;
|
||||||
int bytesReceived;
|
int unparsedBytesReceived = 0;
|
||||||
int unparsedBytesReceived;
|
bool upgraded = false;
|
||||||
bool upgraded;
|
|
||||||
|
|
||||||
httpParser.listenToStream(controller.stream);
|
httpParser.listenToStream(controller.stream);
|
||||||
var subscription = httpParser.listen((incoming) {
|
var subscription = httpParser.listen((incoming) {
|
||||||
|
@ -72,7 +73,7 @@ class HttpParserTest {
|
||||||
}
|
}
|
||||||
if (expectedHeaders != null) {
|
if (expectedHeaders != null) {
|
||||||
expectedHeaders.forEach((String name, String value) =>
|
expectedHeaders.forEach((String name, String value) =>
|
||||||
Expect.equals(value, headers[name][0]));
|
Expect.equals(value, headers![name]![0]));
|
||||||
}
|
}
|
||||||
incoming.listen((List<int> data) {
|
incoming.listen((List<int> data) {
|
||||||
Expect.isFalse(upgraded);
|
Expect.isFalse(upgraded);
|
||||||
|
@ -81,7 +82,7 @@ class HttpParserTest {
|
||||||
port2.close();
|
port2.close();
|
||||||
Expect.equals(expectedMethod, method);
|
Expect.equals(expectedMethod, method);
|
||||||
Expect.stringEquals(expectedUri, uri.toString());
|
Expect.stringEquals(expectedUri, uri.toString());
|
||||||
Expect.equals(expectedVersion, headers.protocolVersion);
|
Expect.equals(expectedVersion, headers!.protocolVersion);
|
||||||
if (upgrade) {
|
if (upgrade) {
|
||||||
Expect.equals(0, bytesReceived);
|
Expect.equals(0, bytesReceived);
|
||||||
// port1 is closed by the listener on the detached data.
|
// port1 is closed by the listener on the detached data.
|
||||||
|
@ -104,13 +105,6 @@ class HttpParserTest {
|
||||||
port1.close();
|
port1.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
method = null;
|
|
||||||
uri = null;
|
|
||||||
headers = null;
|
|
||||||
bytesReceived = 0;
|
|
||||||
unparsedBytesReceived = 0;
|
|
||||||
upgraded = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWrite(List<int> requestData, [int chunkSize = -1]) {
|
void testWrite(List<int> requestData, [int chunkSize = -1]) {
|
||||||
|
@ -118,7 +112,7 @@ class HttpParserTest {
|
||||||
reset();
|
reset();
|
||||||
for (int pos = 0; pos < requestData.length; pos += chunkSize) {
|
for (int pos = 0; pos < requestData.length; pos += chunkSize) {
|
||||||
int end = min(requestData.length, pos + chunkSize);
|
int end = min(requestData.length, pos + chunkSize);
|
||||||
controller.add(requestData.sublist(pos, end));
|
controller.add(requestData.sublist(pos, end) as Uint8List);
|
||||||
}
|
}
|
||||||
controller.close();
|
controller.close();
|
||||||
}
|
}
|
||||||
|
@ -135,7 +129,7 @@ class HttpParserTest {
|
||||||
String request, String expectedMethod, String expectedUri,
|
String request, String expectedMethod, String expectedUri,
|
||||||
{int expectedTransferLength: 0,
|
{int expectedTransferLength: 0,
|
||||||
int expectedBytesReceived: 0,
|
int expectedBytesReceived: 0,
|
||||||
Map<String, String> expectedHeaders: null,
|
Map<String, String>? expectedHeaders: null,
|
||||||
bool chunked: false,
|
bool chunked: false,
|
||||||
bool upgrade: false,
|
bool upgrade: false,
|
||||||
int unparsedLength: 0,
|
int unparsedLength: 0,
|
||||||
|
@ -164,8 +158,8 @@ class HttpParserTest {
|
||||||
|
|
||||||
static void _testParseInvalidRequest(String request) {
|
static void _testParseInvalidRequest(String request) {
|
||||||
_HttpParser httpParser;
|
_HttpParser httpParser;
|
||||||
bool errorCalled;
|
bool errorCalled = false;
|
||||||
StreamController<Uint8List> controller;
|
late StreamController<Uint8List> controller;
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
httpParser = new _HttpParser.requestParser();
|
httpParser = new _HttpParser.requestParser();
|
||||||
|
@ -192,7 +186,7 @@ class HttpParserTest {
|
||||||
pos < requestData.length && !errorCalled;
|
pos < requestData.length && !errorCalled;
|
||||||
pos += chunkSize) {
|
pos += chunkSize) {
|
||||||
int end = min(requestData.length, pos + chunkSize);
|
int end = min(requestData.length, pos + chunkSize);
|
||||||
controller.add(requestData.sublist(pos, end));
|
controller.add(requestData.sublist(pos, end) as Uint8List);
|
||||||
}
|
}
|
||||||
controller.close();
|
controller.close();
|
||||||
}
|
}
|
||||||
|
@ -209,27 +203,27 @@ class HttpParserTest {
|
||||||
String response, int expectedStatusCode, String expectedReasonPhrase,
|
String response, int expectedStatusCode, String expectedReasonPhrase,
|
||||||
{int expectedTransferLength: 0,
|
{int expectedTransferLength: 0,
|
||||||
int expectedBytesReceived: 0,
|
int expectedBytesReceived: 0,
|
||||||
Map<String, String> expectedHeaders: null,
|
Map<String, String>? expectedHeaders: null,
|
||||||
bool chunked: false,
|
bool chunked: false,
|
||||||
bool close: false,
|
bool close: false,
|
||||||
String responseToMethod: null,
|
String? responseToMethod: null,
|
||||||
bool connectionClose: false,
|
bool connectionClose: false,
|
||||||
bool upgrade: false,
|
bool upgrade: false,
|
||||||
int unparsedLength: 0,
|
int unparsedLength: 0,
|
||||||
String expectedVersion: "1.1"}) {
|
String expectedVersion: "1.1"}) {
|
||||||
StreamController<Uint8List> controller;
|
late StreamController<Uint8List> controller;
|
||||||
bool upgraded;
|
bool upgraded;
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
_HttpParser httpParser;
|
_HttpParser httpParser;
|
||||||
bool headersCompleteCalled;
|
bool headersCompleteCalled = false;
|
||||||
bool dataEndCalled;
|
bool dataEndCalled = false;
|
||||||
bool dataEndClose;
|
bool? dataEndClose = null;
|
||||||
int statusCode;
|
int statusCode = -1;
|
||||||
String reasonPhrase;
|
String? reasonPhrase = null;
|
||||||
_HttpHeaders headers;
|
_HttpHeaders? headers = null;
|
||||||
int contentLength;
|
int bytesReceived = 0;
|
||||||
int bytesReceived;
|
|
||||||
httpParser = new _HttpParser.responseParser();
|
httpParser = new _HttpParser.responseParser();
|
||||||
controller = new StreamController(sync: true);
|
controller = new StreamController(sync: true);
|
||||||
var port = new ReceivePort();
|
var port = new ReceivePort();
|
||||||
|
@ -240,7 +234,7 @@ class HttpParserTest {
|
||||||
void whenDone() {
|
void whenDone() {
|
||||||
doneCallCount++;
|
doneCallCount++;
|
||||||
if (doneCallCount < 2) return;
|
if (doneCallCount < 2) return;
|
||||||
Expect.equals(expectedVersion, headers.protocolVersion);
|
Expect.equals(expectedVersion, headers!.protocolVersion);
|
||||||
Expect.equals(expectedStatusCode, statusCode);
|
Expect.equals(expectedStatusCode, statusCode);
|
||||||
Expect.equals(expectedReasonPhrase, reasonPhrase);
|
Expect.equals(expectedReasonPhrase, reasonPhrase);
|
||||||
Expect.isTrue(headersCompleteCalled);
|
Expect.isTrue(headersCompleteCalled);
|
||||||
|
@ -254,7 +248,7 @@ class HttpParserTest {
|
||||||
|
|
||||||
var subscription = httpParser.listen((incoming) {
|
var subscription = httpParser.listen((incoming) {
|
||||||
port.close();
|
port.close();
|
||||||
statusCode = incoming.statusCode;
|
statusCode = incoming.statusCode!;
|
||||||
reasonPhrase = incoming.reasonPhrase;
|
reasonPhrase = incoming.reasonPhrase;
|
||||||
headers = incoming.headers;
|
headers = incoming.headers;
|
||||||
Expect.isFalse(headersCompleteCalled);
|
Expect.isFalse(headersCompleteCalled);
|
||||||
|
@ -265,7 +259,7 @@ class HttpParserTest {
|
||||||
}
|
}
|
||||||
if (expectedHeaders != null) {
|
if (expectedHeaders != null) {
|
||||||
expectedHeaders.forEach((String name, String value) {
|
expectedHeaders.forEach((String name, String value) {
|
||||||
Expect.equals(value, headers[name][0]);
|
Expect.equals(value, headers![name]![0]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Expect.equals(upgrade, httpParser.upgrade);
|
Expect.equals(upgrade, httpParser.upgrade);
|
||||||
|
@ -279,14 +273,6 @@ class HttpParserTest {
|
||||||
whenDone();
|
whenDone();
|
||||||
});
|
});
|
||||||
}, onDone: whenDone);
|
}, onDone: whenDone);
|
||||||
|
|
||||||
headersCompleteCalled = false;
|
|
||||||
dataEndCalled = false;
|
|
||||||
dataEndClose = null;
|
|
||||||
statusCode = -1;
|
|
||||||
reasonPhrase = null;
|
|
||||||
headers = null;
|
|
||||||
bytesReceived = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWrite(List<int> requestData, [int chunkSize = -1]) {
|
void testWrite(List<int> requestData, [int chunkSize = -1]) {
|
||||||
|
@ -294,7 +280,7 @@ class HttpParserTest {
|
||||||
reset();
|
reset();
|
||||||
for (int pos = 0; pos < requestData.length; pos += chunkSize) {
|
for (int pos = 0; pos < requestData.length; pos += chunkSize) {
|
||||||
int end = min(requestData.length, pos + chunkSize);
|
int end = min(requestData.length, pos + chunkSize);
|
||||||
controller.add(requestData.sublist(pos, end));
|
controller.add(requestData.sublist(pos, end) as Uint8List);
|
||||||
}
|
}
|
||||||
if (close) controller.close();
|
if (close) controller.close();
|
||||||
}
|
}
|
||||||
|
@ -337,7 +323,7 @@ class HttpParserTest {
|
||||||
pos < requestData.length && !errorCalled;
|
pos < requestData.length && !errorCalled;
|
||||||
pos += chunkSize) {
|
pos += chunkSize) {
|
||||||
int end = min(requestData.length, pos + chunkSize);
|
int end = min(requestData.length, pos + chunkSize);
|
||||||
controller.add(requestData.sublist(pos, end));
|
controller.add(requestData.sublist(pos, end) as Uint8List);
|
||||||
}
|
}
|
||||||
controller.close();
|
controller.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
// OtherResources=certificates/server_chain.pem
|
// OtherResources=certificates/server_chain.pem
|
||||||
// OtherResources=certificates/server_key.pem
|
// OtherResources=certificates/server_key.pem
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
library dart._http;
|
||||||
|
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
@ -20,9 +18,8 @@ import "dart:typed_data";
|
||||||
|
|
||||||
import "package:async_helper/async_helper.dart";
|
import "package:async_helper/async_helper.dart";
|
||||||
import "package:expect/expect.dart";
|
import "package:expect/expect.dart";
|
||||||
import "package:path/path.dart";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
part "../../../sdk_nnbd/lib/_http/crypto.dart";
|
||||||
|
|
||||||
const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
const String CERT_NAME = 'localhost_cert';
|
const String CERT_NAME = 'localhost_cert';
|
||||||
|
@ -44,7 +41,7 @@ SecurityContext clientContext = new SecurityContext()
|
||||||
class SecurityConfiguration {
|
class SecurityConfiguration {
|
||||||
final bool secure;
|
final bool secure;
|
||||||
|
|
||||||
SecurityConfiguration({bool this.secure});
|
SecurityConfiguration({required bool this.secure});
|
||||||
|
|
||||||
Future<HttpServer> createServer({int backlog: 0}) => secure
|
Future<HttpServer> createServer({int backlog: 0}) => secure
|
||||||
? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog)
|
? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog)
|
||||||
|
@ -61,7 +58,7 @@ class SecurityConfiguration {
|
||||||
response.statusCode = HttpStatus.switchingProtocols;
|
response.statusCode = HttpStatus.switchingProtocols;
|
||||||
response.headers.set(HttpHeaders.connectionHeader, "upgrade");
|
response.headers.set(HttpHeaders.connectionHeader, "upgrade");
|
||||||
response.headers.set(HttpHeaders.upgradeHeader, "websocket");
|
response.headers.set(HttpHeaders.upgradeHeader, "websocket");
|
||||||
String key = request.headers.value("Sec-WebSocket-Key");
|
String? key = request.headers.value("Sec-WebSocket-Key");
|
||||||
_SHA1 sha1 = new _SHA1();
|
_SHA1 sha1 = new _SHA1();
|
||||||
sha1.add("$key$webSocketGUID".codeUnits);
|
sha1.add("$key$webSocketGUID".codeUnits);
|
||||||
String accept = _CryptoUtils.bytesToBase64(sha1.close());
|
String accept = _CryptoUtils.bytesToBase64(sha1.close());
|
||||||
|
|
|
@ -7,17 +7,16 @@
|
||||||
// VMOptions=--short_socket_write
|
// VMOptions=--short_socket_write
|
||||||
// VMOptions=--short_socket_read --short_socket_write
|
// VMOptions=--short_socket_read --short_socket_write
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
library dart._http;
|
||||||
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
import "dart:io";
|
import "dart:io";
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
import "dart:typed_data";
|
import "dart:typed_data";
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
import "package:expect/expect.dart";
|
||||||
|
|
||||||
|
part "../../../sdk_nnbd/lib/_http/crypto.dart";
|
||||||
|
|
||||||
const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ void testPing(int totalConnections) {
|
||||||
response.statusCode = HttpStatus.switchingProtocols;
|
response.statusCode = HttpStatus.switchingProtocols;
|
||||||
response.headers.set(HttpHeaders.connectionHeader, "upgrade");
|
response.headers.set(HttpHeaders.connectionHeader, "upgrade");
|
||||||
response.headers.set(HttpHeaders.upgradeHeader, "websocket");
|
response.headers.set(HttpHeaders.upgradeHeader, "websocket");
|
||||||
String key = request.headers.value("Sec-WebSocket-Key");
|
String? key = request.headers.value("Sec-WebSocket-Key");
|
||||||
_SHA1 sha1 = new _SHA1();
|
_SHA1 sha1 = new _SHA1();
|
||||||
sha1.add("$key$webSocketGUID".codeUnits);
|
sha1.add("$key$webSocketGUID".codeUnits);
|
||||||
String accept = _CryptoUtils.bytesToBase64(sha1.close());
|
String accept = _CryptoUtils.bytesToBase64(sha1.close());
|
||||||
|
|
|
@ -2,12 +2,8 @@
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
library dart._http;
|
||||||
|
|
||||||
import "package:async_helper/async_helper.dart";
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
import "dart:collection";
|
import "dart:collection";
|
||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
|
@ -17,15 +13,21 @@ import "dart:math";
|
||||||
import "dart:typed_data";
|
import "dart:typed_data";
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
import "package:async_helper/async_helper.dart";
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
import "package:expect/expect.dart";
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
import "../../../sdk_nnbd/lib/internal/internal.dart"
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
part "../../../sdk_nnbd/lib/_http/crypto.dart";
|
||||||
part "../../../sdk/lib/_http/websocket.dart";
|
part "../../../sdk_nnbd/lib/_http/embedder_config.dart";
|
||||||
part "../../../sdk/lib/_http/websocket_impl.dart";
|
part "../../../sdk_nnbd/lib/_http/http_impl.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_date.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_parser.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_headers.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/http_session.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/websocket.dart";
|
||||||
|
part "../../../sdk_nnbd/lib/_http/websocket_impl.dart";
|
||||||
|
|
||||||
class WebSocketFrame {
|
class WebSocketFrame {
|
||||||
WebSocketFrame(int opcode, List<int> data);
|
WebSocketFrame(int opcode, List<int> data);
|
||||||
|
@ -35,16 +37,16 @@ class WebSocketFrame {
|
||||||
// collect the message and expect it to be equal to the
|
// collect the message and expect it to be equal to the
|
||||||
// expectedMessage field when fully received.
|
// expectedMessage field when fully received.
|
||||||
class WebSocketMessageCollector {
|
class WebSocketMessageCollector {
|
||||||
List<int> expectedMessage;
|
List<int>? expectedMessage;
|
||||||
|
|
||||||
int messageCount = 0;
|
int messageCount = 0;
|
||||||
|
|
||||||
var data;
|
var data;
|
||||||
|
|
||||||
Function onClosed;
|
void Function()? onClosed;
|
||||||
|
|
||||||
WebSocketMessageCollector(Stream stream,
|
WebSocketMessageCollector(Stream stream,
|
||||||
[List<int> this.expectedMessage = null]) {
|
[List<int>? this.expectedMessage = null]) {
|
||||||
stream.listen(onMessageData, onDone: onClosed, onError: onError);
|
stream.listen(onMessageData, onDone: onClosed, onError: onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ class WebSocketMessageCollector {
|
||||||
if (buffer is String) {
|
if (buffer is String) {
|
||||||
buffer = utf8.encode(buffer);
|
buffer = utf8.encode(buffer);
|
||||||
}
|
}
|
||||||
Expect.listEquals(expectedMessage, buffer);
|
Expect.listEquals(expectedMessage!, buffer);
|
||||||
messageCount++;
|
messageCount++;
|
||||||
data = buffer;
|
data = buffer;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +71,7 @@ const int FRAME_OPCODE_TEXT = 1;
|
||||||
const int FRAME_OPCODE_BINARY = 2;
|
const int FRAME_OPCODE_BINARY = 2;
|
||||||
|
|
||||||
// Function for building a web socket frame.
|
// Function for building a web socket frame.
|
||||||
List<int> createFrame(bool fin, int opcode, int maskingKey, List<int> data,
|
List<int> createFrame(bool fin, int opcode, int? maskingKey, List<int> data,
|
||||||
int offset, int count) {
|
int offset, int count) {
|
||||||
int frameSize = 2;
|
int frameSize = 2;
|
||||||
if (count > 125) frameSize += 2;
|
if (count > 125) frameSize += 2;
|
||||||
|
@ -145,8 +147,7 @@ void testFullMessages() {
|
||||||
|
|
||||||
void runTest(int from, int to, int step) {
|
void runTest(int from, int to, int step) {
|
||||||
for (int messageLength = from; messageLength < to; messageLength += step) {
|
for (int messageLength = from; messageLength < to; messageLength += step) {
|
||||||
List<int> message = new List<int>(messageLength);
|
List<int> message = [for (int i = 0; i < messageLength; i++) i & 0x7F];
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0x7F;
|
|
||||||
testMessage(FRAME_OPCODE_TEXT, message);
|
testMessage(FRAME_OPCODE_TEXT, message);
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
||||||
testMessage(FRAME_OPCODE_BINARY, message);
|
testMessage(FRAME_OPCODE_BINARY, message);
|
||||||
|
@ -206,8 +207,7 @@ void testFragmentedMessages() {
|
||||||
|
|
||||||
void runTest(int from, int to, int step) {
|
void runTest(int from, int to, int step) {
|
||||||
for (int messageLength = from; messageLength < to; messageLength += step) {
|
for (int messageLength = from; messageLength < to; messageLength += step) {
|
||||||
List<int> message = new List<int>(messageLength);
|
List<int> message = [for (int i = 0; i < messageLength; i++) i & 0x7F];
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0x7F;
|
|
||||||
testMessageFragmentation(FRAME_OPCODE_TEXT, message);
|
testMessageFragmentation(FRAME_OPCODE_TEXT, message);
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
||||||
testMessageFragmentation(FRAME_OPCODE_BINARY, message);
|
testMessageFragmentation(FRAME_OPCODE_BINARY, message);
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright (c) 2012, 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.
|
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
|
||||||
|
|
||||||
import "dart:async";
|
|
||||||
import "dart:collection";
|
|
||||||
import "dart:convert";
|
|
||||||
import "dart:developer";
|
|
||||||
import "dart:io";
|
|
||||||
import "dart:math";
|
|
||||||
import "dart:typed_data";
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
|
||||||
|
|
||||||
void testParseHttpCookieDate() {
|
|
||||||
Expect.throws(() => HttpDate._parseCookieDate(""));
|
|
||||||
|
|
||||||
test(int year, int month, int day, int hours, int minutes, int seconds,
|
|
||||||
String formatted) {
|
|
||||||
DateTime date =
|
|
||||||
new DateTime.utc(year, month, day, hours, minutes, seconds, 0);
|
|
||||||
Expect.equals(date, HttpDate._parseCookieDate(formatted));
|
|
||||||
}
|
|
||||||
|
|
||||||
test(2012, DateTime.june, 19, 14, 15, 01, "tue, 19-jun-12 14:15:01 gmt");
|
|
||||||
test(2021, DateTime.june, 09, 10, 18, 14, "Wed, 09-Jun-2021 10:18:14 GMT");
|
|
||||||
test(2021, DateTime.january, 13, 22, 23, 01, "Wed, 13-Jan-2021 22:23:01 GMT");
|
|
||||||
test(2013, DateTime.january, 15, 21, 47, 38, "Tue, 15-Jan-2013 21:47:38 GMT");
|
|
||||||
test(1970, DateTime.january, 01, 00, 00, 01, "Thu, 01-Jan-1970 00:00:01 GMT");
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testParseHttpCookieDate();
|
|
||||||
}
|
|
|
@ -1,726 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
|
||||||
|
|
||||||
import "dart:async";
|
|
||||||
import "dart:collection";
|
|
||||||
import "dart:convert";
|
|
||||||
import "dart:developer";
|
|
||||||
import "dart:io";
|
|
||||||
import "dart:isolate";
|
|
||||||
import "dart:math";
|
|
||||||
import "dart:typed_data";
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
|
||||||
|
|
||||||
void testMultiValue() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
|
||||||
headers.add(HttpHeaders.pragmaHeader, "pragma1");
|
|
||||||
Expect.equals(1, headers[HttpHeaders.pragmaHeader].length);
|
|
||||||
Expect.equals(1, headers["pragma"].length);
|
|
||||||
Expect.equals(1, headers["Pragma"].length);
|
|
||||||
Expect.equals(1, headers["pragma"].length);
|
|
||||||
Expect.equals("pragma1", headers.value(HttpHeaders.pragmaHeader));
|
|
||||||
|
|
||||||
headers.add(HttpHeaders.pragmaHeader, "pragma2");
|
|
||||||
Expect.equals(2, headers[HttpHeaders.pragmaHeader].length);
|
|
||||||
Expect.throws(
|
|
||||||
() => headers.value(HttpHeaders.pragmaHeader), (e) => e is HttpException);
|
|
||||||
|
|
||||||
headers.add(HttpHeaders.pragmaHeader, ["pragma3", "pragma4"]);
|
|
||||||
Expect.listEquals(["pragma1", "pragma2", "pragma3", "pragma4"],
|
|
||||||
headers[HttpHeaders.pragmaHeader]);
|
|
||||||
|
|
||||||
headers.remove(HttpHeaders.pragmaHeader, "pragma3");
|
|
||||||
Expect.equals(3, headers[HttpHeaders.pragmaHeader].length);
|
|
||||||
Expect.listEquals(
|
|
||||||
["pragma1", "pragma2", "pragma4"], headers[HttpHeaders.pragmaHeader]);
|
|
||||||
|
|
||||||
headers.remove(HttpHeaders.pragmaHeader, "pragma3");
|
|
||||||
Expect.equals(3, headers[HttpHeaders.pragmaHeader].length);
|
|
||||||
|
|
||||||
headers.set(HttpHeaders.pragmaHeader, "pragma5");
|
|
||||||
Expect.equals(1, headers[HttpHeaders.pragmaHeader].length);
|
|
||||||
|
|
||||||
headers.set(HttpHeaders.pragmaHeader, ["pragma6", "pragma7"]);
|
|
||||||
Expect.equals(2, headers[HttpHeaders.pragmaHeader].length);
|
|
||||||
|
|
||||||
headers.removeAll(HttpHeaders.pragmaHeader);
|
|
||||||
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testDate() {
|
|
||||||
DateTime date1 = new DateTime.utc(1999, DateTime.june, 11, 18, 46, 53, 0);
|
|
||||||
String httpDate1 = "Fri, 11 Jun 1999 18:46:53 GMT";
|
|
||||||
DateTime date2 = new DateTime.utc(2000, DateTime.august, 16, 12, 34, 56, 0);
|
|
||||||
String httpDate2 = "Wed, 16 Aug 2000 12:34:56 GMT";
|
|
||||||
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.isNull(headers.date);
|
|
||||||
headers.date = date1;
|
|
||||||
Expect.equals(date1, headers.date);
|
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.dateHeader));
|
|
||||||
Expect.equals(1, headers[HttpHeaders.dateHeader].length);
|
|
||||||
headers.add(HttpHeaders.dateHeader, httpDate2);
|
|
||||||
Expect.equals(1, headers[HttpHeaders.dateHeader].length);
|
|
||||||
Expect.equals(date2, headers.date);
|
|
||||||
Expect.equals(httpDate2, headers.value(HttpHeaders.dateHeader));
|
|
||||||
headers.set(HttpHeaders.dateHeader, httpDate1);
|
|
||||||
Expect.equals(1, headers[HttpHeaders.dateHeader].length);
|
|
||||||
Expect.equals(date1, headers.date);
|
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.dateHeader));
|
|
||||||
|
|
||||||
headers.set(HttpHeaders.dateHeader, "xxx");
|
|
||||||
Expect.equals("xxx", headers.value(HttpHeaders.dateHeader));
|
|
||||||
Expect.equals(null, headers.date);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testExpires() {
|
|
||||||
DateTime date1 = new DateTime.utc(1999, DateTime.june, 11, 18, 46, 53, 0);
|
|
||||||
String httpDate1 = "Fri, 11 Jun 1999 18:46:53 GMT";
|
|
||||||
DateTime date2 = new DateTime.utc(2000, DateTime.august, 16, 12, 34, 56, 0);
|
|
||||||
String httpDate2 = "Wed, 16 Aug 2000 12:34:56 GMT";
|
|
||||||
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.isNull(headers.expires);
|
|
||||||
headers.expires = date1;
|
|
||||||
Expect.equals(date1, headers.expires);
|
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.expiresHeader));
|
|
||||||
Expect.equals(1, headers[HttpHeaders.expiresHeader].length);
|
|
||||||
headers.add(HttpHeaders.expiresHeader, httpDate2);
|
|
||||||
Expect.equals(1, headers[HttpHeaders.expiresHeader].length);
|
|
||||||
Expect.equals(date2, headers.expires);
|
|
||||||
Expect.equals(httpDate2, headers.value(HttpHeaders.expiresHeader));
|
|
||||||
headers.set(HttpHeaders.expiresHeader, httpDate1);
|
|
||||||
Expect.equals(1, headers[HttpHeaders.expiresHeader].length);
|
|
||||||
Expect.equals(date1, headers.expires);
|
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.expiresHeader));
|
|
||||||
|
|
||||||
headers.set(HttpHeaders.expiresHeader, "xxx");
|
|
||||||
Expect.equals("xxx", headers.value(HttpHeaders.expiresHeader));
|
|
||||||
Expect.equals(null, headers.expires);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testIfModifiedSince() {
|
|
||||||
DateTime date1 = new DateTime.utc(1999, DateTime.june, 11, 18, 46, 53, 0);
|
|
||||||
String httpDate1 = "Fri, 11 Jun 1999 18:46:53 GMT";
|
|
||||||
DateTime date2 = new DateTime.utc(2000, DateTime.august, 16, 12, 34, 56, 0);
|
|
||||||
String httpDate2 = "Wed, 16 Aug 2000 12:34:56 GMT";
|
|
||||||
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.isNull(headers.ifModifiedSince);
|
|
||||||
headers.ifModifiedSince = date1;
|
|
||||||
Expect.equals(date1, headers.ifModifiedSince);
|
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
|
||||||
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader].length);
|
|
||||||
headers.add(HttpHeaders.ifModifiedSinceHeader, httpDate2);
|
|
||||||
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader].length);
|
|
||||||
Expect.equals(date2, headers.ifModifiedSince);
|
|
||||||
Expect.equals(httpDate2, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
|
||||||
headers.set(HttpHeaders.ifModifiedSinceHeader, httpDate1);
|
|
||||||
Expect.equals(1, headers[HttpHeaders.ifModifiedSinceHeader].length);
|
|
||||||
Expect.equals(date1, headers.ifModifiedSince);
|
|
||||||
Expect.equals(httpDate1, headers.value(HttpHeaders.ifModifiedSinceHeader));
|
|
||||||
|
|
||||||
headers.set(HttpHeaders.ifModifiedSinceHeader, "xxx");
|
|
||||||
Expect.equals("xxx", headers.value(HttpHeaders.ifModifiedSinceHeader));
|
|
||||||
Expect.equals(null, headers.ifModifiedSince);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHost() {
|
|
||||||
String host = "www.google.com";
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.isNull(headers.host);
|
|
||||||
Expect.isNull(headers.port);
|
|
||||||
headers.host = host;
|
|
||||||
Expect.equals(host, headers.value(HttpHeaders.hostHeader));
|
|
||||||
headers.port = 1234;
|
|
||||||
Expect.equals("$host:1234", headers.value(HttpHeaders.hostHeader));
|
|
||||||
headers.port = HttpClient.defaultHttpPort;
|
|
||||||
Expect.equals(host, headers.value(HttpHeaders.hostHeader));
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add(HttpHeaders.hostHeader, host);
|
|
||||||
Expect.equals(host, headers.host);
|
|
||||||
Expect.equals(HttpClient.defaultHttpPort, headers.port);
|
|
||||||
headers.add(HttpHeaders.hostHeader, "$host:4567");
|
|
||||||
Expect.equals(1, headers[HttpHeaders.hostHeader].length);
|
|
||||||
Expect.equals(host, headers.host);
|
|
||||||
Expect.equals(4567, headers.port);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add(HttpHeaders.hostHeader, "$host:xxx");
|
|
||||||
Expect.equals("$host:xxx", headers.value(HttpHeaders.hostHeader));
|
|
||||||
Expect.equals(host, headers.host);
|
|
||||||
Expect.isNull(headers.port);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add(HttpHeaders.hostHeader, ":1234");
|
|
||||||
Expect.equals(":1234", headers.value(HttpHeaders.hostHeader));
|
|
||||||
Expect.isNull(headers.host);
|
|
||||||
Expect.equals(1234, headers.port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testTransferEncoding() {
|
|
||||||
expectChunked(headers) {
|
|
||||||
Expect.listEquals(headers['transfer-encoding'], ['chunked']);
|
|
||||||
Expect.isTrue(headers.chunkedTransferEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
expectNonChunked(headers) {
|
|
||||||
Expect.isNull(headers['transfer-encoding']);
|
|
||||||
Expect.isFalse(headers.chunkedTransferEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
_HttpHeaders headers;
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.chunkedTransferEncoding = true;
|
|
||||||
expectChunked(headers);
|
|
||||||
headers.set('transfer-encoding', ['chunked']);
|
|
||||||
expectChunked(headers);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.set('transfer-encoding', ['chunked']);
|
|
||||||
expectChunked(headers);
|
|
||||||
headers.chunkedTransferEncoding = true;
|
|
||||||
expectChunked(headers);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.chunkedTransferEncoding = true;
|
|
||||||
headers.chunkedTransferEncoding = false;
|
|
||||||
expectNonChunked(headers);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.chunkedTransferEncoding = true;
|
|
||||||
headers.remove('transfer-encoding', 'chunked');
|
|
||||||
expectNonChunked(headers);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.set('transfer-encoding', ['chunked']);
|
|
||||||
headers.chunkedTransferEncoding = false;
|
|
||||||
expectNonChunked(headers);
|
|
||||||
|
|
||||||
headers = new _HttpHeaders("1.1");
|
|
||||||
headers.set('transfer-encoding', ['chunked']);
|
|
||||||
headers.remove('transfer-encoding', 'chunked');
|
|
||||||
expectNonChunked(headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testEnumeration() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.isNull(headers[HttpHeaders.pragmaHeader]);
|
|
||||||
headers.add("My-Header-1", "value 1");
|
|
||||||
headers.add("My-Header-2", "value 2");
|
|
||||||
headers.add("My-Header-1", "value 3");
|
|
||||||
bool myHeader1 = false;
|
|
||||||
bool myHeader2 = false;
|
|
||||||
int totalValues = 0;
|
|
||||||
headers.forEach((String name, List<String> values) {
|
|
||||||
totalValues += values.length;
|
|
||||||
if (name == "my-header-1") {
|
|
||||||
myHeader1 = true;
|
|
||||||
Expect.isTrue(values.indexOf("value 1") != -1);
|
|
||||||
Expect.isTrue(values.indexOf("value 3") != -1);
|
|
||||||
}
|
|
||||||
if (name == "my-header-2") {
|
|
||||||
myHeader2 = true;
|
|
||||||
Expect.isTrue(values.indexOf("value 2") != -1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Expect.isTrue(myHeader1);
|
|
||||||
Expect.isTrue(myHeader2);
|
|
||||||
Expect.equals(3, totalValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHeaderValue() {
|
|
||||||
void check(HeaderValue headerValue, String value,
|
|
||||||
[Map<String, String> parameters]) {
|
|
||||||
Expect.equals(value, headerValue.value);
|
|
||||||
if (parameters != null) {
|
|
||||||
Expect.equals(parameters.length, headerValue.parameters.length);
|
|
||||||
parameters.forEach((String name, String value) {
|
|
||||||
Expect.equals(value, headerValue.parameters[name]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Expect.equals(0, headerValue.parameters.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderValue headerValue;
|
|
||||||
headerValue = HeaderValue.parse("");
|
|
||||||
check(headerValue, "", {});
|
|
||||||
headerValue = HeaderValue.parse(";");
|
|
||||||
check(headerValue, "", {});
|
|
||||||
headerValue = HeaderValue.parse(";;");
|
|
||||||
check(headerValue, "", {});
|
|
||||||
headerValue = HeaderValue.parse("v;a");
|
|
||||||
check(headerValue, "v", {"a": null});
|
|
||||||
headerValue = HeaderValue.parse("v;a=");
|
|
||||||
check(headerValue, "v", {"a": ""});
|
|
||||||
Expect.throws(() => HeaderValue.parse("v;a=\""), (e) => e is HttpException);
|
|
||||||
headerValue = HeaderValue.parse("v;a=\"\"");
|
|
||||||
check(headerValue, "v", {"a": ""});
|
|
||||||
Expect.throws(() => HeaderValue.parse("v;a=\"\\"), (e) => e is HttpException);
|
|
||||||
Expect.throws(
|
|
||||||
() => HeaderValue.parse("v;a=\";b=\"c\""), (e) => e is HttpException);
|
|
||||||
Expect.throws(() => HeaderValue.parse("v;a=b c"), (e) => e is HttpException);
|
|
||||||
headerValue = HeaderValue.parse("æ;ø=å");
|
|
||||||
check(headerValue, "æ", {"ø": "å"});
|
|
||||||
headerValue =
|
|
||||||
HeaderValue.parse("xxx; aaa=bbb; ccc=\"\\\";\\a\"; ddd=\" \"");
|
|
||||||
check(headerValue, "xxx", {"aaa": "bbb", "ccc": '\";a', "ddd": " "});
|
|
||||||
headerValue =
|
|
||||||
new HeaderValue("xxx", {"aaa": "bbb", "ccc": '\";a', "ddd": " "});
|
|
||||||
check(headerValue, "xxx", {"aaa": "bbb", "ccc": '\";a', "ddd": " "});
|
|
||||||
|
|
||||||
headerValue = HeaderValue.parse("attachment; filename=genome.jpeg;"
|
|
||||||
"modification-date=\"Wed, 12 February 1997 16:29:51 -0500\"");
|
|
||||||
var parameters = {
|
|
||||||
"filename": "genome.jpeg",
|
|
||||||
"modification-date": "Wed, 12 February 1997 16:29:51 -0500"
|
|
||||||
};
|
|
||||||
check(headerValue, "attachment", parameters);
|
|
||||||
headerValue = new HeaderValue("attachment", parameters);
|
|
||||||
check(headerValue, "attachment", parameters);
|
|
||||||
headerValue = HeaderValue.parse(" attachment ;filename=genome.jpeg ;"
|
|
||||||
"modification-date = \"Wed, 12 February 1997 16:29:51 -0500\"");
|
|
||||||
check(headerValue, "attachment", parameters);
|
|
||||||
headerValue = HeaderValue.parse("xxx; aaa; bbb; ccc");
|
|
||||||
check(headerValue, "xxx", {"aaa": null, "bbb": null, "ccc": null});
|
|
||||||
headerValue = HeaderValue.parse("v; a=A; b=B, V; c=C", valueSeparator: ";");
|
|
||||||
check(headerValue, "v", {});
|
|
||||||
headerValue = HeaderValue.parse("v; a=A; b=B, V; c=C", valueSeparator: ";");
|
|
||||||
check(headerValue, "v", {});
|
|
||||||
headerValue = HeaderValue.parse("v; a=A; b=B, V; c=C", valueSeparator: ",");
|
|
||||||
check(headerValue, "v", {"a": "A", "b": "B"});
|
|
||||||
Expect.throws(() => HeaderValue.parse("v; a=A; b=B, V; c=C"));
|
|
||||||
|
|
||||||
Expect.equals("", HeaderValue().toString());
|
|
||||||
Expect.equals("", HeaderValue("").toString());
|
|
||||||
Expect.equals("v", HeaderValue("v").toString());
|
|
||||||
Expect.equals("v", HeaderValue("v", null).toString());
|
|
||||||
Expect.equals("v", HeaderValue("v", {}).toString());
|
|
||||||
Expect.equals("v; ", HeaderValue("v", {"": null}).toString());
|
|
||||||
Expect.equals("v; a", HeaderValue("v", {"a": null}).toString());
|
|
||||||
Expect.equals("v; a; b", HeaderValue("v", {"a": null, "b": null}).toString());
|
|
||||||
Expect.equals(
|
|
||||||
"v; a; b=c", HeaderValue("v", {"a": null, "b": "c"}).toString());
|
|
||||||
Expect.equals(
|
|
||||||
"v; a=c; b", HeaderValue("v", {"a": "c", "b": null}).toString());
|
|
||||||
Expect.equals("v; a=\"\"", HeaderValue("v", {"a": ""}).toString());
|
|
||||||
Expect.equals("v; a=\"b c\"", HeaderValue("v", {"a": "b c"}).toString());
|
|
||||||
Expect.equals("v; a=\",\"", HeaderValue("v", {"a": ","}).toString());
|
|
||||||
Expect.equals(
|
|
||||||
"v; a=\"\\\\\\\"\"", HeaderValue("v", {"a": "\\\""}).toString());
|
|
||||||
Expect.equals("v; a=\"ø\"", HeaderValue("v", {"a": "ø"}).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void testContentType() {
|
|
||||||
void check(ContentType contentType, String primaryType, String subType,
|
|
||||||
[Map<String, String> parameters]) {
|
|
||||||
Expect.equals(primaryType, contentType.primaryType);
|
|
||||||
Expect.equals(subType, contentType.subType);
|
|
||||||
Expect.equals("$primaryType/$subType", contentType.value);
|
|
||||||
if (parameters != null) {
|
|
||||||
Expect.equals(parameters.length, contentType.parameters.length);
|
|
||||||
parameters.forEach((String name, String value) {
|
|
||||||
Expect.equals(value, contentType.parameters[name]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Expect.equals(0, contentType.parameters.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentType contentType;
|
|
||||||
contentType = new ContentType("", "");
|
|
||||||
Expect.equals("", contentType.primaryType);
|
|
||||||
Expect.equals("", contentType.subType);
|
|
||||||
Expect.equals("/", contentType.value);
|
|
||||||
Expect.throwsUnsupportedError(() => contentType.parameters["xxx"] = "yyy");
|
|
||||||
|
|
||||||
contentType = ContentType.parse("text/html");
|
|
||||||
check(contentType, "text", "html");
|
|
||||||
Expect.equals("text/html", contentType.toString());
|
|
||||||
contentType = new ContentType("text", "html", charset: "utf-8");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8"});
|
|
||||||
Expect.equals("text/html; charset=utf-8", contentType.toString());
|
|
||||||
Expect.throwsUnsupportedError(() => contentType.parameters["xxx"] = "yyy");
|
|
||||||
|
|
||||||
contentType = new ContentType("text", "html",
|
|
||||||
parameters: {"CHARSET": "UTF-8", "xxx": "YYY"});
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8", "xxx": "YYY"});
|
|
||||||
String s = contentType.toString();
|
|
||||||
bool expectedToString = (s == "text/html; charset=utf-8; xxx=YYY" ||
|
|
||||||
s == "text/html; xxx=YYY; charset=utf-8");
|
|
||||||
Expect.isTrue(expectedToString);
|
|
||||||
contentType = ContentType.parse("text/html; CHARSET=UTF-8; xxx=YYY");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8", "xxx": "YYY"});
|
|
||||||
Expect.throwsUnsupportedError(() => contentType.parameters["xxx"] = "yyy");
|
|
||||||
|
|
||||||
contentType = new ContentType("text", "html",
|
|
||||||
charset: "ISO-8859-1", parameters: {"CHARSET": "UTF-8", "xxx": "yyy"});
|
|
||||||
check(contentType, "text", "html", {"charset": "iso-8859-1", "xxx": "yyy"});
|
|
||||||
s = contentType.toString();
|
|
||||||
expectedToString = (s == "text/html; charset=iso-8859-1; xxx=yyy" ||
|
|
||||||
s == "text/html; xxx=yyy; charset=iso-8859-1");
|
|
||||||
Expect.isTrue(expectedToString);
|
|
||||||
|
|
||||||
contentType = ContentType.parse("text/html");
|
|
||||||
check(contentType, "text", "html");
|
|
||||||
contentType = ContentType.parse(" text/html ");
|
|
||||||
check(contentType, "text", "html");
|
|
||||||
contentType = ContentType.parse("text/html; charset=utf-8");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8"});
|
|
||||||
contentType = ContentType.parse(" text/html ; charset = utf-8 ");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8"});
|
|
||||||
contentType = ContentType.parse("text/html; charset=utf-8; xxx=yyy");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8", "xxx": "yyy"});
|
|
||||||
contentType =
|
|
||||||
ContentType.parse(" text/html ; charset = utf-8 ; xxx=yyy ");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8", "xxx": "yyy"});
|
|
||||||
contentType = ContentType.parse('text/html; charset=utf-8; xxx="yyy"');
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8", "xxx": "yyy"});
|
|
||||||
contentType =
|
|
||||||
ContentType.parse(" text/html ; charset = utf-8 ; xxx=yyy ");
|
|
||||||
check(contentType, "text", "html", {"charset": "utf-8", "xxx": "yyy"});
|
|
||||||
|
|
||||||
contentType = ContentType.parse("text/html; charset=;");
|
|
||||||
check(contentType, "text", "html", {"charset": ""});
|
|
||||||
contentType = ContentType.parse("text/html; charset;");
|
|
||||||
check(contentType, "text", "html", {"charset": null});
|
|
||||||
|
|
||||||
// Test builtin content types.
|
|
||||||
check(ContentType.text, "text", "plain", {"charset": "utf-8"});
|
|
||||||
check(ContentType.html, "text", "html", {"charset": "utf-8"});
|
|
||||||
check(ContentType.json, "application", "json", {"charset": "utf-8"});
|
|
||||||
check(ContentType.binary, "application", "octet-stream");
|
|
||||||
}
|
|
||||||
|
|
||||||
void testKnownContentTypes() {
|
|
||||||
// Well known content types used by the VM service.
|
|
||||||
ContentType.parse('text/html; charset=UTF-8');
|
|
||||||
ContentType.parse('application/dart; charset=UTF-8');
|
|
||||||
ContentType.parse('application/javascript; charset=UTF-8');
|
|
||||||
ContentType.parse('text/css; charset=UTF-8');
|
|
||||||
ContentType.parse('image/gif');
|
|
||||||
ContentType.parse('image/png');
|
|
||||||
ContentType.parse('image/jpeg');
|
|
||||||
ContentType.parse('image/jpeg');
|
|
||||||
ContentType.parse('image/svg+xml');
|
|
||||||
ContentType.parse('text/plain');
|
|
||||||
}
|
|
||||||
|
|
||||||
void testContentTypeCache() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.set(HttpHeaders.contentTypeHeader, "text/html");
|
|
||||||
Expect.equals("text", headers.contentType.primaryType);
|
|
||||||
Expect.equals("html", headers.contentType.subType);
|
|
||||||
Expect.equals("text/html", headers.contentType.value);
|
|
||||||
headers.set(HttpHeaders.contentTypeHeader, "text/plain; charset=utf-8");
|
|
||||||
Expect.equals("text", headers.contentType.primaryType);
|
|
||||||
Expect.equals("plain", headers.contentType.subType);
|
|
||||||
Expect.equals("text/plain", headers.contentType.value);
|
|
||||||
headers.removeAll(HttpHeaders.contentTypeHeader);
|
|
||||||
Expect.isNull(headers.contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testCookie() {
|
|
||||||
test(String name, String value) {
|
|
||||||
void checkCookiesEquals(a, b) {
|
|
||||||
Expect.equals(a.name, b.name);
|
|
||||||
Expect.equals(a.value, b.value);
|
|
||||||
Expect.equals(a.expires, b.expires);
|
|
||||||
Expect.equals(a.toString(), b.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkCookie(cookie, s) {
|
|
||||||
Expect.equals(s, cookie.toString());
|
|
||||||
var c = new _Cookie.fromSetCookieValue(s);
|
|
||||||
checkCookiesEquals(cookie, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cookie cookie;
|
|
||||||
cookie = new Cookie(name, value);
|
|
||||||
Expect.equals("$name=$value; HttpOnly", cookie.toString());
|
|
||||||
DateTime date = new DateTime.utc(2014, DateTime.january, 5, 23, 59, 59, 0);
|
|
||||||
cookie.expires = date;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Expires=Sun, 05 Jan 2014 23:59:59 GMT"
|
|
||||||
"; HttpOnly");
|
|
||||||
cookie.maxAge = 567;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Expires=Sun, 05 Jan 2014 23:59:59 GMT"
|
|
||||||
"; Max-Age=567"
|
|
||||||
"; HttpOnly");
|
|
||||||
cookie.domain = "example.com";
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Expires=Sun, 05 Jan 2014 23:59:59 GMT"
|
|
||||||
"; Max-Age=567"
|
|
||||||
"; Domain=example.com"
|
|
||||||
"; HttpOnly");
|
|
||||||
cookie.path = "/xxx";
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Expires=Sun, 05 Jan 2014 23:59:59 GMT"
|
|
||||||
"; Max-Age=567"
|
|
||||||
"; Domain=example.com"
|
|
||||||
"; Path=/xxx"
|
|
||||||
"; HttpOnly");
|
|
||||||
cookie.secure = true;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Expires=Sun, 05 Jan 2014 23:59:59 GMT"
|
|
||||||
"; Max-Age=567"
|
|
||||||
"; Domain=example.com"
|
|
||||||
"; Path=/xxx"
|
|
||||||
"; Secure"
|
|
||||||
"; HttpOnly");
|
|
||||||
cookie.httpOnly = false;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Expires=Sun, 05 Jan 2014 23:59:59 GMT"
|
|
||||||
"; Max-Age=567"
|
|
||||||
"; Domain=example.com"
|
|
||||||
"; Path=/xxx"
|
|
||||||
"; Secure");
|
|
||||||
cookie.expires = null;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Max-Age=567"
|
|
||||||
"; Domain=example.com"
|
|
||||||
"; Path=/xxx"
|
|
||||||
"; Secure");
|
|
||||||
cookie.maxAge = null;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Domain=example.com"
|
|
||||||
"; Path=/xxx"
|
|
||||||
"; Secure");
|
|
||||||
cookie.domain = null;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Path=/xxx"
|
|
||||||
"; Secure");
|
|
||||||
cookie.path = null;
|
|
||||||
checkCookie(
|
|
||||||
cookie,
|
|
||||||
"$name=$value"
|
|
||||||
"; Secure");
|
|
||||||
cookie.secure = false;
|
|
||||||
checkCookie(cookie, "$name=$value");
|
|
||||||
}
|
|
||||||
|
|
||||||
test("name", "value");
|
|
||||||
test("abc", "def");
|
|
||||||
test("ABC", "DEF");
|
|
||||||
test("Abc", "Def");
|
|
||||||
test("SID", "sJdkjKSJD12343kjKj78");
|
|
||||||
}
|
|
||||||
|
|
||||||
void testInvalidCookie() {
|
|
||||||
Expect.throws(() => new _Cookie.fromSetCookieValue(""));
|
|
||||||
Expect.throws(() => new _Cookie.fromSetCookieValue("="));
|
|
||||||
Expect.throws(() => new _Cookie.fromSetCookieValue("=xxx"));
|
|
||||||
Expect.throws(() => new _Cookie.fromSetCookieValue("xxx"));
|
|
||||||
Expect.throws(
|
|
||||||
() => new _Cookie.fromSetCookieValue("xxx=yyy; expires=12 jan 2013"));
|
|
||||||
Expect.throws(() => new _Cookie.fromSetCookieValue("x x = y y"));
|
|
||||||
Expect.throws(() => new _Cookie("[4", "y"));
|
|
||||||
Expect.throws(() => new _Cookie("4", "y\""));
|
|
||||||
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.set(
|
|
||||||
'Cookie', 'DARTSESSID=d3d6fdd78d51aaaf2924c32e991f4349; undefined');
|
|
||||||
Expect.equals('DARTSESSID', headers._parseCookies().single.name);
|
|
||||||
Expect.equals(
|
|
||||||
'd3d6fdd78d51aaaf2924c32e991f4349', headers._parseCookies().single.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHeaderLists() {
|
|
||||||
HttpHeaders.generalHeaders.forEach((x) => null);
|
|
||||||
HttpHeaders.entityHeaders.forEach((x) => null);
|
|
||||||
HttpHeaders.responseHeaders.forEach((x) => null);
|
|
||||||
HttpHeaders.requestHeaders.forEach((x) => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testInvalidFieldName() {
|
|
||||||
void test(String field) {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.throwsFormatException(() => headers.add(field, "value"));
|
|
||||||
Expect.throwsFormatException(() => headers.set(field, "value"));
|
|
||||||
Expect.throwsFormatException(() => headers.remove(field, "value"));
|
|
||||||
Expect.throwsFormatException(() => headers.removeAll(field));
|
|
||||||
}
|
|
||||||
|
|
||||||
test('\r');
|
|
||||||
test('\n');
|
|
||||||
test(',');
|
|
||||||
test('test\x00');
|
|
||||||
}
|
|
||||||
|
|
||||||
void testInvalidFieldValue() {
|
|
||||||
void test(value, {bool remove: true}) {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
Expect.throwsFormatException(() => headers.add("field", value));
|
|
||||||
Expect.throwsFormatException(() => headers.set("field", value));
|
|
||||||
if (remove) {
|
|
||||||
Expect.throwsFormatException(() => headers.remove("field", value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test('\r');
|
|
||||||
test('\n');
|
|
||||||
test('test\x00');
|
|
||||||
// Test we handle other types correctly.
|
|
||||||
test(new StringBuffer('\x00'), remove: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testClear() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add("a", "b");
|
|
||||||
headers.contentLength = 7;
|
|
||||||
headers.chunkedTransferEncoding = true;
|
|
||||||
headers.clear();
|
|
||||||
Expect.isNull(headers["a"]);
|
|
||||||
Expect.equals(headers.contentLength, -1);
|
|
||||||
Expect.isFalse(headers.chunkedTransferEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testFolding() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add("a", "b");
|
|
||||||
headers.add("a", "c");
|
|
||||||
headers.add("a", "d");
|
|
||||||
// no folding by default
|
|
||||||
Expect.isTrue(headers.toString().contains('b, c, d'));
|
|
||||||
// Header name should be case insensitive
|
|
||||||
headers.noFolding('A');
|
|
||||||
var str = headers.toString();
|
|
||||||
Expect.isTrue(str.contains(': b'));
|
|
||||||
Expect.isTrue(str.contains(': c'));
|
|
||||||
Expect.isTrue(str.contains(': d'));
|
|
||||||
}
|
|
||||||
|
|
||||||
void testLowercaseAdd() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add('A', 'a');
|
|
||||||
Expect.equals(headers['a'][0], headers['A'][0]);
|
|
||||||
Expect.equals(headers['A'][0], 'a');
|
|
||||||
headers.add('Foo', 'Foo', preserveHeaderCase: true);
|
|
||||||
Expect.equals(headers['Foo'][0], 'Foo');
|
|
||||||
// Header field is Foo.
|
|
||||||
Expect.isTrue(headers.toString().contains('Foo:'));
|
|
||||||
|
|
||||||
headers.add('FOo', 'FOo', preserveHeaderCase: true);
|
|
||||||
// Header field changes to FOo.
|
|
||||||
Expect.isTrue(headers.toString().contains('FOo:'));
|
|
||||||
|
|
||||||
headers.add('FOO', 'FOO', preserveHeaderCase: false);
|
|
||||||
// Header field
|
|
||||||
Expect.isTrue(!headers.toString().contains('Foo:'));
|
|
||||||
Expect.isTrue(!headers.toString().contains('FOo:'));
|
|
||||||
Expect.isTrue(headers.toString().contains('FOO'));
|
|
||||||
}
|
|
||||||
|
|
||||||
void testLowercaseSet() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add('test', 'lower cases');
|
|
||||||
// 'Test' should override 'test' entity
|
|
||||||
headers.set('TEST', 'upper cases', preserveHeaderCase: true);
|
|
||||||
Expect.isTrue(headers.toString().contains('TEST: upper cases'));
|
|
||||||
Expect.equals(1, headers['test'].length);
|
|
||||||
Expect.equals(headers['test'][0], 'upper cases');
|
|
||||||
|
|
||||||
// Latest header will be stored.
|
|
||||||
headers.set('Test', 'mixed cases', preserveHeaderCase: true);
|
|
||||||
Expect.isTrue(headers.toString().contains('Test: mixed cases'));
|
|
||||||
Expect.equals(1, headers['test'].length);
|
|
||||||
Expect.equals(headers['test'][0], 'mixed cases');
|
|
||||||
}
|
|
||||||
|
|
||||||
void testForEach() {
|
|
||||||
_HttpHeaders headers = new _HttpHeaders("1.1");
|
|
||||||
headers.add('header1', 'value 1');
|
|
||||||
headers.add('header2', 'value 2');
|
|
||||||
headers.add('HEADER1', 'value 3', preserveHeaderCase: true);
|
|
||||||
headers.add('HEADER3', 'value 4', preserveHeaderCase: true);
|
|
||||||
|
|
||||||
BytesBuilder builder = BytesBuilder();
|
|
||||||
headers._build(builder);
|
|
||||||
|
|
||||||
Expect.isTrue(utf8.decode(builder.toBytes()).contains('HEADER1'));
|
|
||||||
|
|
||||||
bool myHeader1 = false;
|
|
||||||
bool myHeader2 = false;
|
|
||||||
bool myHeader3 = false;
|
|
||||||
int totalValues = 0;
|
|
||||||
headers.forEach((String name, List<String> values) {
|
|
||||||
totalValues += values.length;
|
|
||||||
if (name == "HEADER1") {
|
|
||||||
myHeader1 = true;
|
|
||||||
Expect.isTrue(values.indexOf("value 1") != -1);
|
|
||||||
Expect.isTrue(values.indexOf("value 3") != -1);
|
|
||||||
}
|
|
||||||
if (name == "header2") {
|
|
||||||
myHeader2 = true;
|
|
||||||
Expect.isTrue(values.indexOf("value 2") != -1);
|
|
||||||
}
|
|
||||||
if (name == "HEADER3") {
|
|
||||||
myHeader3 = true;
|
|
||||||
Expect.isTrue(values.indexOf("value 4") != -1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Expect.isTrue(myHeader1);
|
|
||||||
Expect.isTrue(myHeader2);
|
|
||||||
Expect.isTrue(myHeader3);
|
|
||||||
Expect.equals(4, totalValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
testMultiValue();
|
|
||||||
testDate();
|
|
||||||
testExpires();
|
|
||||||
testIfModifiedSince();
|
|
||||||
testHost();
|
|
||||||
testTransferEncoding();
|
|
||||||
testEnumeration();
|
|
||||||
testHeaderValue();
|
|
||||||
testContentType();
|
|
||||||
testKnownContentTypes();
|
|
||||||
testContentTypeCache();
|
|
||||||
testCookie();
|
|
||||||
testInvalidCookie();
|
|
||||||
testHeaderLists();
|
|
||||||
testInvalidFieldName();
|
|
||||||
testInvalidFieldValue();
|
|
||||||
testClear();
|
|
||||||
testFolding();
|
|
||||||
testLowercaseAdd();
|
|
||||||
testLowercaseSet();
|
|
||||||
testForEach();
|
|
||||||
}
|
|
|
@ -1,849 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
|
||||||
|
|
||||||
import "dart:async";
|
|
||||||
import "dart:collection";
|
|
||||||
import "dart:convert";
|
|
||||||
import "dart:developer";
|
|
||||||
import "dart:io";
|
|
||||||
import "dart:isolate";
|
|
||||||
import "dart:math";
|
|
||||||
import "dart:typed_data";
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
|
||||||
|
|
||||||
class HttpParserTest {
|
|
||||||
static void runAllTests() {
|
|
||||||
testParseRequest();
|
|
||||||
testParseResponse();
|
|
||||||
testParseInvalidRequest();
|
|
||||||
testParseInvalidResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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"}) {
|
|
||||||
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;
|
|
||||||
Uri uri;
|
|
||||||
_HttpHeaders headers;
|
|
||||||
int contentLength;
|
|
||||||
int bytesReceived;
|
|
||||||
int unparsedBytesReceived;
|
|
||||||
bool upgraded;
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
method = null;
|
|
||||||
uri = null;
|
|
||||||
headers = null;
|
|
||||||
bytesReceived = 0;
|
|
||||||
unparsedBytesReceived = 0;
|
|
||||||
upgraded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
controller.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test parsing the request three times delivering the data in
|
|
||||||
// different chunks.
|
|
||||||
List<int> requestData = new Uint8List.fromList(request.codeUnits);
|
|
||||||
testWrite(requestData);
|
|
||||||
testWrite(requestData, 10);
|
|
||||||
testWrite(requestData, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _testParseInvalidRequest(String request) {
|
|
||||||
_HttpParser httpParser;
|
|
||||||
bool errorCalled;
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
controller.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test parsing the request three times delivering the data in
|
|
||||||
// different chunks.
|
|
||||||
List<int> requestData = new Uint8List.fromList(request.codeUnits);
|
|
||||||
testWrite(requestData);
|
|
||||||
testWrite(requestData, 10);
|
|
||||||
testWrite(requestData, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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"}) {
|
|
||||||
StreamController<Uint8List> controller;
|
|
||||||
bool upgraded;
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
_HttpParser httpParser;
|
|
||||||
bool headersCompleteCalled;
|
|
||||||
bool dataEndCalled;
|
|
||||||
bool dataEndClose;
|
|
||||||
int statusCode;
|
|
||||||
String reasonPhrase;
|
|
||||||
_HttpHeaders headers;
|
|
||||||
int contentLength;
|
|
||||||
int bytesReceived;
|
|
||||||
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);
|
|
||||||
|
|
||||||
headersCompleteCalled = false;
|
|
||||||
dataEndCalled = false;
|
|
||||||
dataEndClose = null;
|
|
||||||
statusCode = -1;
|
|
||||||
reasonPhrase = null;
|
|
||||||
headers = null;
|
|
||||||
bytesReceived = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
if (close) controller.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test parsing the request three times delivering the data in
|
|
||||||
// different chunks.
|
|
||||||
List<int> responseData = new Uint8List.fromList(response.codeUnits);
|
|
||||||
testWrite(responseData);
|
|
||||||
testWrite(responseData, 10);
|
|
||||||
testWrite(responseData, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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));
|
|
||||||
}
|
|
||||||
controller.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test parsing the request three times delivering the data in
|
|
||||||
// different chunks.
|
|
||||||
List<int> responseData = new Uint8List.fromList(response.codeUnits);
|
|
||||||
testWrite(responseData);
|
|
||||||
testWrite(responseData, 10);
|
|
||||||
testWrite(responseData, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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 mixing chunked encoding and content length (content length
|
|
||||||
// is ignored).
|
|
||||||
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""";
|
|
||||||
_testParseRequest(request, "POST", "/test",
|
|
||||||
expectedTransferLength: -1, expectedBytesReceived: 10, chunked: true);
|
|
||||||
|
|
||||||
// Test mixing chunked encoding and content length (content length
|
|
||||||
// is ignored).
|
|
||||||
request = """
|
|
||||||
POST /test HTTP/1.1\r
|
|
||||||
Transfer-Encoding: chunked\r
|
|
||||||
Content-Length: 3\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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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();
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// VMOptions=
|
|
||||||
// VMOptions=--short_socket_read
|
|
||||||
// VMOptions=--short_socket_write
|
|
||||||
// VMOptions=--short_socket_read --short_socket_write
|
|
||||||
// OtherResources=certificates/server_chain.pem
|
|
||||||
// OtherResources=certificates/server_key.pem
|
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
|
||||||
|
|
||||||
import "dart:async";
|
|
||||||
import "dart:io";
|
|
||||||
import "dart:math";
|
|
||||||
import "dart:typed_data";
|
|
||||||
|
|
||||||
import "package:async_helper/async_helper.dart";
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
import "package:path/path.dart";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
|
||||||
|
|
||||||
const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
||||||
const String CERT_NAME = 'localhost_cert';
|
|
||||||
const String HOST_NAME = 'localhost';
|
|
||||||
|
|
||||||
String localFile(path) => Platform.script.resolve(path).toFilePath();
|
|
||||||
|
|
||||||
SecurityContext serverContext = new SecurityContext()
|
|
||||||
..useCertificateChain(localFile('certificates/server_chain.pem'))
|
|
||||||
..usePrivateKey(localFile('certificates/server_key.pem'),
|
|
||||||
password: 'dartdart');
|
|
||||||
|
|
||||||
SecurityContext clientContext = new SecurityContext()
|
|
||||||
..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
|
|
||||||
*/
|
|
||||||
class SecurityConfiguration {
|
|
||||||
final bool secure;
|
|
||||||
|
|
||||||
SecurityConfiguration({bool this.secure});
|
|
||||||
|
|
||||||
Future<HttpServer> createServer({int backlog: 0}) => secure
|
|
||||||
? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog)
|
|
||||||
: HttpServer.bind(HOST_NAME, 0, backlog: backlog);
|
|
||||||
|
|
||||||
Future<WebSocket> createClient(int port) =>
|
|
||||||
// TODO(whesse): Add a client context argument to WebSocket.connect.
|
|
||||||
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/');
|
|
||||||
|
|
||||||
void testForceCloseServerEnd(int totalConnections) {
|
|
||||||
createServer().then((server) {
|
|
||||||
server.listen((request) {
|
|
||||||
var response = request.response;
|
|
||||||
response.statusCode = HttpStatus.switchingProtocols;
|
|
||||||
response.headers.set(HttpHeaders.connectionHeader, "upgrade");
|
|
||||||
response.headers.set(HttpHeaders.upgradeHeader, "websocket");
|
|
||||||
String key = request.headers.value("Sec-WebSocket-Key");
|
|
||||||
_SHA1 sha1 = new _SHA1();
|
|
||||||
sha1.add("$key$webSocketGUID".codeUnits);
|
|
||||||
String accept = _CryptoUtils.bytesToBase64(sha1.close());
|
|
||||||
response.headers.add("Sec-WebSocket-Accept", accept);
|
|
||||||
response.headers.contentLength = 0;
|
|
||||||
response.detachSocket().then((socket) {
|
|
||||||
socket.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
int closeCount = 0;
|
|
||||||
for (int i = 0; i < totalConnections; i++) {
|
|
||||||
createClient(server.port).then((webSocket) {
|
|
||||||
webSocket.add("Hello, world!");
|
|
||||||
webSocket.listen((message) {
|
|
||||||
Expect.fail("unexpected message");
|
|
||||||
}, onDone: () {
|
|
||||||
closeCount++;
|
|
||||||
if (closeCount == totalConnections) {
|
|
||||||
server.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void runTests() {
|
|
||||||
testForceCloseServerEnd(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
asyncStart();
|
|
||||||
new SecurityConfiguration(secure: false).runTests();
|
|
||||||
// TODO(whesse): WebSocket.connect needs an optional context: parameter
|
|
||||||
// new SecurityConfiguration(secure: true).runTests();
|
|
||||||
asyncEnd();
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// VMOptions=
|
|
||||||
// VMOptions=--short_socket_read
|
|
||||||
// VMOptions=--short_socket_write
|
|
||||||
// VMOptions=--short_socket_read --short_socket_write
|
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
|
||||||
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
import "dart:async";
|
|
||||||
import "dart:io";
|
|
||||||
import "dart:math";
|
|
||||||
import "dart:typed_data";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
|
||||||
|
|
||||||
const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
||||||
|
|
||||||
void testPing(int totalConnections) {
|
|
||||||
HttpServer.bind('localhost', 0).then((server) {
|
|
||||||
int closed = 0;
|
|
||||||
server.listen((request) {
|
|
||||||
var response = request.response;
|
|
||||||
response.statusCode = HttpStatus.switchingProtocols;
|
|
||||||
response.headers.set(HttpHeaders.connectionHeader, "upgrade");
|
|
||||||
response.headers.set(HttpHeaders.upgradeHeader, "websocket");
|
|
||||||
String key = request.headers.value("Sec-WebSocket-Key");
|
|
||||||
_SHA1 sha1 = new _SHA1();
|
|
||||||
sha1.add("$key$webSocketGUID".codeUnits);
|
|
||||||
String accept = _CryptoUtils.bytesToBase64(sha1.close());
|
|
||||||
response.headers.add("Sec-WebSocket-Accept", accept);
|
|
||||||
response.headers.contentLength = 0;
|
|
||||||
response.detachSocket().then((socket) {
|
|
||||||
socket.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
int closeCount = 0;
|
|
||||||
for (int i = 0; i < totalConnections; i++) {
|
|
||||||
WebSocket.connect('ws://localhost:${server.port}').then((webSocket) {
|
|
||||||
webSocket.pingInterval = const Duration(milliseconds: 100);
|
|
||||||
webSocket.listen((message) {
|
|
||||||
Expect.fail("unexpected message");
|
|
||||||
}, onDone: () {
|
|
||||||
closeCount++;
|
|
||||||
if (closeCount == totalConnections) {
|
|
||||||
server.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testPing(10);
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
// Copyright (c) 2012, 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.
|
|
||||||
|
|
||||||
// @dart = 2.6
|
|
||||||
|
|
||||||
library dart._http;
|
|
||||||
|
|
||||||
import "package:async_helper/async_helper.dart";
|
|
||||||
import "package:expect/expect.dart";
|
|
||||||
import "dart:async";
|
|
||||||
import "dart:collection";
|
|
||||||
import "dart:convert";
|
|
||||||
import "dart:developer";
|
|
||||||
import "dart:io";
|
|
||||||
import "dart:math";
|
|
||||||
import "dart:typed_data";
|
|
||||||
import "dart:isolate";
|
|
||||||
|
|
||||||
part "../../../sdk/lib/_http/crypto.dart";
|
|
||||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_impl.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_date.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_parser.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_headers.dart";
|
|
||||||
part "../../../sdk/lib/_http/http_session.dart";
|
|
||||||
part "../../../sdk/lib/_http/websocket.dart";
|
|
||||||
part "../../../sdk/lib/_http/websocket_impl.dart";
|
|
||||||
|
|
||||||
class WebSocketFrame {
|
|
||||||
WebSocketFrame(int opcode, List<int> data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class that when hooked up to the web socket protocol transformer will
|
|
||||||
// collect the message and expect it to be equal to the
|
|
||||||
// expectedMessage field when fully received.
|
|
||||||
class WebSocketMessageCollector {
|
|
||||||
List<int> expectedMessage;
|
|
||||||
|
|
||||||
int messageCount = 0;
|
|
||||||
|
|
||||||
var data;
|
|
||||||
|
|
||||||
Function onClosed;
|
|
||||||
|
|
||||||
WebSocketMessageCollector(Stream stream,
|
|
||||||
[List<int> this.expectedMessage = null]) {
|
|
||||||
stream.listen(onMessageData, onDone: onClosed, onError: onError);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onMessageData(buffer) {
|
|
||||||
if (buffer is String) {
|
|
||||||
buffer = utf8.encode(buffer);
|
|
||||||
}
|
|
||||||
Expect.listEquals(expectedMessage, buffer);
|
|
||||||
messageCount++;
|
|
||||||
data = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onError(e, trace) {
|
|
||||||
String msg = "Unexpected error $e";
|
|
||||||
if (trace != null) msg += "\nStackTrace: $trace";
|
|
||||||
Expect.fail(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Web socket constants.
|
|
||||||
const int FRAME_OPCODE_TEXT = 1;
|
|
||||||
const int FRAME_OPCODE_BINARY = 2;
|
|
||||||
|
|
||||||
// Function for building a web socket frame.
|
|
||||||
List<int> createFrame(bool fin, int opcode, int maskingKey, List<int> data,
|
|
||||||
int offset, int count) {
|
|
||||||
int frameSize = 2;
|
|
||||||
if (count > 125) frameSize += 2;
|
|
||||||
if (count > 65535) frameSize += 6;
|
|
||||||
frameSize += count;
|
|
||||||
// No masking.
|
|
||||||
assert(maskingKey == null);
|
|
||||||
List<int> frame = new Uint8List(frameSize);
|
|
||||||
int frameIndex = 0;
|
|
||||||
frame[frameIndex++] = (fin ? 0x80 : 0x00) | opcode;
|
|
||||||
if (count < 126) {
|
|
||||||
frame[frameIndex++] = count;
|
|
||||||
} else if (count < 65536) {
|
|
||||||
frame[frameIndex++] = 126;
|
|
||||||
frame[frameIndex++] = count >> 8;
|
|
||||||
frame[frameIndex++] = count & 0xFF;
|
|
||||||
} else {
|
|
||||||
frame[frameIndex++] = 127;
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
frame[frameIndex++] = count >> ((7 - i) * 8) & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
frame.setRange(frameIndex, frameIndex + count, data, offset);
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test processing messages which are sent in a single frame.
|
|
||||||
void testFullMessages() {
|
|
||||||
void testMessage(int opcode, List<int> message) {
|
|
||||||
int messageCount = 0;
|
|
||||||
// Use the same web socket protocol transformer for all frames.
|
|
||||||
var transformer = new _WebSocketProtocolTransformer();
|
|
||||||
var controller = new StreamController<List<int>>(sync: true);
|
|
||||||
WebSocketMessageCollector mc = new WebSocketMessageCollector(
|
|
||||||
controller.stream.transform(transformer), message);
|
|
||||||
|
|
||||||
List<int> frame =
|
|
||||||
createFrame(true, opcode, null, message, 0, message.length);
|
|
||||||
|
|
||||||
// Update the transformer with one big chunk.
|
|
||||||
messageCount++;
|
|
||||||
controller.add(frame);
|
|
||||||
mc.onClosed = () {
|
|
||||||
Expect.isNotNull(mc.data);
|
|
||||||
Expect.equals(0, transformer._state);
|
|
||||||
|
|
||||||
mc.data = null;
|
|
||||||
|
|
||||||
// Only run this part on small messages.
|
|
||||||
if (message.length < 1000) {
|
|
||||||
// Update the transformer one byte at the time.
|
|
||||||
messageCount++;
|
|
||||||
for (int i = 0; i < frame.length; i++) {
|
|
||||||
controller.add(<int>[frame[i]]);
|
|
||||||
}
|
|
||||||
Expect.equals(0, transformer._state);
|
|
||||||
Expect.isNotNull(mc.data);
|
|
||||||
mc.data = null;
|
|
||||||
|
|
||||||
// Update the transformer two bytes at the time.
|
|
||||||
messageCount++;
|
|
||||||
for (int i = 0; i < frame.length; i += 2) {
|
|
||||||
controller.add(frame.sublist(i, min(i + 2, frame.length)));
|
|
||||||
}
|
|
||||||
Expect.equals(0, transformer._state);
|
|
||||||
Expect.isNotNull(mc.data);
|
|
||||||
}
|
|
||||||
Expect.equals(messageCount, mc.messageCount);
|
|
||||||
print("Messages test, messages $messageCount");
|
|
||||||
};
|
|
||||||
controller.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void runTest(int from, int to, int step) {
|
|
||||||
for (int messageLength = from; messageLength < to; messageLength += step) {
|
|
||||||
List<int> message = new List<int>(messageLength);
|
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0x7F;
|
|
||||||
testMessage(FRAME_OPCODE_TEXT, message);
|
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
|
||||||
testMessage(FRAME_OPCODE_BINARY, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test different message sizes.
|
|
||||||
runTest(0, 10, 1);
|
|
||||||
runTest(120, 130, 1);
|
|
||||||
runTest(0, 1000, 100);
|
|
||||||
runTest(65534, 65537, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test processing of frames which are split into fragments.
|
|
||||||
void testFragmentedMessages() {
|
|
||||||
// Use the same web socket protocol transformer for all frames.
|
|
||||||
var transformer = new _WebSocketProtocolTransformer();
|
|
||||||
var controller = new StreamController<List<int>>(sync: true);
|
|
||||||
WebSocketMessageCollector mc =
|
|
||||||
new WebSocketMessageCollector(controller.stream.transform(transformer));
|
|
||||||
|
|
||||||
int messageCount = 0;
|
|
||||||
int frameCount = 0;
|
|
||||||
|
|
||||||
void testFragmentMessage(int opcode, List<int> message, int fragmentSize) {
|
|
||||||
messageCount++;
|
|
||||||
int messageIndex = 0;
|
|
||||||
int remaining = message.length;
|
|
||||||
bool firstFrame = true;
|
|
||||||
bool lastFrame = false;
|
|
||||||
while (!lastFrame) {
|
|
||||||
int payloadSize = min(fragmentSize, remaining);
|
|
||||||
lastFrame = payloadSize == remaining;
|
|
||||||
List<int> frame = createFrame(lastFrame, firstFrame ? opcode : 0x00, null,
|
|
||||||
message, messageIndex, payloadSize);
|
|
||||||
frameCount++;
|
|
||||||
messageIndex += payloadSize;
|
|
||||||
controller.add(frame);
|
|
||||||
remaining -= payloadSize;
|
|
||||||
firstFrame = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testMessageFragmentation(int opcode, List<int> message) {
|
|
||||||
mc.expectedMessage = message;
|
|
||||||
|
|
||||||
// Test with fragmenting the message in different fragment sizes.
|
|
||||||
if (message.length <= 10) {
|
|
||||||
for (int i = 1; i < 10; i++) {
|
|
||||||
testFragmentMessage(opcode, message, i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
testFragmentMessage(opcode, message, 10);
|
|
||||||
testFragmentMessage(opcode, message, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void runTest(int from, int to, int step) {
|
|
||||||
for (int messageLength = from; messageLength < to; messageLength += step) {
|
|
||||||
List<int> message = new List<int>(messageLength);
|
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0x7F;
|
|
||||||
testMessageFragmentation(FRAME_OPCODE_TEXT, message);
|
|
||||||
for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF;
|
|
||||||
testMessageFragmentation(FRAME_OPCODE_BINARY, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test different message sizes.
|
|
||||||
runTest(0, 10, 1);
|
|
||||||
runTest(120, 130, 1);
|
|
||||||
runTest(0, 1000, 100);
|
|
||||||
runTest(65534, 65537, 1);
|
|
||||||
print("Fragment messages test, messages $messageCount, frames $frameCount");
|
|
||||||
Expect.equals(messageCount, mc.messageCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testUnmaskedMessage() {
|
|
||||||
var transformer = new _WebSocketProtocolTransformer(true);
|
|
||||||
var controller = new StreamController<List<int>>(sync: true);
|
|
||||||
asyncStart();
|
|
||||||
controller.stream.transform(transformer).listen((_) {}, onError: (e) {
|
|
||||||
asyncEnd();
|
|
||||||
});
|
|
||||||
var message = new Uint8List(10);
|
|
||||||
List<int> frame =
|
|
||||||
createFrame(true, FRAME_OPCODE_BINARY, null, message, 0, message.length);
|
|
||||||
controller.add(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testFullMessages();
|
|
||||||
testFragmentedMessages();
|
|
||||||
testUnmaskedMessage();
|
|
||||||
}
|
|
Loading…
Reference in a new issue