#include "chrome/enterprise_companion/url_loader_factory_provider.h"
#include <memory>
#include <utility>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/sequence_checker.h"
#include "base/strings/stringprintf.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/sequence_bound.h"
#include "build/build_config.h"
#include "chrome/enterprise_companion/enterprise_companion.h"
#include "chrome/enterprise_companion/event_logger.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "net/cert/cert_verifier.h"
#include "net/cert_net/cert_net_fetcher_url_request.h"
#include "net/proxy_resolution/proxy_config_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/transitional_url_loader_factory_owner.h"
#if BUILDFLAG(IS_MAC)
#include <sys/types.h>
#include "chrome/enterprise_companion/mac/mac_utils.h"
#endif
namespace enterprise_companion {
namespace {
class URLRequestContextGetter : public net::URLRequestContextGetter { … };
class URLLoaderFactoryProxy final : public network::mojom::URLLoaderFactory { … };
class InProcessURLLoaderFactoryProvider : public URLLoaderFactoryProvider { … };
#if BUILDFLAG(IS_MAC)
class URLLoaderFactoryProviderProxy : public URLLoaderFactoryProvider {
public:
explicit URLLoaderFactoryProviderProxy(
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote,
base::OnceClosure on_disconnect_callback) {
mojo::Remote remote(std::move(pending_remote));
remote.set_disconnect_handler(std::move(on_disconnect_callback));
url_loader_factory_ =
base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
std::move(remote));
}
~URLLoaderFactoryProviderProxy() override = default;
std::unique_ptr<network::PendingSharedURLLoaderFactory>
GetPendingURLLoaderFactory() override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return url_loader_factory_->Clone();
}
private:
SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
};
#endif
}
base::SequenceBound<URLLoaderFactoryProvider>
CreateInProcessUrlLoaderFactoryProvider(
scoped_refptr<base::SingleThreadTaskRunner> net_thread_runner,
base::SequenceBound<EventLoggerCookieHandler> event_logger_cookie_handler,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver,
base::OnceClosure on_disconnect_callback) { … }
#if BUILDFLAG(IS_MAC)
base::SequenceBound<URLLoaderFactoryProvider>
CreateUrlLoaderFactoryProviderProxy(
scoped_refptr<base::SequencedTaskRunner> task_runner,
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote,
base::OnceClosure on_disconnect_callback) {
return base::SequenceBound<URLLoaderFactoryProviderProxy>(
task_runner, std::move(pending_remote),
std::move(on_disconnect_callback));
}
base::SequenceBound<URLLoaderFactoryProvider> CreateOutOfProcessNetWorker(
base::OnceClosure on_disconnect_callback) {
mojo::PlatformChannel channel;
base::LaunchOptions options;
base::FilePath exe_path;
if (!base::PathService::Get(base::FILE_EXE, &exe_path)) {
LOG(ERROR) << "Failed to retrieve the current executable's path.";
return {};
}
base::CommandLine command_line(exe_path);
command_line.AppendSwitch(kNetWorkerSwitch);
std::optional<uid_t> uid = GuessLoggedInUser();
if (!uid) {
LOG(ERROR)
<< "Could not determine a logged-in user to impersonate for "
"networking. The root bootstrap namespace (in formal Mach kernel "
"terms, the \"startup context\") will be used, which may cause "
"proxy configuration or authorization to fail.";
} else {
command_line.PrependWrapper(
base::StringPrintf("/bin/launchctl asuser %d", *uid));
}
channel.PrepareToPassRemoteEndpoint(&options, &command_line);
base::Process process = base::LaunchProcess(command_line, options);
channel.RemoteProcessLaunchAttempted();
if (!process.IsValid()) {
LOG(ERROR) << "Failed to launch network process.";
return {};
}
mojo::ScopedMessagePipeHandle pipe = mojo::OutgoingInvitation::SendIsolated(
channel.TakeLocalEndpoint(), {}, process.Handle());
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote(
std::move(pipe), network::mojom::URLLoaderFactory::Version_);
if (!pending_remote) {
LOG(ERROR) << "Failed to establish IPC with the network process.";
return {};
}
return CreateUrlLoaderFactoryProviderProxy(
base::SequencedTaskRunner::GetCurrentDefault(), std::move(pending_remote),
std::move(on_disconnect_callback));
}
#endif
}