mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

* Fix typos * lowercase animated & opacity * Undo typo fix --------- Co-authored-by: Michael Goderbauer <goderbauer@google.com>
150 lines
5.2 KiB
Dart
150 lines
5.2 KiB
Dart
// Copyright 2014 The Flutter Authors. 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 'base/io.dart';
|
|
import 'base/net.dart';
|
|
import 'base/platform.dart';
|
|
import 'doctor_validator.dart';
|
|
import 'features.dart';
|
|
|
|
/// Common Flutter HTTP hosts.
|
|
const String kCloudHost = 'https://storage.googleapis.com/';
|
|
const String kCocoaPods = 'https://cocoapods.org/';
|
|
const String kGitHub = 'https://github.com/';
|
|
const String kMaven = 'https://maven.google.com/';
|
|
const String kPubDev = 'https://pub.dev/';
|
|
|
|
// Overridable environment variables.
|
|
const String kPubDevOverride = 'PUB_HOSTED_URL'; // https://dart.dev/tools/pub/environment-variables
|
|
|
|
// Validator that checks all provided hosts are reachable and responsive
|
|
class HttpHostValidator extends DoctorValidator {
|
|
HttpHostValidator({
|
|
required Platform platform,
|
|
required FeatureFlags featureFlags,
|
|
required HttpClient httpClient,
|
|
}) : _platform = platform,
|
|
_featureFlags = featureFlags,
|
|
_httpClient = httpClient,
|
|
super('Network resources');
|
|
|
|
final Platform _platform;
|
|
final FeatureFlags _featureFlags;
|
|
final HttpClient _httpClient;
|
|
|
|
final Set<Uri> _activeHosts = <Uri>{};
|
|
|
|
@override
|
|
String get slowWarning {
|
|
if (_activeHosts.isEmpty) {
|
|
return 'Network resources check is taking a long time...';
|
|
}
|
|
return 'Attempting to reach ${_activeHosts.map((Uri url) => url.host).join(", ")}...';
|
|
}
|
|
|
|
/// Make a head request to the HTTP host for checking availability
|
|
Future<String?> _checkHostAvailability(Uri host) async {
|
|
try {
|
|
assert(!_activeHosts.contains(host));
|
|
_activeHosts.add(host);
|
|
final HttpClientRequest req = await _httpClient.headUrl(host);
|
|
await req.close();
|
|
// HTTP host is available if no exception happened.
|
|
return null;
|
|
} on SocketException catch (error) {
|
|
return 'A network error occurred while checking "$host": ${error.message}';
|
|
} on HttpException catch (error) {
|
|
return 'An HTTP error occurred while checking "$host": ${error.message}';
|
|
} on HandshakeException catch (error) {
|
|
return 'A cryptographic error occurred while checking "$host": ${error.message}\n'
|
|
'You may be experiencing a man-in-the-middle attack, your network may be '
|
|
'compromised, or you may have malware installed on your computer.';
|
|
} on OSError catch (error) {
|
|
return 'An error occurred while checking "$host": ${error.message}';
|
|
} finally {
|
|
_activeHosts.remove(host);
|
|
}
|
|
}
|
|
|
|
static Uri? _parseUrl(String value) {
|
|
final Uri? url = Uri.tryParse(value);
|
|
if (url == null || !url.hasScheme || !url.hasAuthority || (!url.hasEmptyPath && !url.hasAbsolutePath) || url.hasFragment) {
|
|
return null;
|
|
}
|
|
return url;
|
|
}
|
|
|
|
@override
|
|
Future<ValidationResult> validate() async {
|
|
final List<String?> availabilityResults = <String?>[];
|
|
|
|
final List<Uri> requiredHosts = <Uri>[];
|
|
if (_platform.environment.containsKey(kPubDevOverride)) {
|
|
final Uri? url = _parseUrl(_platform.environment[kPubDevOverride]!);
|
|
if (url == null) {
|
|
availabilityResults.add(
|
|
'Environment variable $kPubDevOverride does not specify a valid URL: "${_platform.environment[kPubDevOverride]}"\n'
|
|
'Please see https://flutter.dev/community/china for an example of how to use it.'
|
|
);
|
|
} else {
|
|
requiredHosts.add(url);
|
|
}
|
|
} else {
|
|
requiredHosts.add(Uri.parse(kPubDev));
|
|
}
|
|
if (_platform.environment.containsKey(kFlutterStorageBaseUrl)) {
|
|
final Uri? url = _parseUrl(_platform.environment[kFlutterStorageBaseUrl]!);
|
|
if (url == null) {
|
|
availabilityResults.add(
|
|
'Environment variable $kFlutterStorageBaseUrl does not specify a valid URL: "${_platform.environment[kFlutterStorageBaseUrl]}"\n'
|
|
'Please see https://flutter.dev/community/china for an example of how to use it.'
|
|
);
|
|
} else {
|
|
requiredHosts.add(url);
|
|
}
|
|
} else {
|
|
requiredHosts.add(Uri.parse(kCloudHost));
|
|
if (_featureFlags.isAndroidEnabled) {
|
|
// if kFlutterStorageBaseUrl is set it is used instead of Maven
|
|
requiredHosts.add(Uri.parse(kMaven));
|
|
}
|
|
}
|
|
if (_featureFlags.isMacOSEnabled) {
|
|
requiredHosts.add(Uri.parse(kCocoaPods));
|
|
}
|
|
requiredHosts.add(Uri.parse(kGitHub));
|
|
|
|
// Check all the hosts simultaneously.
|
|
availabilityResults.addAll(await Future.wait<String?>(requiredHosts.map(_checkHostAvailability)));
|
|
|
|
int failures = 0;
|
|
int successes = 0;
|
|
final List<ValidationMessage> messages = <ValidationMessage>[];
|
|
for (final String? message in availabilityResults) {
|
|
if (message == null) {
|
|
successes += 1;
|
|
} else {
|
|
failures += 1;
|
|
messages.add(ValidationMessage.error(message));
|
|
}
|
|
}
|
|
|
|
if (failures == 0) {
|
|
assert(successes > 0);
|
|
assert(messages.isEmpty);
|
|
return const ValidationResult(
|
|
ValidationType.success,
|
|
<ValidationMessage>[ValidationMessage('All expected network resources are available.')],
|
|
);
|
|
}
|
|
assert(messages.isNotEmpty);
|
|
return ValidationResult(
|
|
successes == 0 ? ValidationType.notAvailable : ValidationType.partial,
|
|
messages,
|
|
);
|
|
}
|
|
}
|