
This change removes calls to base::UTF8ToUTF16 with a single-line string literal not containing escape sequences and replaces them with a u"..." literal instead. This is a mechanical change: $ git grep -lw UTF8ToUTF16 | \ xargs sed -i 's/\(base::\)\?UTF8ToUTF16(\("[^\\"]*"\))/u\2/g' $ git cl format AX-Relnotes: n/a. Bug: 1189439 Change-Id: I6df2e531f62926a12be3f610ce8627d94ec407f6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2776021 Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org> Commit-Queue: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Owners-Override: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/master@{#865390}
662 lines
25 KiB
C++
662 lines
25 KiB
C++
// Copyright 2017 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "content/browser/network_service_instance_impl.h"
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "base/bind.h"
|
|
#include "base/callback_helpers.h"
|
|
#include "base/environment.h"
|
|
#include "base/feature_list.h"
|
|
#include "base/files/file.h"
|
|
#include "base/message_loop/message_pump_type.h"
|
|
#include "base/metrics/histogram_macros.h"
|
|
#include "base/no_destructor.h"
|
|
#include "base/sequenced_task_runner.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "base/synchronization/waitable_event.h"
|
|
#include "base/threading/sequence_local_storage_slot.h"
|
|
#include "base/threading/thread.h"
|
|
#include "base/threading/thread_restrictions.h"
|
|
#include "build/build_config.h"
|
|
#include "build/chromeos_buildflags.h"
|
|
#include "content/browser/browser_main_loop.h"
|
|
#include "content/browser/network_service_client.h"
|
|
#include "content/browser/service_sandbox_type.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/browser/content_browser_client.h"
|
|
#include "content/public/browser/network_service_instance.h"
|
|
#include "content/public/browser/service_process_host.h"
|
|
#include "content/public/common/content_client.h"
|
|
#include "content/public/common/network_service_util.h"
|
|
#include "mojo/public/cpp/bindings/pending_receiver.h"
|
|
#include "mojo/public/cpp/bindings/remote.h"
|
|
#include "net/log/net_log_util.h"
|
|
#include "services/cert_verifier/cert_verifier_service_factory.h"
|
|
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
|
|
#include "services/network/network_service.h"
|
|
#include "services/network/public/cpp/features.h"
|
|
#include "services/network/public/cpp/network_switches.h"
|
|
#include "services/network/public/mojom/net_log.mojom.h"
|
|
#include "services/network/public/mojom/network_change_manager.mojom.h"
|
|
#include "services/network/public/mojom/network_service.mojom.h"
|
|
#include "services/network/public/mojom/network_service_test.mojom.h"
|
|
|
|
#if !defined(OS_MAC)
|
|
#include "sandbox/policy/features.h"
|
|
#endif
|
|
|
|
#if defined(OS_WIN)
|
|
#include "base/metrics/histogram_functions.h"
|
|
#include "base/win/registry.h"
|
|
#include "base/win/windows_version.h"
|
|
#endif // defined(OS_WIN)
|
|
|
|
namespace content {
|
|
|
|
namespace {
|
|
|
|
#if defined(OS_POSIX)
|
|
// Environment variable pointing to credential cache file.
|
|
constexpr char kKrb5CCEnvName[] = "KRB5CCNAME";
|
|
// Environment variable pointing to Kerberos config file.
|
|
constexpr char kKrb5ConfEnvName[] = "KRB5_CONFIG";
|
|
#endif
|
|
|
|
bool g_force_create_network_service_directly = false;
|
|
mojo::Remote<network::mojom::NetworkService>* g_network_service_remote =
|
|
nullptr;
|
|
network::NetworkConnectionTracker* g_network_connection_tracker;
|
|
bool g_network_service_is_responding = false;
|
|
base::Time g_last_network_service_crash;
|
|
|
|
std::unique_ptr<network::NetworkService>& GetLocalNetworkService() {
|
|
static base::NoDestructor<
|
|
base::SequenceLocalStorageSlot<std::unique_ptr<network::NetworkService>>>
|
|
service;
|
|
return service->GetOrCreateValue();
|
|
}
|
|
|
|
// If this feature is enabled, the Network Service will run on its own thread
|
|
// when running in-process; otherwise it will run on the IO thread.
|
|
//
|
|
// On Chrome OS, the Network Service must run on the IO thread because
|
|
// ProfileIOData and NetworkContext both try to set up NSS, which has to be
|
|
// called from the IO thread.
|
|
const base::Feature kNetworkServiceDedicatedThread {
|
|
"NetworkServiceDedicatedThread",
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
base::FEATURE_DISABLED_BY_DEFAULT
|
|
#else
|
|
base::FEATURE_ENABLED_BY_DEFAULT
|
|
#endif
|
|
};
|
|
|
|
base::Thread& GetNetworkServiceDedicatedThread() {
|
|
static base::NoDestructor<base::Thread> thread{"NetworkService"};
|
|
DCHECK(base::FeatureList::IsEnabled(kNetworkServiceDedicatedThread));
|
|
return *thread;
|
|
}
|
|
|
|
// The instance NetworkService used when hosting the service in-process. This is
|
|
// set up by |CreateInProcessNetworkServiceOnThread()| and destroyed by
|
|
// |ShutDownNetworkService()|.
|
|
network::NetworkService* g_in_process_instance = nullptr;
|
|
|
|
static NetworkServiceClient* g_client = nullptr;
|
|
|
|
void CreateInProcessNetworkServiceOnThread(
|
|
mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
|
|
// The test interface doesn't need to be implemented in the in-process case.
|
|
auto registry = std::make_unique<service_manager::BinderRegistry>();
|
|
registry->AddInterface(
|
|
base::DoNothing::Repeatedly<
|
|
mojo::PendingReceiver<network::mojom::NetworkServiceTest>>());
|
|
g_in_process_instance = new network::NetworkService(
|
|
std::move(registry), std::move(receiver),
|
|
true /* delay_initialization_until_set_client */);
|
|
}
|
|
|
|
scoped_refptr<base::SequencedTaskRunner>& GetNetworkTaskRunnerStorage() {
|
|
static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>> storage;
|
|
return *storage;
|
|
}
|
|
|
|
void CreateInProcessNetworkService(
|
|
mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
|
|
scoped_refptr<base::SingleThreadTaskRunner> task_runner;
|
|
if (base::FeatureList::IsEnabled(kNetworkServiceDedicatedThread)) {
|
|
base::Thread::Options options(base::MessagePumpType::IO, 0);
|
|
GetNetworkServiceDedicatedThread().StartWithOptions(options);
|
|
task_runner = GetNetworkServiceDedicatedThread().task_runner();
|
|
} else {
|
|
task_runner = GetIOThreadTaskRunner({});
|
|
}
|
|
|
|
GetNetworkTaskRunnerStorage() = std::move(task_runner);
|
|
|
|
GetNetworkTaskRunner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&CreateInProcessNetworkServiceOnThread,
|
|
std::move(receiver)));
|
|
}
|
|
|
|
network::mojom::NetworkServiceParamsPtr CreateNetworkServiceParams() {
|
|
network::mojom::NetworkServiceParamsPtr network_service_params =
|
|
network::mojom::NetworkServiceParams::New();
|
|
network_service_params->initial_connection_type =
|
|
network::mojom::ConnectionType(
|
|
net::NetworkChangeNotifier::GetConnectionType());
|
|
network_service_params->initial_connection_subtype =
|
|
network::mojom::ConnectionSubtype(
|
|
net::NetworkChangeNotifier::GetConnectionSubtype());
|
|
network_service_params->default_observer =
|
|
g_client->BindURLLoaderNetworkServiceObserver();
|
|
#if defined(OS_POSIX)
|
|
// Send Kerberos environment variables to the network service.
|
|
if (IsOutOfProcessNetworkService()) {
|
|
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
|
std::string value;
|
|
if (env->HasVar(kKrb5CCEnvName)) {
|
|
env->GetVar(kKrb5CCEnvName, &value);
|
|
network_service_params->environment.push_back(
|
|
network::mojom::EnvironmentVariable::New(kKrb5CCEnvName, value));
|
|
}
|
|
if (env->HasVar(kKrb5ConfEnvName)) {
|
|
env->GetVar(kKrb5ConfEnvName, &value);
|
|
network_service_params->environment.push_back(
|
|
network::mojom::EnvironmentVariable::New(kKrb5ConfEnvName, value));
|
|
}
|
|
}
|
|
#endif
|
|
return network_service_params;
|
|
}
|
|
|
|
void CreateNetworkServiceOnIOForTesting(
|
|
mojo::PendingReceiver<network::mojom::NetworkService> receiver,
|
|
base::WaitableEvent* completion_event) {
|
|
if (GetLocalNetworkService()) {
|
|
GetLocalNetworkService()->Bind(std::move(receiver));
|
|
return;
|
|
}
|
|
|
|
GetLocalNetworkService() = std::make_unique<network::NetworkService>(
|
|
nullptr /* registry */, std::move(receiver),
|
|
true /* delay_initialization_until_set_client */);
|
|
GetLocalNetworkService()->Initialize(
|
|
network::mojom::NetworkServiceParams::New(),
|
|
true /* mock_network_change_notifier */);
|
|
if (completion_event)
|
|
completion_event->Signal();
|
|
}
|
|
|
|
void BindNetworkChangeManagerReceiver(
|
|
mojo::PendingReceiver<network::mojom::NetworkChangeManager> receiver) {
|
|
GetNetworkService()->GetNetworkChangeManager(std::move(receiver));
|
|
}
|
|
|
|
base::RepeatingClosureList& GetCrashHandlersList() {
|
|
static base::NoDestructor<base::RepeatingClosureList> s_list;
|
|
return *s_list;
|
|
}
|
|
|
|
void OnNetworkServiceCrash() {
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
DCHECK(g_network_service_remote);
|
|
DCHECK(g_network_service_remote->is_bound());
|
|
DCHECK(!g_network_service_remote->is_connected());
|
|
g_last_network_service_crash = base::Time::Now();
|
|
GetCrashHandlersList().Notify();
|
|
}
|
|
|
|
// Parses the desired granularity of NetLog capturing specified by the command
|
|
// line.
|
|
net::NetLogCaptureMode GetNetCaptureModeFromCommandLine(
|
|
const base::CommandLine& command_line) {
|
|
base::StringPiece switch_name = network::switches::kNetLogCaptureMode;
|
|
|
|
if (command_line.HasSwitch(switch_name)) {
|
|
std::string value = command_line.GetSwitchValueASCII(switch_name);
|
|
|
|
if (value == "Default")
|
|
return net::NetLogCaptureMode::kDefault;
|
|
if (value == "IncludeSensitive")
|
|
return net::NetLogCaptureMode::kIncludeSensitive;
|
|
if (value == "Everything")
|
|
return net::NetLogCaptureMode::kEverything;
|
|
|
|
// Warn when using the old command line switches.
|
|
if (value == "IncludeCookiesAndCredentials") {
|
|
LOG(ERROR) << "Deprecated value for --" << switch_name
|
|
<< ". Use IncludeSensitive instead";
|
|
return net::NetLogCaptureMode::kIncludeSensitive;
|
|
}
|
|
if (value == "IncludeSocketBytes") {
|
|
LOG(ERROR) << "Deprecated value for --" << switch_name
|
|
<< ". Use Everything instead";
|
|
return net::NetLogCaptureMode::kEverything;
|
|
}
|
|
|
|
LOG(ERROR) << "Unrecognized value for --" << switch_name;
|
|
}
|
|
|
|
return net::NetLogCaptureMode::kDefault;
|
|
}
|
|
|
|
#if defined(OS_WIN)
|
|
// This enum is used to record a histogram and should not be renumbered.
|
|
enum class ServiceStatus {
|
|
kUnknown = 0,
|
|
kNotFound = 1,
|
|
kFound = 2,
|
|
kMaxValue = kFound
|
|
};
|
|
|
|
ServiceStatus DetectSecurityProviders() {
|
|
// https://docs.microsoft.com/en-us/windows/win32/secauthn/writing-and-installing-a-security-support-provider
|
|
base::win::RegKey key(HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Control\\Lsa", KEY_READ);
|
|
if (!key.Valid())
|
|
return ServiceStatus::kUnknown;
|
|
|
|
std::vector<std::wstring> packages;
|
|
if (key.ReadValues(L"Security Packages", &packages) != ERROR_SUCCESS)
|
|
return ServiceStatus::kUnknown;
|
|
|
|
for (const auto& package : packages) {
|
|
// Security Packages can be empty or just "". Anything else indicates
|
|
// there is potentially a third party SSP/APs DLL installed, and network
|
|
// sandbox should not be engaged.
|
|
if (package.empty())
|
|
continue;
|
|
if (package != L"\"\"")
|
|
return ServiceStatus::kFound;
|
|
}
|
|
return ServiceStatus::kNotFound;
|
|
}
|
|
#endif // defined(OS_WIN)
|
|
|
|
} // namespace
|
|
|
|
class NetworkServiceInstancePrivate {
|
|
public:
|
|
// Opens the specified file, blocking until the file is open. Used to open
|
|
// files specified by network::switches::kLogNetLog or
|
|
// network::switches::kSSLKeyLogFile. Since these arguments can be used to
|
|
// debug startup behavior, asynchronously opening the file on another thread
|
|
// would result in losing data, hence the need for blocking open operations.
|
|
// |file_flags| specifies the flags passed to the base::File constructor call.
|
|
//
|
|
// ThreadRestrictions needs to be able to friend the class/method to allow
|
|
// blocking, but can't friend CONTENT_EXPORT methods, so have it friend
|
|
// NetworkServiceInstancePrivate instead of GetNetworkService().
|
|
static base::File BlockingOpenFile(const base::FilePath& path,
|
|
int file_flags) {
|
|
base::ScopedAllowBlocking allow_blocking;
|
|
return base::File(path, file_flags);
|
|
}
|
|
};
|
|
|
|
network::mojom::NetworkService* GetNetworkService() {
|
|
if (!g_network_service_remote)
|
|
g_network_service_remote = new mojo::Remote<network::mojom::NetworkService>;
|
|
if (!g_network_service_remote->is_bound() ||
|
|
!g_network_service_remote->is_connected()) {
|
|
bool service_was_bound = g_network_service_remote->is_bound();
|
|
g_network_service_remote->reset();
|
|
if (GetContentClient()->browser()->IsShuttingDown()) {
|
|
// This happens at system shutdown, since in other scenarios the network
|
|
// process would only be torn down once the message loop stopped running.
|
|
// We don't want to start the network service again so just create message
|
|
// pipe that's not bound to stop consumers from requesting creation of the
|
|
// service.
|
|
auto receiver = g_network_service_remote->BindNewPipeAndPassReceiver();
|
|
auto leaked_pipe = receiver.PassPipe().release();
|
|
} else {
|
|
if (!g_force_create_network_service_directly) {
|
|
mojo::PendingReceiver<network::mojom::NetworkService> receiver =
|
|
g_network_service_remote->BindNewPipeAndPassReceiver();
|
|
g_network_service_remote->set_disconnect_handler(
|
|
base::BindOnce(&OnNetworkServiceCrash));
|
|
if (IsInProcessNetworkService()) {
|
|
CreateInProcessNetworkService(std::move(receiver));
|
|
} else {
|
|
if (service_was_bound)
|
|
LOG(ERROR) << "Network service crashed, restarting service.";
|
|
ServiceProcessHost::Launch(std::move(receiver),
|
|
ServiceProcessHost::Options()
|
|
.WithDisplayName(u"Network Service")
|
|
.Pass());
|
|
}
|
|
} else {
|
|
// This should only be reached in unit tests.
|
|
if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
|
|
CreateNetworkServiceOnIOForTesting(
|
|
g_network_service_remote->BindNewPipeAndPassReceiver(),
|
|
/*completion_event=*/nullptr);
|
|
} else {
|
|
base::WaitableEvent event;
|
|
GetIOThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(
|
|
CreateNetworkServiceOnIOForTesting,
|
|
g_network_service_remote->BindNewPipeAndPassReceiver(),
|
|
base::Unretained(&event)));
|
|
event.Wait();
|
|
}
|
|
}
|
|
|
|
delete g_client; // In case we're recreating the network service.
|
|
g_client = new NetworkServiceClient();
|
|
|
|
// Call SetClient before creating NetworkServiceClient, as the latter
|
|
// might make requests to NetworkService that depend on initialization.
|
|
(*g_network_service_remote)->SetParams(CreateNetworkServiceParams());
|
|
g_network_service_is_responding = false;
|
|
g_network_service_remote->QueryVersion(base::BindOnce(
|
|
[](base::Time start_time, uint32_t) {
|
|
g_network_service_is_responding = true;
|
|
base::TimeDelta delta = base::Time::Now() - start_time;
|
|
UMA_HISTOGRAM_MEDIUM_TIMES("NetworkService.TimeToFirstResponse",
|
|
delta);
|
|
if (g_last_network_service_crash.is_null()) {
|
|
UMA_HISTOGRAM_MEDIUM_TIMES(
|
|
"NetworkService.TimeToFirstResponse.OnStartup", delta);
|
|
} else {
|
|
UMA_HISTOGRAM_MEDIUM_TIMES(
|
|
"NetworkService.TimeToFirstResponse.AfterCrash", delta);
|
|
}
|
|
},
|
|
base::Time::Now()));
|
|
|
|
const base::CommandLine* command_line =
|
|
base::CommandLine::ForCurrentProcess();
|
|
if (command_line->HasSwitch(network::switches::kLogNetLog)) {
|
|
base::FilePath log_path =
|
|
command_line->GetSwitchValuePath(network::switches::kLogNetLog);
|
|
|
|
base::File file = NetworkServiceInstancePrivate::BlockingOpenFile(
|
|
log_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
|
|
if (!file.IsValid()) {
|
|
LOG(ERROR) << "Failed opening NetLog: " << log_path.value();
|
|
} else {
|
|
(*g_network_service_remote)
|
|
->StartNetLog(
|
|
std::move(file),
|
|
GetNetCaptureModeFromCommandLine(*command_line),
|
|
GetContentClient()->browser()->GetNetLogConstants());
|
|
}
|
|
}
|
|
|
|
base::FilePath ssl_key_log_path;
|
|
if (command_line->HasSwitch(network::switches::kSSLKeyLogFile)) {
|
|
UMA_HISTOGRAM_ENUMERATION(kSSLKeyLogFileHistogram,
|
|
SSLKeyLogFileAction::kSwitchFound);
|
|
ssl_key_log_path =
|
|
command_line->GetSwitchValuePath(network::switches::kSSLKeyLogFile);
|
|
LOG_IF(WARNING, ssl_key_log_path.empty())
|
|
<< "ssl-key-log-file argument missing";
|
|
} else {
|
|
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
|
std::string env_str;
|
|
if (env->GetVar("SSLKEYLOGFILE", &env_str)) {
|
|
UMA_HISTOGRAM_ENUMERATION(kSSLKeyLogFileHistogram,
|
|
SSLKeyLogFileAction::kEnvVarFound);
|
|
#if defined(OS_WIN)
|
|
// base::Environment returns environment variables in UTF-8 on
|
|
// Windows.
|
|
ssl_key_log_path = base::FilePath(base::UTF8ToWide(env_str));
|
|
#else
|
|
ssl_key_log_path = base::FilePath(env_str);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (!ssl_key_log_path.empty()) {
|
|
base::File file = NetworkServiceInstancePrivate::BlockingOpenFile(
|
|
ssl_key_log_path,
|
|
base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
|
|
if (!file.IsValid()) {
|
|
LOG(ERROR) << "Failed opening SSL key log file: "
|
|
<< ssl_key_log_path.value();
|
|
} else {
|
|
UMA_HISTOGRAM_ENUMERATION(kSSLKeyLogFileHistogram,
|
|
SSLKeyLogFileAction::kLogFileEnabled);
|
|
(*g_network_service_remote)->SetSSLKeyLogFile(std::move(file));
|
|
}
|
|
}
|
|
|
|
GetContentClient()->browser()->OnNetworkServiceCreated(
|
|
g_network_service_remote->get());
|
|
}
|
|
}
|
|
return g_network_service_remote->get();
|
|
}
|
|
|
|
base::CallbackListSubscription RegisterNetworkServiceCrashHandler(
|
|
base::RepeatingClosure handler) {
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
DCHECK(!handler.is_null());
|
|
|
|
return GetCrashHandlersList().Add(std::move(handler));
|
|
}
|
|
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
net::NetworkChangeNotifier* GetNetworkChangeNotifier() {
|
|
return BrowserMainLoop::GetInstance()->network_change_notifier();
|
|
}
|
|
#endif
|
|
|
|
void FlushNetworkServiceInstanceForTesting() {
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
|
if (g_network_service_remote)
|
|
g_network_service_remote->FlushForTesting();
|
|
}
|
|
|
|
network::NetworkConnectionTracker* GetNetworkConnectionTracker() {
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
|
|
!BrowserThread::IsThreadInitialized(BrowserThread::UI));
|
|
if (!g_network_connection_tracker) {
|
|
g_network_connection_tracker = new network::NetworkConnectionTracker(
|
|
base::BindRepeating(&BindNetworkChangeManagerReceiver));
|
|
}
|
|
return g_network_connection_tracker;
|
|
}
|
|
|
|
void GetNetworkConnectionTrackerFromUIThread(
|
|
base::OnceCallback<void(network::NetworkConnectionTracker*)> callback) {
|
|
GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
|
|
->PostTaskAndReplyWithResult(FROM_HERE,
|
|
base::BindOnce(&GetNetworkConnectionTracker),
|
|
std::move(callback));
|
|
}
|
|
|
|
network::NetworkConnectionTrackerAsyncGetter
|
|
CreateNetworkConnectionTrackerAsyncGetter() {
|
|
return base::BindRepeating(&content::GetNetworkConnectionTrackerFromUIThread);
|
|
}
|
|
|
|
void SetNetworkConnectionTrackerForTesting(
|
|
network::NetworkConnectionTracker* network_connection_tracker) {
|
|
if (g_network_connection_tracker != network_connection_tracker) {
|
|
DCHECK(!g_network_connection_tracker || !network_connection_tracker);
|
|
g_network_connection_tracker = network_connection_tracker;
|
|
}
|
|
}
|
|
|
|
const scoped_refptr<base::SequencedTaskRunner>& GetNetworkTaskRunner() {
|
|
DCHECK(IsInProcessNetworkService());
|
|
return GetNetworkTaskRunnerStorage();
|
|
}
|
|
|
|
void ForceCreateNetworkServiceDirectlyForTesting() {
|
|
g_force_create_network_service_directly = true;
|
|
}
|
|
|
|
void ResetNetworkServiceForTesting() {
|
|
ShutDownNetworkService();
|
|
}
|
|
|
|
void ShutDownNetworkService() {
|
|
delete g_network_service_remote;
|
|
g_network_service_remote = nullptr;
|
|
delete g_client;
|
|
g_client = nullptr;
|
|
if (g_in_process_instance) {
|
|
GetNetworkTaskRunner()->DeleteSoon(FROM_HERE, g_in_process_instance);
|
|
g_in_process_instance = nullptr;
|
|
}
|
|
GetNetworkTaskRunnerStorage().reset();
|
|
}
|
|
|
|
NetworkServiceAvailability GetNetworkServiceAvailability() {
|
|
if (!g_network_service_remote)
|
|
return NetworkServiceAvailability::NOT_CREATED;
|
|
else if (!g_network_service_remote->is_bound())
|
|
return NetworkServiceAvailability::NOT_BOUND;
|
|
else if (!g_network_service_remote->is_connected())
|
|
return NetworkServiceAvailability::ENCOUNTERED_ERROR;
|
|
else if (!g_network_service_is_responding)
|
|
return NetworkServiceAvailability::NOT_RESPONDING;
|
|
else
|
|
return NetworkServiceAvailability::AVAILABLE;
|
|
}
|
|
|
|
base::TimeDelta GetTimeSinceLastNetworkServiceCrash() {
|
|
if (g_last_network_service_crash.is_null())
|
|
return base::TimeDelta();
|
|
return base::Time::Now() - g_last_network_service_crash;
|
|
}
|
|
|
|
void PingNetworkService(base::OnceClosure closure) {
|
|
GetNetworkService();
|
|
// Unfortunately, QueryVersion requires a RepeatingCallback.
|
|
g_network_service_remote->QueryVersion(base::BindOnce(
|
|
[](base::OnceClosure closure, uint32_t) {
|
|
if (closure)
|
|
std::move(closure).Run();
|
|
},
|
|
std::move(closure)));
|
|
}
|
|
|
|
namespace {
|
|
|
|
cert_verifier::mojom::CertVerifierServiceFactory*
|
|
g_cert_verifier_service_factory_for_testing = nullptr;
|
|
|
|
mojo::PendingRemote<cert_verifier::mojom::CertVerifierService>
|
|
GetNewCertVerifierServiceRemote(
|
|
cert_verifier::mojom::CertVerifierServiceFactory*
|
|
cert_verifier_service_factory,
|
|
cert_verifier::mojom::CertVerifierCreationParamsPtr creation_params) {
|
|
mojo::PendingRemote<cert_verifier::mojom::CertVerifierService>
|
|
cert_verifier_remote;
|
|
cert_verifier_service_factory->GetNewCertVerifier(
|
|
cert_verifier_remote.InitWithNewPipeAndPassReceiver(),
|
|
std::move(creation_params));
|
|
return cert_verifier_remote;
|
|
}
|
|
|
|
void RunInProcessCertVerifierServiceFactory(
|
|
mojo::PendingReceiver<cert_verifier::mojom::CertVerifierServiceFactory>
|
|
receiver) {
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
|
|
BrowserThread::CurrentlyOn(BrowserThread::IO));
|
|
#else
|
|
DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
|
|
BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
#endif
|
|
static base::NoDestructor<base::SequenceLocalStorageSlot<
|
|
std::unique_ptr<cert_verifier::CertVerifierServiceFactoryImpl>>>
|
|
service_factory_slot;
|
|
service_factory_slot->GetOrCreateValue() =
|
|
std::make_unique<cert_verifier::CertVerifierServiceFactoryImpl>(
|
|
std::move(receiver));
|
|
}
|
|
|
|
// Owns the CertVerifierServiceFactory used by the browser.
|
|
// Lives on the UI thread.
|
|
mojo::Remote<cert_verifier::mojom::CertVerifierServiceFactory>&
|
|
GetCertVerifierServiceFactoryRemoteStorage() {
|
|
static base::NoDestructor<base::SequenceLocalStorageSlot<
|
|
mojo::Remote<cert_verifier::mojom::CertVerifierServiceFactory>>>
|
|
cert_verifier_service_factory_remote;
|
|
return cert_verifier_service_factory_remote->GetOrCreateValue();
|
|
}
|
|
|
|
// Returns a pointer to a CertVerifierServiceFactory usable on the UI thread.
|
|
cert_verifier::mojom::CertVerifierServiceFactory*
|
|
GetCertVerifierServiceFactory() {
|
|
if (g_cert_verifier_service_factory_for_testing)
|
|
return g_cert_verifier_service_factory_for_testing;
|
|
|
|
mojo::Remote<cert_verifier::mojom::CertVerifierServiceFactory>&
|
|
factory_remote_storage = GetCertVerifierServiceFactoryRemoteStorage();
|
|
if (!factory_remote_storage.is_bound() ||
|
|
!factory_remote_storage.is_connected()) {
|
|
factory_remote_storage.reset();
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
// ChromeOS's in-process CertVerifierService should run on the IO thread
|
|
// because it interacts with IO-bound NSS and ChromeOS user slots.
|
|
// See for example InitializeNSSForChromeOSUser().
|
|
GetIOThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&RunInProcessCertVerifierServiceFactory,
|
|
factory_remote_storage.BindNewPipeAndPassReceiver()));
|
|
#else
|
|
RunInProcessCertVerifierServiceFactory(
|
|
factory_remote_storage.BindNewPipeAndPassReceiver());
|
|
#endif
|
|
}
|
|
return factory_remote_storage.get();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
network::mojom::CertVerifierServiceRemoteParamsPtr GetCertVerifierParams(
|
|
cert_verifier::mojom::CertVerifierCreationParamsPtr
|
|
cert_verifier_creation_params) {
|
|
return network::mojom::CertVerifierServiceRemoteParams::New(
|
|
GetNewCertVerifierServiceRemote(
|
|
GetCertVerifierServiceFactory(),
|
|
std::move(cert_verifier_creation_params)));
|
|
}
|
|
|
|
void SetCertVerifierServiceFactoryForTesting(
|
|
cert_verifier::mojom::CertVerifierServiceFactory* service_factory) {
|
|
g_cert_verifier_service_factory_for_testing = service_factory;
|
|
}
|
|
|
|
bool IsNetworkSandboxEnabled() {
|
|
#if defined(OS_MAC) || defined(OS_FUCHSIA)
|
|
return true;
|
|
#else
|
|
#if defined(OS_WIN)
|
|
if (base::win::GetVersion() < base::win::Version::WIN10)
|
|
return false;
|
|
auto ssp_status = DetectSecurityProviders();
|
|
base::UmaHistogramEnumeration("Windows.ServiceStatus.SSP", ssp_status);
|
|
switch (ssp_status) {
|
|
case ServiceStatus::kUnknown:
|
|
return false;
|
|
case ServiceStatus::kNotFound:
|
|
break;
|
|
case ServiceStatus::kFound:
|
|
return false;
|
|
}
|
|
#endif // defined(OS_WIN)
|
|
return base::FeatureList::IsEnabled(
|
|
sandbox::policy::features::kNetworkServiceSandbox);
|
|
#endif // defined(OS_MAC) || defined(OS_FUCHSIA)
|
|
}
|
|
|
|
} // namespace content
|