Call _isLoopback as a last resort (flutter/engine#28576)

This commit is contained in:
Bruno Leroux 2021-09-15 17:47:01 +02:00 committed by GitHub
parent 41a964c47e
commit cf0c1b8c2a
2 changed files with 55 additions and 5 deletions

View File

@ -249,20 +249,22 @@ bool _isLoopback(String host) {
// ignore: unused_element
void Function(Uri) _getHttpConnectionHookClosure(bool mayInsecurelyConnectToAllDomains) {
return (Uri uri) {
if (_isLoopback(uri.host)) {
return;
}
final dynamic zoneOverride = Zone.current[#flutter.io.allow_http];
if (zoneOverride == true) {
return;
}
if (zoneOverride == false && uri.isScheme('http')) {
// Going to throw
// Going to _isLoopback check before throwing
} else if (mayInsecurelyConnectToAllDomains || uri.isScheme('https')) {
// In absence of zone override, if engine setting allows the connection
// or if connection is to `https`, allow the connection.
return;
}
// Loopback connections are always allowed
// Check at last resort to avoid debug annoyance of try/on ArgumentError
if (_isLoopback(uri.host)) {
return;
}
throw UnsupportedError(
'Non-https connection "$uri" is not supported by the platform. '
'Refer to https://flutter.dev/docs/release/breaking-changes/network-policy-ios-android.');

View File

@ -52,7 +52,7 @@ Future<bool> _supportsIPv6() async {
}
void main() {
test('testWithHostname', () async {
test('testWithLocalIP', () async {
await bindServerAndTest(await getLocalHostIP(), (HttpClient httpClient, Uri httpUri) async {
asyncExpectThrows<UnsupportedError>(
() async => httpClient.getUrl(httpUri));
@ -67,6 +67,30 @@ void main() {
});
});
test('testWithHostname', () async {
await bindServerAndTest(Platform.localHostname, (HttpClient httpClient, Uri httpUri) async {
asyncExpectThrows<UnsupportedError>(
() async => httpClient.getUrl(httpUri));
final _MockZoneValue mockFoo = _MockZoneValue('foo');
asyncExpectThrows<UnsupportedError>(
() async => runZoned(() => httpClient.getUrl(httpUri),
zoneValues: <dynamic, dynamic>{#flutter.io.allow_http: mockFoo}));
expect(mockFoo.checked, isTrue);
final _MockZoneValue mockFalse = _MockZoneValue(false);
asyncExpectThrows<UnsupportedError>(
() async => runZoned(() => httpClient.getUrl(httpUri),
zoneValues: <dynamic, dynamic>{#flutter.io.allow_http: mockFalse}));
expect(mockFalse.checked, isTrue);
final _MockZoneValue mockTrue = _MockZoneValue(true);
await runZoned(() => httpClient.getUrl(httpUri),
zoneValues: <dynamic, dynamic>{#flutter.io.allow_http: mockTrue});
expect(mockFalse.checked, isTrue);
});
});
test('testWithLoopback', () async {
await bindServerAndTest('127.0.0.1', (HttpClient httpClient, Uri uri) async {
await httpClient.getUrl(Uri.parse('http://localhost:${uri.port}'));
@ -82,3 +106,27 @@ void main() {
}
});
}
class _MockZoneValue {
_MockZoneValue(this._value);
Object? _value;
bool _falseChecked = false;
bool _trueChecked = false;
@override
bool operator ==(Object o) {
if(o == true) {
_trueChecked = true;
}
if(o == false) {
_falseChecked = true;
}
return _value == o;
}
bool get checked => _falseChecked && _trueChecked;
@override
int get hashCode => _value.hashCode;
}