mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 15:01:30 +00:00
Reland "Revert commits part of #40548 which still has some design debates and breaks valid local network http traffic"
This is a reland of d84f359786
Original change's description:
> Revert commits part of #40548 which still has some design debates and breaks valid local network http traffic
>
> Bug: https://github.com/flutter/flutter/issues/72723
> Change-Id: Ib5f809fccf1fad69add441fd40c463da8dc8be36
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192953
> Auto-Submit: Xiao Yu <xster@google.com>
> Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Bug: https://github.com/flutter/flutter/issues/72723
Change-Id: I466d888b3f324a996f0bef0463e7ab3df3179c56
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195485
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Commit-Queue: Xiao Yu <xster@google.com>
This commit is contained in:
parent
7eda3cfe76
commit
d968304570
28 changed files with 363 additions and 531 deletions
|
@ -170,8 +170,8 @@ Evaluated: MapLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 ->
|
|||
Evaluated: SymbolLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> SymbolConstant(#noFolding)
|
||||
Evaluated: ListLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> ListConstant(const <Type*>[])
|
||||
Evaluated: MapLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
|
||||
Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> SymbolConstant(#clear)
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> ListConstant(const <Type*>[])
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> ListConstant(const <dynamic>[])
|
||||
Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
|
||||
Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> SymbolConstant(#clear)
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> ListConstant(const <Type*>[])
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> ListConstant(const <dynamic>[])
|
||||
Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
|
||||
Extra constant evaluation: evaluated: 268, effectively constant: 91
|
||||
|
|
11
sdk/lib/_http/embedder_config.dart
Normal file
11
sdk/lib/_http/embedder_config.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
part of dart._http;
|
||||
|
||||
/// Embedder-specific `dart:_http` configuration.
|
||||
|
||||
/// [HttpClient] will disallow HTTP URLs if this value is set to `false`.
|
||||
@pragma("vm:entry-point")
|
||||
bool _embedderAllowsHttp = true;
|
|
@ -24,6 +24,7 @@ import 'dart:io';
|
|||
import 'dart:typed_data';
|
||||
|
||||
part 'crypto.dart';
|
||||
part 'embedder_config.dart';
|
||||
part 'http_date.dart';
|
||||
part 'http_headers.dart';
|
||||
part 'http_impl.dart';
|
||||
|
|
|
@ -2620,6 +2620,40 @@ class _HttpClient implements HttpClient {
|
|||
|
||||
set findProxy(String f(Uri uri)?) => _findProxy = f;
|
||||
|
||||
static void _startRequestTimelineEvent(
|
||||
TimelineTask? timeline, String method, Uri uri) {
|
||||
timeline?.start('HTTP CLIENT ${method.toUpperCase()}', arguments: {
|
||||
'method': method.toUpperCase(),
|
||||
'uri': uri.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Whether HTTP requests are currently allowed.
|
||||
///
|
||||
/// If the [Zone] variable `#dart.library.io.allow_http` is set to a boolean,
|
||||
/// it determines whether the HTTP protocol is allowed. If the zone variable
|
||||
/// is set to any other non-null value, HTTP is not allowed.
|
||||
/// Otherwise, if the `dart.library.io.allow_http` environment flag
|
||||
/// is set to `false`, HTTP is not allowed.
|
||||
/// Otherwise, [_embedderAllowsHttp] determines the result.
|
||||
bool get _isHttpAllowed {
|
||||
final zoneOverride = Zone.current[#dart.library.io.allow_http];
|
||||
if (zoneOverride != null) return true == zoneOverride;
|
||||
bool envOverride =
|
||||
bool.fromEnvironment("dart.library.io.allow_http", defaultValue: true);
|
||||
return envOverride && _embedderAllowsHttp;
|
||||
}
|
||||
|
||||
bool _isLoopback(String host) {
|
||||
if (host.isEmpty) return false;
|
||||
if ("localhost" == host) return true;
|
||||
try {
|
||||
return InternetAddress(host).isLoopback;
|
||||
} on ArgumentError {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
|
||||
if (_closing) {
|
||||
throw new StateError("Client is closed");
|
||||
|
@ -2641,9 +2675,11 @@ class _HttpClient implements HttpClient {
|
|||
}
|
||||
|
||||
bool isSecure = uri.isScheme("https");
|
||||
if (!isSecure && !isInsecureConnectionAllowed(uri.host)) {
|
||||
throw new StateError("Insecure HTTP is not allowed by platform: $uri");
|
||||
if (!_isHttpAllowed && !isSecure && !_isLoopback(uri.host)) {
|
||||
throw new StateError(
|
||||
"Insecure HTTP is not allowed by the current platform: $uri");
|
||||
}
|
||||
|
||||
int port = uri.port;
|
||||
if (port == 0) {
|
||||
port =
|
||||
|
|
|
@ -36,13 +36,18 @@ abstract class _EmbedderConfig {
|
|||
/// to all domains.
|
||||
///
|
||||
/// This setting can be overridden by per-domain policies.
|
||||
@Deprecated(
|
||||
"To be re-implemented in https://github.com/flutter/flutter/issues/54448")
|
||||
@pragma('vm:entry-point')
|
||||
static bool _mayInsecurelyConnectToAllDomains = true;
|
||||
|
||||
/// Domain network policies set by embedder.
|
||||
@Deprecated(
|
||||
"To be re-implemented in https://github.com/flutter/flutter/issues/54448")
|
||||
@pragma('vm:entry-point')
|
||||
static void _setDomainPolicies(String domainNetworkPolicyJson) {
|
||||
_domainPolicies = _constructDomainPolicies(domainNetworkPolicyJson);
|
||||
// Doesn't do anything because the implementation has been reverted in
|
||||
// https://github.com/flutter/flutter/issues/72723.
|
||||
}
|
||||
|
||||
// TODO(zra): Consider adding:
|
||||
|
|
|
@ -6,6 +6,9 @@ part of dart.io;
|
|||
|
||||
/// Whether insecure connections to [host] are allowed.
|
||||
///
|
||||
/// This API is deprecated and always returns true. See
|
||||
/// https://github.com/flutter/flutter/issues/72723 for more details.
|
||||
///
|
||||
/// [host] must be a [String] or [InternetAddress].
|
||||
///
|
||||
/// If any of the domain policies match [host], the matching policy will make
|
||||
|
@ -14,179 +17,7 @@ part of dart.io;
|
|||
/// used.
|
||||
///
|
||||
/// Loopback addresses are always allowed.
|
||||
@Deprecated("See https://github.com/flutter/flutter/issues/54448 for followup")
|
||||
bool isInsecureConnectionAllowed(dynamic host) {
|
||||
String hostString;
|
||||
if (host is String) {
|
||||
try {
|
||||
if ("localhost" == host || InternetAddress(host).isLoopback) return true;
|
||||
} on ArgumentError {
|
||||
// Assume not loopback.
|
||||
}
|
||||
hostString = host;
|
||||
} else if (host is InternetAddress) {
|
||||
if (host.isLoopback) return true;
|
||||
hostString = host.host;
|
||||
} else {
|
||||
throw ArgumentError.value(
|
||||
host, "host", "Must be a String or InternetAddress");
|
||||
}
|
||||
final topMatchedPolicy = _findBestDomainNetworkPolicy(hostString);
|
||||
final envOverride = bool.fromEnvironment(
|
||||
"dart.library.io.may_insecurely_connect_to_all_domains",
|
||||
defaultValue: true);
|
||||
return topMatchedPolicy?.allowInsecureConnections ??
|
||||
(envOverride && _EmbedderConfig._mayInsecurelyConnectToAllDomains);
|
||||
}
|
||||
|
||||
/// Policy for a specific domain.
|
||||
///
|
||||
/// [_DomainNetworkPolicy] can be used to create exceptions to the global
|
||||
/// network policy.
|
||||
class _DomainNetworkPolicy {
|
||||
/// https://tools.ietf.org/html/rfc1034#:~:text=Name%20space%20specifications
|
||||
///
|
||||
/// We specifically do not allow IP addresses.
|
||||
static final _domainMatcher = RegExp(
|
||||
r"^(?:[a-z\d-]{1,63}\.)+[a-z][a-z\d-]{0,62}$",
|
||||
caseSensitive: false);
|
||||
|
||||
/// The domain on which the policy is being set.
|
||||
///
|
||||
/// This cannot be a numeric IP address.
|
||||
///
|
||||
/// For example: `example.com`.
|
||||
final String domain;
|
||||
|
||||
/// Whether to allow insecure socket connections for this domain.
|
||||
final bool allowInsecureConnections;
|
||||
|
||||
/// Whether this domain policy covers sub-domains as well.
|
||||
///
|
||||
/// If this is true, all subdomains inherit the same policy. For instance,
|
||||
/// a policy set on `example.com` would apply to `*.example.com` such as
|
||||
/// `subdomain.example.com` or `www.example.com`.
|
||||
final bool includesSubDomains;
|
||||
|
||||
/// Creates a new domain exception in the network policy.
|
||||
///
|
||||
/// [domain] is the domain on which the policy is being set.
|
||||
///
|
||||
/// [includesSubDomains] determines whether the policy applies to
|
||||
/// all sub domains. If this is set to true, all subdomains inherit the
|
||||
/// same policy. For instance, a policy set on `example.com` would apply to
|
||||
/// `*.example.com` such as `subdomain.example.com` or `www.example.com`.
|
||||
///
|
||||
/// [allowInsecureConnections] determines whether to allow insecure socket
|
||||
/// connections for this [domain].
|
||||
_DomainNetworkPolicy(this.domain,
|
||||
{this.includesSubDomains = false,
|
||||
this.allowInsecureConnections = false}) {
|
||||
if (domain.length > 255 || !_domainMatcher.hasMatch(domain)) {
|
||||
throw ArgumentError.value(domain, "domain", "Invalid domain name");
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates how well the policy matches to a given host string.
|
||||
///
|
||||
/// A host matches a [policy] if it ends with its [domain].
|
||||
///
|
||||
/// A score is given to such a match depending on the specificity of the
|
||||
/// [domain]:
|
||||
///
|
||||
/// * A longer domain receives a higher score.
|
||||
/// * A domain that does not allow sub domains receives a higher score.
|
||||
///
|
||||
/// Returns -1 if the policy does not match.
|
||||
int matchScore(String host) {
|
||||
final domainLength = domain.length;
|
||||
final hostLength = host.length;
|
||||
final lengthDelta = hostLength - domainLength;
|
||||
if (host.endsWith(domain) &&
|
||||
(lengthDelta == 0 ||
|
||||
includesSubDomains && host.codeUnitAt(lengthDelta - 1) == 0x2e)) {
|
||||
return domainLength * 2 + (includesSubDomains ? 0 : 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Checks whether the [policy] to be added conflicts with existing policies.
|
||||
///
|
||||
/// Returns [true] if policy is safe to add to existing policy set and [false]
|
||||
/// if policy can safely be ignored.
|
||||
///
|
||||
/// Throws [ArgumentError] if a conflict is detected.
|
||||
bool checkConflict(List<_DomainNetworkPolicy> existingPolicies) {
|
||||
for (final existingPolicy in existingPolicies) {
|
||||
if (includesSubDomains == existingPolicy.includesSubDomains &&
|
||||
domain == existingPolicy.domain) {
|
||||
if (allowInsecureConnections ==
|
||||
existingPolicy.allowInsecureConnections) {
|
||||
// This is a duplicate policy
|
||||
return false;
|
||||
}
|
||||
throw StateError("Contradiction in the domain security policies: "
|
||||
"'$this' contradicts '$existingPolicy'");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This is used for encoding information about the policy in user visible
|
||||
/// errors.
|
||||
@override
|
||||
String toString() {
|
||||
final subDomainPrefix = includesSubDomains ? '*.' : '';
|
||||
final insecureConnectionPermission =
|
||||
allowInsecureConnections ? 'Allows' : 'Disallows';
|
||||
return "$subDomainPrefix$domain: "
|
||||
"$insecureConnectionPermission insecure connections";
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the top [DomainNetworkPolicy] instance that match given a single
|
||||
/// [domain].
|
||||
///
|
||||
/// We order the policies according to how specific they are. The final policy
|
||||
/// for a given [domain] is determined by the top matching
|
||||
/// [DomainNetworkPolicy].
|
||||
///
|
||||
/// Returns null if there's no matching policy.
|
||||
_DomainNetworkPolicy? _findBestDomainNetworkPolicy(String domain) {
|
||||
var topScore = 0;
|
||||
_DomainNetworkPolicy? topPolicy;
|
||||
for (final _DomainNetworkPolicy policy in _domainPolicies) {
|
||||
final score = policy.matchScore(domain);
|
||||
if (score > topScore) {
|
||||
topScore = score;
|
||||
topPolicy = policy;
|
||||
}
|
||||
}
|
||||
return topPolicy;
|
||||
}
|
||||
|
||||
/// Domain level policies that dart:io is enforcing.
|
||||
late List<_DomainNetworkPolicy> _domainPolicies =
|
||||
_constructDomainPolicies(null);
|
||||
|
||||
List<_DomainNetworkPolicy> _constructDomainPolicies(
|
||||
String? domainPoliciesString) {
|
||||
final domainPolicies = <_DomainNetworkPolicy>[];
|
||||
domainPoliciesString ??= String.fromEnvironment(
|
||||
"dart.library.io.domain_network_policies",
|
||||
defaultValue: "");
|
||||
if (domainPoliciesString.isNotEmpty) {
|
||||
final List<dynamic> policiesJson = json.decode(domainPoliciesString);
|
||||
for (final List<dynamic> policyJson in policiesJson) {
|
||||
assert(policyJson.length == 3);
|
||||
final policy = _DomainNetworkPolicy(
|
||||
policyJson[0],
|
||||
includesSubDomains: policyJson[1],
|
||||
allowInsecureConnections: policyJson[2],
|
||||
);
|
||||
if (policy.checkConflict(domainPolicies)) {
|
||||
domainPolicies.add(policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return domainPolicies;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// This test file disallows VM from accepting insecure connections to all
|
||||
// domains and tests that HTTP connections to non-localhost targets fail.
|
||||
// HTTPS connections and localhost connections should still succeed.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
import "http_bind_test.dart";
|
||||
|
||||
Future<String> getLocalHostIP() async {
|
||||
final interfaces = await NetworkInterface.list(
|
||||
includeLoopback: false, type: InternetAddressType.IPv4);
|
||||
return interfaces.first.addresses.first.address;
|
||||
}
|
||||
|
||||
Future<void> testBanHttp(String serverHost,
|
||||
Future<void> testCode(HttpClient client, Uri uri)) async {
|
||||
final httpClient = new HttpClient();
|
||||
final server = await HttpServer.bind(serverHost, 0);
|
||||
final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
|
||||
try {
|
||||
await testCode(httpClient, uri);
|
||||
} finally {
|
||||
httpClient.close(force: true);
|
||||
await server.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testWithLoopback() async {
|
||||
await testBanHttp("127.0.0.1", (httpClient, uri) async {
|
||||
await asyncTest(() async =>
|
||||
await httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
|
||||
await asyncTest(() async =>
|
||||
await httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> testWithIPv6() async {
|
||||
if (await supportsIPV6()) {
|
||||
await testBanHttp("::1", (httpClient, uri) async {
|
||||
await asyncTest(() => httpClient.getUrl(uri));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testWithHttps() async {
|
||||
await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
|
||||
asyncExpectThrows(
|
||||
() => httpClient.getUrl(Uri(
|
||||
scheme: 'https',
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
)),
|
||||
(e) => e is SocketException || e is HandshakeException);
|
||||
});
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
Future.wait(<Future>[
|
||||
testWithLoopback(),
|
||||
testWithIPv6(),
|
||||
testWithHttps(),
|
||||
]).then((_) => asyncEnd());
|
||||
}
|
69
tests/standalone/io/http_ban_http_embedder_test.dart
Normal file
69
tests/standalone/io/http_ban_http_embedder_test.dart
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.allow_http=false
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
import 'http_ban_http_normal_test.dart';
|
||||
import 'http_bind_test.dart';
|
||||
|
||||
Future<void> testWithHostname() async {
|
||||
await testBanHttp(await getLocalHostIP(), (httpClient, httpUri) async {
|
||||
asyncExpectThrows(
|
||||
() async => await httpClient.getUrl(httpUri), (e) => e is StateError);
|
||||
asyncExpectThrows(
|
||||
() async => await runZoned(() => httpClient.getUrl(httpUri),
|
||||
zoneValues: {#dart.library.io.allow_http: 'foo'}),
|
||||
(e) => e is StateError);
|
||||
asyncExpectThrows(
|
||||
() async => await runZoned(() => httpClient.getUrl(httpUri),
|
||||
zoneValues: {#dart.library.io.allow_http: false}),
|
||||
(e) => e is StateError);
|
||||
await asyncTest(() => runZoned(() => httpClient.getUrl(httpUri),
|
||||
zoneValues: {#dart.library.io.allow_http: true}));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> testWithLoopback() async {
|
||||
await testBanHttp("127.0.0.1", (httpClient, uri) async {
|
||||
await asyncTest(
|
||||
() => httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
|
||||
await asyncTest(
|
||||
() => httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> testWithIPv6() async {
|
||||
if (await supportsIPV6()) {
|
||||
await testBanHttp("::1", (httpClient, uri) async {
|
||||
await asyncTest(() => httpClient.getUrl(uri));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testWithHTTPS() async {
|
||||
await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
|
||||
asyncExpectThrows(
|
||||
() => httpClient.getUrl(Uri(
|
||||
scheme: 'https',
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
)),
|
||||
(e) => e is SocketException || e is HandshakeException);
|
||||
});
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
Future.wait(<Future>[
|
||||
testWithHostname(),
|
||||
testWithLoopback(),
|
||||
testWithIPv6(),
|
||||
testWithHTTPS(),
|
||||
]).then((_) => asyncEnd());
|
||||
}
|
44
tests/standalone/io/http_ban_http_normal_test.dart
Normal file
44
tests/standalone/io/http_ban_http_normal_test.dart
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
Future<String> getLocalHostIP() async {
|
||||
final interfaces = await NetworkInterface.list(
|
||||
includeLoopback: false, type: InternetAddressType.IPv4);
|
||||
return interfaces.first.addresses.first.address;
|
||||
}
|
||||
|
||||
Future<void> testBanHttp(String serverHost,
|
||||
Future<void> testCode(HttpClient client, Uri uri)) async {
|
||||
final httpClient = new HttpClient();
|
||||
final server = await HttpServer.bind(serverHost, 0);
|
||||
final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
|
||||
try {
|
||||
await testCode(httpClient, uri);
|
||||
} finally {
|
||||
httpClient.close(force: true);
|
||||
await server.close();
|
||||
}
|
||||
}
|
||||
|
||||
main() async {
|
||||
await asyncTest(() async {
|
||||
final host = await getLocalHostIP();
|
||||
// Normal HTTP request succeeds.
|
||||
await testBanHttp(host, (httpClient, uri) async {
|
||||
await asyncTest(() => httpClient.getUrl(uri));
|
||||
});
|
||||
// We can ban HTTP explicitly.
|
||||
await testBanHttp(host, (httpClient, uri) async {
|
||||
asyncExpectThrows(
|
||||
() async => await runZoned(() => httpClient.getUrl(uri),
|
||||
zoneValues: {#dart.library.io.allow_http: false}),
|
||||
(e) => e is StateError);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// This test file disallows VM from accepting insecure connections to all
|
||||
// domains and tests that HTTP connections to non-localhost targets fail.
|
||||
// HTTPS connections and localhost connections should still succeed.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
Future<void> testWithHostname() async {
|
||||
final httpClient = new HttpClient();
|
||||
final uri = Uri(scheme: 'http', host: 'domain.invalid', port: 12345);
|
||||
asyncExpectThrows(
|
||||
() async => await httpClient.getUrl(uri),
|
||||
(e) =>
|
||||
e is StateError &&
|
||||
e.message.contains("Insecure HTTP is not allowed by platform"));
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
testWithHostname().then((_) => asyncEnd());
|
||||
}
|
|
@ -19,6 +19,7 @@ import "../../../sdk/lib/internal/internal.dart"
|
|||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
|
||||
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";
|
||||
|
|
|
@ -19,6 +19,7 @@ import "../../../sdk/lib/internal/internal.dart"
|
|||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
|
||||
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";
|
||||
|
|
|
@ -19,6 +19,7 @@ import "../../../sdk/lib/internal/internal.dart"
|
|||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
|
||||
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";
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.domain_network_policies=[["foobar.com",true,true],["foobar.com",true,true],["baz.foobar.com",true,true],["baz.foobar.com",false,false]] -Ddart.library.io.may_insecurely_connect_to_all_domains=false
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void _checkAllows(List<String> domains) {
|
||||
for (final domain in domains) {
|
||||
Expect.isTrue(
|
||||
isInsecureConnectionAllowed(domain), "$domain should be allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
void _checkDenies(List<String> domains) {
|
||||
for (final domain in domains) {
|
||||
Expect.isFalse(
|
||||
isInsecureConnectionAllowed(domain), "$domain should not be allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// These have no policy but the default is false.
|
||||
_checkDenies([
|
||||
"mailfoobar.com",
|
||||
"abc.com",
|
||||
"oobar.com",
|
||||
"foobar.co",
|
||||
"128.221.55.31",
|
||||
"fe80::4607:0bff:fea0:7747%invalid",
|
||||
]);
|
||||
// These are explicitly denied.
|
||||
_checkDenies(["baz.foobar.com"]);
|
||||
_checkAllows(
|
||||
["foobar.com", "test.baz.foobar.com", "test2.test.baz.foobar.com"]);
|
||||
_checkAllows(["::1", "localhost"]);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.domain_network_policies=[["com",true,true]]
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
// This test passes in an invalid domain as a network policy and checks that
|
||||
// loading the policies throws.
|
||||
void main() {
|
||||
Expect.throwsArgumentError(() => isInsecureConnectionAllowed("test.com"));
|
||||
}
|
32
tests/standalone/io/network_policy_test.dart
Normal file
32
tests/standalone/io/network_policy_test.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void _checkAllows(List<String> domains) {
|
||||
for (final domain in domains) {
|
||||
Expect.isTrue(
|
||||
isInsecureConnectionAllowed(domain), "$domain should be allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// All domains and addresses are allowed.
|
||||
_checkAllows([
|
||||
"mailfoobar.com",
|
||||
"abc.com",
|
||||
"oobar.com",
|
||||
"foobar.co",
|
||||
"128.221.55.31",
|
||||
"fe80::4607:0bff:fea0:7747%invalid",
|
||||
"baz.foobar.com",
|
||||
"foobar.com",
|
||||
"test.baz.foobar.com",
|
||||
"test2.test.baz.foobar.com",
|
||||
"::1",
|
||||
"localhost",
|
||||
]);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.domain_network_policies=[["baz.foobar.com",true,true],["baz.foobar.com",false,false]]
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void main() {
|
||||
Expect.isFalse(isInsecureConnectionAllowed("baz.foobar.com"));
|
||||
Expect.isTrue(isInsecureConnectionAllowed("test.baz.foobar.com"));
|
||||
}
|
|
@ -20,6 +20,7 @@ import "../../../sdk/lib/internal/internal.dart"
|
|||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
|
||||
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";
|
||||
|
|
|
@ -12,10 +12,8 @@ fragmentation_typed_data_test: Skip # This test crashes on the bot, but not loca
|
|||
|
||||
[ $system == android ]
|
||||
entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
|
||||
io/http_ban_http_allowed_cases_test: Skip # Depends on grabbing local hostname which isn't supported.
|
||||
io/network_policy_configuration_test: Skip # Can't pass -D params containing quotes to adb.
|
||||
io/network_policy_invalid_domain_test: Skip # Can't pass -D params containing quotes to adb.
|
||||
io/network_policy_tie_breaker_test: Skip # Can't pass -D params containing quotes to adb.
|
||||
io/http_ban_http_embedder_test: Skip # Requires http server bound to non-loopback; not provided by system.
|
||||
io/http_ban_http_normal_test: Skip # Requires http server bound to non-loopback; not provided by system.
|
||||
|
||||
[ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
|
||||
io/file_lock_test: SkipSlow # Timeout
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// This test file disallows VM from accepting insecure connections to all
|
||||
// domains and tests that HTTP connections to non-localhost targets fail.
|
||||
// HTTPS connections and localhost connections should still succeed.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
import "http_bind_test.dart";
|
||||
|
||||
Future<String> getLocalHostIP() async {
|
||||
final interfaces = await NetworkInterface.list(
|
||||
includeLoopback: false, type: InternetAddressType.IPv4);
|
||||
return interfaces.first.addresses.first.address;
|
||||
}
|
||||
|
||||
Future<void> testBanHttp(String serverHost,
|
||||
Future<void> testCode(HttpClient client, Uri uri)) async {
|
||||
final httpClient = new HttpClient();
|
||||
final server = await HttpServer.bind(serverHost, 0);
|
||||
final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
|
||||
try {
|
||||
await testCode(httpClient, uri);
|
||||
} finally {
|
||||
httpClient.close(force: true);
|
||||
await server.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testWithLoopback() async {
|
||||
await testBanHttp("127.0.0.1", (httpClient, uri) async {
|
||||
await asyncTest(() async =>
|
||||
await httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
|
||||
await asyncTest(() async =>
|
||||
await httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> testWithIPv6() async {
|
||||
if (await supportsIPV6()) {
|
||||
await testBanHttp("::1", (httpClient, uri) async {
|
||||
await asyncTest(() => httpClient.getUrl(uri));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testWithHttps() async {
|
||||
await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
|
||||
asyncExpectThrows(
|
||||
() => httpClient.getUrl(Uri(
|
||||
scheme: 'https',
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
)),
|
||||
(e) => e is SocketException || e is HandshakeException);
|
||||
});
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
Future.wait(<Future>[
|
||||
testWithLoopback(),
|
||||
testWithIPv6(),
|
||||
testWithHttps(),
|
||||
]).then((_) => asyncEnd());
|
||||
}
|
69
tests/standalone_2/io/http_ban_http_embedder_test.dart
Normal file
69
tests/standalone_2/io/http_ban_http_embedder_test.dart
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.allow_http=false
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
import 'http_ban_http_normal_test.dart';
|
||||
import 'http_bind_test.dart';
|
||||
|
||||
Future<void> testWithHostname() async {
|
||||
await testBanHttp(await getLocalHostIP(), (httpClient, httpUri) async {
|
||||
asyncExpectThrows(
|
||||
() async => await httpClient.getUrl(httpUri), (e) => e is StateError);
|
||||
asyncExpectThrows(
|
||||
() async => await runZoned(() => httpClient.getUrl(httpUri),
|
||||
zoneValues: {#dart.library.io.allow_http: 'foo'}),
|
||||
(e) => e is StateError);
|
||||
asyncExpectThrows(
|
||||
() async => await runZoned(() => httpClient.getUrl(httpUri),
|
||||
zoneValues: {#dart.library.io.allow_http: false}),
|
||||
(e) => e is StateError);
|
||||
await asyncTest(() => runZoned(() => httpClient.getUrl(httpUri),
|
||||
zoneValues: {#dart.library.io.allow_http: true}));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> testWithLoopback() async {
|
||||
await testBanHttp("127.0.0.1", (httpClient, uri) async {
|
||||
await asyncTest(
|
||||
() => httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
|
||||
await asyncTest(
|
||||
() => httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> testWithIPv6() async {
|
||||
if (await supportsIPV6()) {
|
||||
await testBanHttp("::1", (httpClient, uri) async {
|
||||
await asyncTest(() => httpClient.getUrl(uri));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testWithHTTPS() async {
|
||||
await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
|
||||
asyncExpectThrows(
|
||||
() => httpClient.getUrl(Uri(
|
||||
scheme: 'https',
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
)),
|
||||
(e) => e is SocketException || e is HandshakeException);
|
||||
});
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
Future.wait(<Future>[
|
||||
testWithHostname(),
|
||||
testWithLoopback(),
|
||||
testWithIPv6(),
|
||||
testWithHTTPS(),
|
||||
]).then((_) => asyncEnd());
|
||||
}
|
44
tests/standalone_2/io/http_ban_http_normal_test.dart
Normal file
44
tests/standalone_2/io/http_ban_http_normal_test.dart
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
Future<String> getLocalHostIP() async {
|
||||
final interfaces = await NetworkInterface.list(
|
||||
includeLoopback: false, type: InternetAddressType.IPv4);
|
||||
return interfaces.first.addresses.first.address;
|
||||
}
|
||||
|
||||
Future<void> testBanHttp(String serverHost,
|
||||
Future<void> testCode(HttpClient client, Uri uri)) async {
|
||||
final httpClient = new HttpClient();
|
||||
final server = await HttpServer.bind(serverHost, 0);
|
||||
final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
|
||||
try {
|
||||
await testCode(httpClient, uri);
|
||||
} finally {
|
||||
httpClient.close(force: true);
|
||||
await server.close();
|
||||
}
|
||||
}
|
||||
|
||||
main() async {
|
||||
await asyncTest(() async {
|
||||
final host = await getLocalHostIP();
|
||||
// Normal HTTP request succeeds.
|
||||
await testBanHttp(host, (httpClient, uri) async {
|
||||
await asyncTest(() => httpClient.getUrl(uri));
|
||||
});
|
||||
// We can ban HTTP explicitly.
|
||||
await testBanHttp(host, (httpClient, uri) async {
|
||||
asyncExpectThrows(
|
||||
() async => await runZoned(() => httpClient.getUrl(uri),
|
||||
zoneValues: {#dart.library.io.allow_http: false}),
|
||||
(e) => e is StateError);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// This test file disallows VM from accepting insecure connections to all
|
||||
// domains and tests that HTTP connections to non-localhost targets fail.
|
||||
// HTTPS connections and localhost connections should still succeed.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
Future<void> testWithHostname() async {
|
||||
final httpClient = new HttpClient();
|
||||
final uri = Uri(scheme: 'http', host: 'domain.invalid', port: 12345);
|
||||
asyncExpectThrows(
|
||||
() async => await httpClient.getUrl(uri),
|
||||
(e) =>
|
||||
e is StateError &&
|
||||
e.message.contains("Insecure HTTP is not allowed by platform"));
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
testWithHostname().then((_) => asyncEnd());
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.domain_network_policies=[["foobar.com",true,true],["foobar.com",true,true],["baz.foobar.com",true,true],["baz.foobar.com",false,false]] -Ddart.library.io.may_insecurely_connect_to_all_domains=false
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void _checkAllows(List<String> domains) {
|
||||
for (final domain in domains) {
|
||||
Expect.isTrue(
|
||||
isInsecureConnectionAllowed(domain), "$domain should be allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
void _checkDenies(List<String> domains) {
|
||||
for (final domain in domains) {
|
||||
Expect.isFalse(
|
||||
isInsecureConnectionAllowed(domain), "$domain should not be allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// These have no policy but the default is false.
|
||||
_checkDenies([
|
||||
"mailfoobar.com",
|
||||
"abc.com",
|
||||
"oobar.com",
|
||||
"foobar.co",
|
||||
"128.221.55.31",
|
||||
"fe80::4607:0bff:fea0:7747%invalid",
|
||||
]);
|
||||
// These are explicitly denied.
|
||||
_checkDenies(["baz.foobar.com"]);
|
||||
_checkAllows(
|
||||
["foobar.com", "test.baz.foobar.com", "test2.test.baz.foobar.com"]);
|
||||
_checkAllows(["::1", "localhost"]);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.domain_network_policies=[["com",true,true]]
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
// This test passes in an invalid domain as a network policy and checks that
|
||||
// loading the policies throws.
|
||||
void main() {
|
||||
Expect.throwsArgumentError(() => isInsecureConnectionAllowed("test.com"));
|
||||
}
|
32
tests/standalone_2/io/network_policy_test.dart
Normal file
32
tests/standalone_2/io/network_policy_test.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void _checkAllows(List<String> domains) {
|
||||
for (final domain in domains) {
|
||||
Expect.isTrue(
|
||||
isInsecureConnectionAllowed(domain), "$domain should be allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// All domains and addresses are allowed.
|
||||
_checkAllows([
|
||||
"mailfoobar.com",
|
||||
"abc.com",
|
||||
"oobar.com",
|
||||
"foobar.co",
|
||||
"128.221.55.31",
|
||||
"fe80::4607:0bff:fea0:7747%invalid",
|
||||
"baz.foobar.com",
|
||||
"foobar.com",
|
||||
"test.baz.foobar.com",
|
||||
"test2.test.baz.foobar.com",
|
||||
"::1",
|
||||
"localhost",
|
||||
]);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
// SharedOptions=-Ddart.library.io.domain_network_policies=[["baz.foobar.com",true,true],["baz.foobar.com",false,false]]
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void main() {
|
||||
Expect.isFalse(isInsecureConnectionAllowed("baz.foobar.com"));
|
||||
Expect.isTrue(isInsecureConnectionAllowed("test.baz.foobar.com"));
|
||||
}
|
|
@ -14,10 +14,8 @@ fragmentation_typed_data_test: Skip # This test crashes on the bot, but not loca
|
|||
|
||||
[ $system == android ]
|
||||
entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
|
||||
io/http_ban_http_allowed_cases_test: Skip # Depends on grabbing local hostname which isn't supported.
|
||||
io/network_policy_configuration_test: Skip # Can't pass -D params containing quotes to adb.
|
||||
io/network_policy_invalid_domain_test: Skip # Can't pass -D params containing quotes to adb.
|
||||
io/network_policy_tie_breaker_test: Skip # Can't pass -D params containing quotes to adb.
|
||||
io/http_ban_http_embedder_test: Skip # Requires http server bound to non-loopback; not provided by system.
|
||||
io/http_ban_http_normal_test: Skip # Requires http server bound to non-loopback; not provided by system.
|
||||
|
||||
[ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
|
||||
io/file_lock_test: SkipSlow # Timeout
|
||||
|
|
Loading…
Reference in a new issue