Commit 859c9c73 authored by Matt Mueller's avatar Matt Mueller Committed by Commit Bot

net: proxy netlog messages from browser process to network service process over mojo

Bug: 1040681
Change-Id: Iefab63f598fecc3519065b0440815e2d65bb5070
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2036273Reviewed-by: default avatarMustafa Emre Acer <meacer@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Commit-Queue: Matt Mueller <mattm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741179}
parent 8839b5ea
......@@ -127,11 +127,13 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/network_service_util.h"
#include "content/public/common/service_manager_connection.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/constants.h"
#include "media/media_buildflags.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "net/log/net_log.h"
#include "ppapi/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "services/network/public/cpp/features.h"
......@@ -236,6 +238,13 @@ BrowserProcessImpl::BrowserProcessImpl(StartupData* startup_data) {
}
void BrowserProcessImpl::Init() {
if (content::IsOutOfProcessNetworkService()) {
// Initialize NetLog source IDs to use an alternate starting value for
// the browser process. This needs to be done early in process startup
// before any NetLogSource objects might get created.
net::NetLog::Get()->InitializeSourceIdPartition();
}
#if defined(OS_CHROMEOS)
// Forces creation of |metrics_services_manager_client_| if necessary
// (typically this call is a no-op as MetricsServicesManager has already been
......
......@@ -36,6 +36,7 @@
#include "components/certificate_transparency/ct_known_logs.h"
#include "components/flags_ui/pref_service_flags_storage.h"
#include "components/net_log/net_export_file_writer.h"
#include "components/net_log/net_log_proxy_source.h"
#include "components/network_session_configurator/common/network_features.h"
#include "components/os_crypt/os_crypt.h"
#include "components/policy/core/common/policy_namespace.h"
......@@ -53,6 +54,7 @@
#include "content/public/browser/network_service_instance.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/network_service_util.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/common/user_agent.h"
#include "crypto/sha2.h"
......@@ -85,10 +87,6 @@
#include "ui/base/l10n/l10n_util.h"
#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
#if defined(OS_WIN) || defined(OS_MACOSX)
#include "content/public/common/network_service_util.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/common/constants.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
......@@ -578,6 +576,21 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(
if (!is_quic_allowed_)
network_service->DisableQuic();
if (content::IsOutOfProcessNetworkService()) {
mojo::PendingRemote<network::mojom::NetLogProxySource> proxy_source_remote;
mojo::PendingReceiver<network::mojom::NetLogProxySource>
proxy_source_receiver =
proxy_source_remote.InitWithNewPipeAndPassReceiver();
mojo::Remote<network::mojom::NetLogProxySink> proxy_sink_remote;
network_service->AttachNetLogProxy(
std::move(proxy_source_remote),
proxy_sink_remote.BindNewPipeAndPassReceiver());
if (net_log_proxy_source_)
net_log_proxy_source_->ShutDown();
net_log_proxy_source_ = std::make_unique<net_log::NetLogProxySource>(
std::move(proxy_source_receiver), std::move(proxy_sink_remote));
}
network_service->SetUpHttpAuth(CreateHttpAuthStaticParams(local_state_));
network_service->ConfigureHttpAuthPrefs(
CreateHttpAuthDynamicParams(local_state_));
......
......@@ -36,6 +36,7 @@ class SharedURLLoaderFactory;
namespace net_log {
class NetExportFileWriter;
class NetLogProxySource;
}
// Responsible for creating and managing access to the system NetworkContext.
......@@ -186,6 +187,11 @@ class SystemNetworkContextManager {
BooleanPrefMember enable_referrers_;
// Copies NetLog events from the browser process to the Network Service, if
// the network service is running in a separate process. It will be destroyed
// and re-created on Network Service crash.
std::unique_ptr<net_log::NetLogProxySource> net_log_proxy_source_;
// Initialized on first access.
std::unique_ptr<net_log::NetExportFileWriter> net_export_file_writer_;
......
......@@ -10,6 +10,8 @@ static_library("net_log") {
"net_export_file_writer.h",
"net_export_ui_constants.cc",
"net_export_ui_constants.h",
"net_log_proxy_source.cc",
"net_log_proxy_source.h",
]
deps = [
......@@ -22,7 +24,10 @@ static_library("net_log") {
source_set("unit_tests") {
testonly = true
sources = [ "net_export_file_writer_unittest.cc" ]
sources = [
"net_export_file_writer_unittest.cc",
"net_log_proxy_source_unittest.cc",
]
deps = [
":net_log",
"//base",
......
// Copyright 2020 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 "components/net_log/net_log_proxy_source.h"
namespace net_log {
NetLogProxySource::NetLogProxySource(
mojo::PendingReceiver<network::mojom::NetLogProxySource>
proxy_source_receiver,
mojo::Remote<network::mojom::NetLogProxySink> proxy_sink_remote)
: proxy_source_receiver_(this, std::move(proxy_source_receiver)),
proxy_sink_remote_(std::move(proxy_sink_remote)),
task_runner_(base::SequencedTaskRunnerHandle::Get()) {
// Initialize a WeakPtr instance that can be safely referred to from other
// threads when binding tasks posted back to this thread.
weak_this_ = weak_factory_.GetWeakPtr();
}
NetLogProxySource::~NetLogProxySource() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// Just in case ShutDown() was not called, make sure observer is removed.
UpdateCaptureModes(0);
}
void NetLogProxySource::ShutDown() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
UpdateCaptureModes(0);
weak_factory_.InvalidateWeakPtrs();
proxy_source_receiver_.reset();
proxy_sink_remote_.reset();
}
void NetLogProxySource::OnAddEntry(const net::NetLogEntry& entry) {
if (task_runner_->RunsTasksInCurrentSequence()) {
SendNetLogEntry(entry.type, entry.source.type, entry.source.id,
entry.source.start_time, entry.phase, entry.time,
entry.params.Clone());
} else {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&NetLogProxySource::SendNetLogEntry, weak_this_,
entry.type, entry.source.type, entry.source.id,
entry.source.start_time, entry.phase, entry.time,
entry.params.Clone()));
}
}
void NetLogProxySource::UpdateCaptureModes(
net::NetLogCaptureModeSet new_modes) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// Not capturing, remove observer if necessary.
if (new_modes == 0) {
if (net_log())
net::NetLog::Get()->RemoveObserver(this);
return;
}
// NetLog allows multiple observers to be registered at once, and each might
// have a different capture mode. In the common case there would normally be
// at most one observer registered. To avoid the complication of sending
// different sets of params for each capture mode, if multiple capture modes
// are active, only one observer is registered in the source process, using
// the lowest common denominator capture mode. This handles the common case,
// and in the rare case where multiple capture modes active, is a safe
// fallback.
//
// Register observer for the lowest level that is set in |new_modes|.
for (int i = 0; i <= static_cast<int>(net::NetLogCaptureMode::kLast); ++i) {
net::NetLogCaptureMode mode = static_cast<net::NetLogCaptureMode>(i);
if (net::NetLogCaptureModeSetContains(mode, new_modes)) {
if (net_log() && capture_mode() == mode) {
// Already listening at the desired level.
return;
}
if (net_log()) {
// Listening at the wrong level, remove observer.
net::NetLog::Get()->RemoveObserver(this);
}
net::NetLog::Get()->AddObserver(this, mode);
return;
}
}
NOTREACHED();
}
void NetLogProxySource::SendNetLogEntry(net::NetLogEventType type,
net::NetLogSourceType source_type,
uint32_t source_id,
base::TimeTicks source_start_time,
net::NetLogEventPhase phase,
base::TimeTicks time,
base::Value params) {
proxy_sink_remote_->AddEntry(
static_cast<uint32_t>(type), static_cast<uint32_t>(source_type),
source_id, source_start_time, phase, time, std::move(params));
}
} // namespace net_log
// Copyright 2020 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.
#ifndef COMPONENTS_NET_LOG_NET_LOG_PROXY_SOURCE_H_
#define COMPONENTS_NET_LOG_NET_LOG_PROXY_SOURCE_H_
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/log/net_log.h"
#include "services/network/public/mojom/network_service.mojom.h"
namespace base {
class SequencedTaskRunner;
}
namespace net_log {
// Implementation of NetLogProxySource mojo interface which observes local
// NetLog events and proxies them over mojo to a remote NetLogProxySink.
// Observing and proxying is only active when notified through
// UpdateCaptureModes() that capturing is active in the remote process.
class NetLogProxySource : public net::NetLog::ThreadSafeObserver,
public network::mojom::NetLogProxySource {
public:
// When notified through |proxy_source_receiver| that capturing is active,
// registers a local NetLog observer and sends all NetLog events to
// |proxy_sink_remote|.
// The caller is expected to create a new NetLogProxySource if the remote
// process is restarted.
NetLogProxySource(
mojo::PendingReceiver<network::mojom::NetLogProxySource>
proxy_source_receiver,
mojo::Remote<network::mojom::NetLogProxySink> proxy_sink_remote);
~NetLogProxySource() override;
NetLogProxySource(const NetLogProxySource&) = delete;
NetLogProxySource& operator=(const NetLogProxySource&) = delete;
// Remove NetLog observer and close mojo pipes.
void ShutDown();
// NetLog::ThreadSafeObserver:
void OnAddEntry(const net::NetLogEntry& entry) override;
// mojom::NetLogProxySource:
void UpdateCaptureModes(net::NetLogCaptureModeSet modes) override;
private:
// Proxy entry to the remote. Must only be called on |task_runner_|.
void SendNetLogEntry(net::NetLogEventType type,
net::NetLogSourceType source_type,
uint32_t source_id,
base::TimeTicks source_start_time,
net::NetLogEventPhase phase,
base::TimeTicks time,
base::Value params);
mojo::Receiver<network::mojom::NetLogProxySource> proxy_source_receiver_;
mojo::Remote<network::mojom::NetLogProxySink> proxy_sink_remote_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// A WeakPtr to |this|, which is used when posting tasks from the
// NetLog::ThreadSafeObserver to |task_runner_|. This single WeakPtr instance
// is used for all tasks as the ThreadSafeObserver may call on any thread, so
// the weak_factory_ cannot be accessed safely from those threads.
base::WeakPtr<NetLogProxySource> weak_this_;
base::WeakPtrFactory<NetLogProxySource> weak_factory_{this};
};
} // namespace net_log
#endif // COMPONENTS_NET_LOG_NET_LOG_PROXY_SOURCE_H_
This diff is collapsed.
......@@ -30,6 +30,28 @@ NetLog* NetLog::ThreadSafeObserver::net_log() const {
return net_log_;
}
NetLog::ThreadSafeCaptureModeObserver::ThreadSafeCaptureModeObserver() =
default;
NetLog::ThreadSafeCaptureModeObserver::~ThreadSafeCaptureModeObserver() =
default;
NetLogCaptureModeSet
NetLog::ThreadSafeCaptureModeObserver::GetObserverCaptureModes() const {
DCHECK(net_log_);
return net_log_->GetObserverCaptureModes();
}
void NetLog::ThreadSafeCaptureModeObserver::
AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
base::TimeTicks time,
base::Value&& params) {
DCHECK(net_log_);
net_log_->AddEntryAtTimeWithMaterializedParams(type, source, phase, time,
std::move(params));
}
// static
NetLog* NetLog::Get() {
static base::NoDestructor<NetLog> instance{util::PassKey<NetLog>()};
......@@ -92,6 +114,33 @@ void NetLog::RemoveObserver(NetLog::ThreadSafeObserver* observer) {
UpdateObserverCaptureModes();
}
void NetLog::AddCaptureModeObserver(
NetLog::ThreadSafeCaptureModeObserver* observer) {
base::AutoLock lock(lock_);
DCHECK(!observer->net_log_);
DCHECK(!HasCaptureModeObserver(observer));
DCHECK_LT(capture_mode_observers_.size(), 20u); // Performance sanity check.
observer->net_log_ = this;
capture_mode_observers_.push_back(observer);
}
void NetLog::RemoveCaptureModeObserver(
NetLog::ThreadSafeCaptureModeObserver* observer) {
base::AutoLock lock(lock_);
DCHECK_EQ(this, observer->net_log_);
DCHECK(HasCaptureModeObserver(observer));
auto it = std::find(capture_mode_observers_.begin(),
capture_mode_observers_.end(), observer);
DCHECK(it != capture_mode_observers_.end());
capture_mode_observers_.erase(it);
observer->net_log_ = nullptr;
}
void NetLog::UpdateObserverCaptureModes() {
lock_.AssertAcquired();
......@@ -100,6 +149,10 @@ void NetLog::UpdateObserverCaptureModes() {
NetLogCaptureModeSetAdd(observer->capture_mode_, &capture_mode_set);
base::subtle::NoBarrier_Store(&observer_capture_modes_, capture_mode_set);
// Notify any capture mode observers with the new |capture_mode_set|.
for (auto* capture_mode_observer : capture_mode_observers_)
capture_mode_observer->OnCaptureModeUpdated(capture_mode_set);
}
bool NetLog::HasObserver(ThreadSafeObserver* observer) {
......@@ -107,6 +160,11 @@ bool NetLog::HasObserver(ThreadSafeObserver* observer) {
return base::Contains(observers_, observer);
}
bool NetLog::HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer) {
lock_.AssertAcquired();
return base::Contains(capture_mode_observers_, observer);
}
// static
std::string NetLog::TickCountToString(const base::TimeTicks& time) {
int64_t delta_time = time.since_origin().InMilliseconds();
......@@ -182,6 +240,13 @@ const char* NetLog::EventPhaseToString(NetLogEventPhase phase) {
return nullptr;
}
void NetLog::InitializeSourceIdPartition() {
int32_t old_value = base::subtle::NoBarrier_AtomicExchange(
&last_id_, std::numeric_limits<base::subtle::Atomic32>::min());
DCHECK_EQ(old_value, 0) << " NetLog::InitializeSourceIdPartition() called "
"after NextID() or called multiple times";
}
void NetLog::AddEntryInternal(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
......@@ -209,10 +274,18 @@ void NetLog::AddEntryWithMaterializedParams(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
base::Value&& params) {
NetLogEntry entry(type, source, phase, base::TimeTicks::Now(),
std::move(params));
AddEntryAtTimeWithMaterializedParams(
type, source, phase, base::TimeTicks::Now(), std::move(params));
}
void NetLog::AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
base::TimeTicks time,
base::Value&& params) {
NetLogEntry entry(type, source, phase, time, std::move(params));
// Notify all of the log observers with |capture_mode|.
// Notify all of the log observers, regardless of capture mode.
base::AutoLock lock(lock_);
for (auto* observer : observers_) {
observer->OnAddEntry(entry);
......
......@@ -140,6 +140,39 @@ class NET_EXPORT NetLog {
DISALLOW_COPY_AND_ASSIGN(ThreadSafeObserver);
};
// An observer that is notified of changes in the capture mode set, and has
// the ability to add NetLog entries with materialized params.
class NET_EXPORT ThreadSafeCaptureModeObserver {
public:
ThreadSafeCaptureModeObserver();
virtual void OnCaptureModeUpdated(NetLogCaptureModeSet modes) = 0;
protected:
virtual ~ThreadSafeCaptureModeObserver();
NetLogCaptureModeSet GetObserverCaptureModes() const;
// Add event to the observed NetLog. Must only be called while observing is
// active, and the caller is responsible for ensuring the materialized
// params are suitable for the current capture mode.
void AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
base::TimeTicks time,
base::Value&& params);
private:
// Friend NetLog so that AddCaptureModeObserver/RemoveCaptureModeObserver
// can update the |net_log_| member.
friend class NetLog;
// This value is only modified by the NetLog.
NetLog* net_log_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ThreadSafeCaptureModeObserver);
};
// Returns the singleton NetLog object, which is never destructed and which
// may be used on any thread.
static NetLog* Get();
......@@ -161,6 +194,15 @@ class NET_EXPORT NetLog {
// tests instantiating TestNetLogs.
virtual ~NetLog();
// Configure the source IDs returned by NextID() to use a different starting
// position, so that NetLog events generated by this process will not conflict
// with those generated by another NetLog in a different process. This
// should only be called once, before any NetLogSource could be created in
// the current process.
//
// Currently only a single additional source id partition is supported.
void InitializeSourceIdPartition();
void AddEntry(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase);
......@@ -243,7 +285,7 @@ class NET_EXPORT NetLog {
base::StringPiece value);
// Returns a unique ID which can be used as a source ID. All returned IDs
// will be unique and greater than 0.
// will be unique and not equal to 0.
uint32_t NextID();
// Returns true if there are any observers attached to the NetLog.
......@@ -275,6 +317,12 @@ class NET_EXPORT NetLog {
// an object's destructor.
void RemoveObserver(ThreadSafeObserver* observer);
// Adds an observer that is notified of changes in the capture mode set.
void AddCaptureModeObserver(ThreadSafeCaptureModeObserver* observer);
// Removes a capture mode observer.
void RemoveCaptureModeObserver(ThreadSafeCaptureModeObserver* observer);
// Converts a time to the string format that the NetLog uses to represent
// times. Strings are used since integers may overflow.
// The resulting string contains the number of milliseconds since the origin
......@@ -334,6 +382,15 @@ class NET_EXPORT NetLog {
NetLogEventPhase phase,
base::Value&& params);
// Adds an entry at a certain time, using already materialized parameters,
// when it is already known that the log is capturing (goes straight to
// acquiring observer lock).
void AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
base::TimeTicks time,
base::Value&& params);
// Called whenever an observer is added or removed, to update
// |observer_capture_modes_|. Must have acquired |lock_| prior to calling.
void UpdateObserverCaptureModes();
......@@ -341,6 +398,7 @@ class NET_EXPORT NetLog {
// Returns true if |observer| is watching this NetLog. Must
// be called while |lock_| is already held.
bool HasObserver(ThreadSafeObserver* observer);
bool HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer);
// |lock_| protects access to |observers_|.
base::Lock lock_;
......@@ -364,6 +422,8 @@ class NET_EXPORT NetLog {
// operations on it are fine.
std::vector<ThreadSafeObserver*> observers_;
std::vector<ThreadSafeCaptureModeObserver*> capture_mode_observers_;
DISALLOW_COPY_AND_ASSIGN(NetLog);
};
......
......@@ -62,6 +62,8 @@ jumbo_component("network_service") {
"mojo_host_resolver_impl.h",
"net_log_exporter.cc",
"net_log_exporter.h",
"net_log_proxy_sink.cc",
"net_log_proxy_sink.h",
"network_change_manager.cc",
"network_change_manager.h",
"network_context.cc",
......@@ -305,6 +307,7 @@ source_set("tests") {
"ignore_errors_cert_verifier_unittest.cc",
"keepalive_statistics_recorder_unittest.cc",
"mojo_host_resolver_impl_unittest.cc",
"net_log_proxy_sink_unittest.cc",
"network_change_manager_unittest.cc",
"network_context_unittest.cc",
"network_qualities_pref_delegate_unittest.cc",
......
// Copyright 2020 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 "services/network/net_log_proxy_sink.h"
namespace network {
NetLogProxySink::NetLogProxySink()
: task_runner_(base::SequencedTaskRunnerHandle::Get()) {
// Initialize a WeakPtr instance that can be safely referred to from other
// threads when binding tasks posted back to this thread.
weak_this_ = weak_factory_.GetWeakPtr();
net::NetLog::Get()->AddCaptureModeObserver(this);
}
NetLogProxySink::~NetLogProxySink() {
net::NetLog::Get()->RemoveCaptureModeObserver(this);
}
void NetLogProxySink::AttachSource(
mojo::PendingRemote<network::mojom::NetLogProxySource> proxy_source_remote,
mojo::PendingReceiver<network::mojom::NetLogProxySink>
proxy_sink_receiver) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// Initialize remote with current capturing state. (Netlog capturing might
// already be active when NetLogProxySource gets attached.)
mojo::Remote<network::mojom::NetLogProxySource> bound_remote(
std::move(proxy_source_remote));
bound_remote->UpdateCaptureModes(GetObserverCaptureModes());
proxy_source_remotes_.Add(std::move(bound_remote));
proxy_sink_receivers_.Add(this, std::move(proxy_sink_receiver));
}
void NetLogProxySink::OnCaptureModeUpdated(net::NetLogCaptureModeSet modes) {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&NetLogProxySink::OnCaptureModeUpdated,
weak_this_, modes));
return;
}
for (const auto& source : proxy_source_remotes_) {
source->UpdateCaptureModes(modes);
}
}
void NetLogProxySink::AddEntry(uint32_t type,
uint32_t source_type,
uint32_t source_id,
base::TimeTicks source_start_time,
net::NetLogEventPhase phase,
base::TimeTicks time,
base::Value params) {
// Note: There is a possible race condition, where the NetLog capture mode
// changes, but the other process is still sending events for the old capture
// mode, and thus might log events with a higher than expected capture mode.
// (But if capturing is completely disabled and the other side still has some
// events in the pipe, AddEntryWithMaterializedParams will do nothing, since
// that implies no observers are registered.)
// TODO(mattm): Remote side could send the capture mode along with the event,
// and then check here before logging that the current capture mode still is
// compatible.
AddEntryAtTimeWithMaterializedParams(
static_cast<net::NetLogEventType>(type),
net::NetLogSource(static_cast<net::NetLogSourceType>(source_type),
source_id, source_start_time),
phase, time, std::move(params));
}
} // namespace network
// Copyright 2020 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.
#ifndef SERVICES_NETWORK_NET_LOG_PROXY_SINK_H_
#define SERVICES_NETWORK_NET_LOG_PROXY_SINK_H_
#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "net/log/net_log.h"
#include "services/network/public/mojom/network_service.mojom.h"
namespace base {
class SequencedTaskRunner;
}
namespace network {
// Implementation of NetLogProxySink mojo interface which receives external
// NetLog events and injects them into the NetLog. Also notifies attached
// sources when the NetLog capture mode changes.
class COMPONENT_EXPORT(NETWORK_SERVICE) NetLogProxySink
: public net::NetLog::ThreadSafeCaptureModeObserver,
public network::mojom::NetLogProxySink {
public:
NetLogProxySink();
~NetLogProxySink() override;
NetLogProxySink(const NetLogProxySink&) = delete;
NetLogProxySink& operator=(const NetLogProxySink&) = delete;
// Attaches a source of external NetLog events. The source is automatically
// removed if the mojo pipes are closed.
void AttachSource(mojo::PendingRemote<network::mojom::NetLogProxySource>
proxy_source_remote,
mojo::PendingReceiver<network::mojom::NetLogProxySink>
proxy_sink_receiver);
// net::NetLog::ThreadSafeCaptureModeObserver:
// Notifies attached sources that the capture mode has changed.
void OnCaptureModeUpdated(net::NetLogCaptureModeSet modes) override;
// mojom::NetLogProxySink:
void AddEntry(uint32_t type,
uint32_t source_type,
uint32_t source_id,
base::TimeTicks source_start_time,
net::NetLogEventPhase phase,
base::TimeTicks time,
base::Value params) override;
private:
mojo::RemoteSet<network::mojom::NetLogProxySource> proxy_source_remotes_;
mojo::ReceiverSet<network::mojom::NetLogProxySink> proxy_sink_receivers_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// A WeakPtr to |this|, which is used when posting tasks from the
// NetLog::ThreadSafeCaptureModeObserver to |task_runner_|. This single
// WeakPtr instance is used for all tasks as the ThreadSafeObserver may call
// on any thread, so the weak_factory_ cannot be accessed safely from those
// threads.
base::WeakPtr<NetLogProxySink> weak_this_;
base::WeakPtrFactory<NetLogProxySink> weak_factory_{this};
};
} // namespace network
#endif // SERVICES_NETWORK_NET_LOG_PROXY_SINK_H_
// Copyright 2020 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 "services/network/net_log_proxy_sink.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "net/log/test_net_log.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class FakeNetLogProxySource : public network::mojom::NetLogProxySource {
public:
explicit FakeNetLogProxySource(
mojo::PendingReceiver<network::mojom::NetLogProxySource>
proxy_source_receiver)
: proxy_source_receiver_(this, std::move(proxy_source_receiver)),
run_loop_(std::make_unique<base::RunLoop>()) {}
FakeNetLogProxySource(const FakeNetLogProxySource&) = delete;
FakeNetLogProxySource& operator=(const FakeNetLogProxySource&) = delete;
// mojom::NetLogProxySource:
void UpdateCaptureModes(net::NetLogCaptureModeSet modes) override {
EXPECT_FALSE(already_stored_last_modes_);
already_stored_last_modes_ = true;
last_modes_ = modes;
run_loop_->Quit();
}
net::NetLogCaptureModeSet WaitForUpdateCaptureModes() {
run_loop_->Run();
EXPECT_TRUE(already_stored_last_modes_);
already_stored_last_modes_ = false;
net::NetLogCaptureModeSet last_modes = last_modes_;
last_modes_ = 0;
run_loop_ = std::make_unique<base::RunLoop>();
return last_modes;
}
private:
mojo::Receiver<network::mojom::NetLogProxySource> proxy_source_receiver_;
bool already_stored_last_modes_ = false;
std::unique_ptr<base::RunLoop> run_loop_;
net::NetLogCaptureModeSet last_modes_;
};
void CreateObserver(std::unique_ptr<net::RecordingNetLogObserver>* out_observer,
net::NetLogCaptureMode capture_mode) {
*out_observer = std::make_unique<net::RecordingNetLogObserver>(capture_mode);
}
void DestroyObserver(
std::unique_ptr<net::RecordingNetLogObserver>* out_observer) {
out_observer->reset();
}
} // namespace
TEST(NetLogProxySink, TestMultipleObservers) {
base::test::TaskEnvironment scoped_task_environment;
network::NetLogProxySink net_log_sink;
mojo::PendingRemote<network::mojom::NetLogProxySource> proxy_source_remote;
mojo::PendingReceiver<network::mojom::NetLogProxySource>
proxy_source_receiver =
proxy_source_remote.InitWithNewPipeAndPassReceiver();
mojo::Remote<network::mojom::NetLogProxySink> proxy_sink_remote;
FakeNetLogProxySource net_log_proxy_source(std::move(proxy_source_receiver));
net_log_sink.AttachSource(std::move(proxy_source_remote),
proxy_sink_remote.BindNewPipeAndPassReceiver());
// Attaching should notify with the current capture modeset.
EXPECT_EQ(0U, net_log_proxy_source.WaitForUpdateCaptureModes());
std::unique_ptr<net::RecordingNetLogObserver> net_log_observer1 =
std::make_unique<net::RecordingNetLogObserver>(
net::NetLogCaptureMode::kIncludeSensitive);
EXPECT_EQ(
net::NetLogCaptureModeToBit(net::NetLogCaptureMode::kIncludeSensitive),
net_log_proxy_source.WaitForUpdateCaptureModes());
std::unique_ptr<net::RecordingNetLogObserver> net_log_observer2;
// Create observer2 on a different thread.
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(&CreateObserver, &net_log_observer2,
net::NetLogCaptureMode::kDefault));
EXPECT_EQ(
net::NetLogCaptureModeToBit(net::NetLogCaptureMode::kIncludeSensitive) |
net::NetLogCaptureModeToBit(net::NetLogCaptureMode::kDefault),
net_log_proxy_source.WaitForUpdateCaptureModes());
base::RunLoop add_entry_runloop;
net_log_observer1->SetThreadsafeAddEntryCallback(
add_entry_runloop.QuitClosure());
base::TimeTicks source1_start_time =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(10);
base::TimeTicks source1_event0_time =
source1_start_time + base::TimeDelta::FromMilliseconds(1);
base::Value source1_event0_params(base::Value::Type::DICTIONARY);
source1_event0_params.SetStringKey("hello", "world");
proxy_sink_remote->AddEntry(
static_cast<uint32_t>(net::NetLogEventType::REQUEST_ALIVE),
static_cast<uint32_t>(net::NetLogSourceType::URL_REQUEST), 1U,
source1_start_time, net::NetLogEventPhase::BEGIN, source1_event0_time,
source1_event0_params.Clone());
add_entry_runloop.Run();
auto entries = net_log_observer1->GetEntries();
ASSERT_EQ(1U, entries.size());
EXPECT_EQ(net::NetLogEventType::REQUEST_ALIVE, entries[0].type);
EXPECT_EQ(net::NetLogSourceType::URL_REQUEST, entries[0].source.type);
EXPECT_EQ(1U, entries[0].source.id);
EXPECT_EQ(source1_start_time, entries[0].source.start_time);
EXPECT_EQ(net::NetLogEventPhase::BEGIN, entries[0].phase);
EXPECT_EQ(source1_event0_time, entries[0].time);
EXPECT_TRUE(entries[0].HasParams());
EXPECT_EQ(source1_event0_params, entries[0].params);
auto entries2 = net_log_observer2->GetEntries();
ASSERT_EQ(1U, entries2.size());
EXPECT_EQ(entries[0].type, entries2[0].type);
EXPECT_EQ(entries[0].source.type, entries2[0].source.type);
EXPECT_EQ(entries[0].source.id, entries2[0].source.id);
EXPECT_EQ(entries[0].source.start_time, entries2[0].source.start_time);
EXPECT_EQ(entries[0].phase, entries2[0].phase);
EXPECT_EQ(entries[0].time, entries2[0].time);
EXPECT_EQ(entries[0].params, entries2[0].params);
net_log_observer1.reset();
EXPECT_EQ(net::NetLogCaptureModeToBit(net::NetLogCaptureMode::kDefault),
net_log_proxy_source.WaitForUpdateCaptureModes());
// Destroy observer2 on a different thread.
base::ThreadPool::PostTask(
FROM_HERE, base::BindOnce(DestroyObserver, &net_log_observer2));
EXPECT_EQ(0U, net_log_proxy_source.WaitForUpdateCaptureModes());
}
TEST(NetLogProxySink, TestAttachAfterObserverAdded) {
base::test::TaskEnvironment scoped_task_environment;
// Start observing before creating/attaching the net log proxy.
std::unique_ptr<net::RecordingNetLogObserver> net_log_observer1 =
std::make_unique<net::RecordingNetLogObserver>(
net::NetLogCaptureMode::kIncludeSensitive);
network::NetLogProxySink net_log_sink;
mojo::PendingRemote<network::mojom::NetLogProxySource> proxy_source_remote;
mojo::PendingReceiver<network::mojom::NetLogProxySource>
proxy_source_receiver =
proxy_source_remote.InitWithNewPipeAndPassReceiver();
mojo::Remote<network::mojom::NetLogProxySink> proxy_sink_remote;
FakeNetLogProxySource net_log_proxy_source(std::move(proxy_source_receiver));
net_log_sink.AttachSource(std::move(proxy_source_remote),
proxy_sink_remote.BindNewPipeAndPassReceiver());
// Attaching should notify with the current capture modeset.
EXPECT_EQ(
net::NetLogCaptureModeToBit(net::NetLogCaptureMode::kIncludeSensitive),
net_log_proxy_source.WaitForUpdateCaptureModes());
net_log_observer1.reset();
EXPECT_EQ(0U, net_log_proxy_source.WaitForUpdateCaptureModes());
}
......@@ -51,6 +51,7 @@
#include "services/network/http_auth_cache_copier.h"
#include "services/network/legacy_tls_config_distributor.h"
#include "services/network/net_log_exporter.h"
#include "services/network/net_log_proxy_sink.h"
#include "services/network/network_context.h"
#include "services/network/network_usage_accumulator.h"
#include "services/network/public/cpp/features.h"
......@@ -457,6 +458,15 @@ void NetworkService::StartNetLog(base::File file,
file_net_log_observer_->StartObserving(net_log_, capture_mode);
}
void NetworkService::AttachNetLogProxy(
mojo::PendingRemote<mojom::NetLogProxySource> proxy_source,
mojo::PendingReceiver<mojom::NetLogProxySink> proxy_sink) {
if (!net_log_proxy_sink_)
net_log_proxy_sink_ = std::make_unique<NetLogProxySink>();
net_log_proxy_sink_->AttachSource(std::move(proxy_source),
std::move(proxy_sink));
}
void NetworkService::SetSSLKeyLogFile(base::File file) {
net::SSLClientSocket::SetSSLKeyLogger(
std::make_unique<net::SSLKeyLoggerImpl>(std::move(file)));
......
......@@ -55,6 +55,7 @@ class CRLSetDistributor;
class DnsConfigChangeManager;
class HttpAuthCacheCopier;
class LegacyTLSConfigDistributor;
class NetLogProxySink;
class NetworkContext;
class NetworkUsageAccumulator;
......@@ -114,6 +115,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
void StartNetLog(base::File file,
net::NetLogCaptureMode capture_mode,
base::Value constants) override;
void AttachNetLogProxy(
mojo::PendingRemote<mojom::NetLogProxySource> proxy_source,
mojo::PendingReceiver<mojom::NetLogProxySink>) override;
void SetSSLKeyLogFile(base::File file) override;
void CreateNetworkContext(
mojo::PendingReceiver<mojom::NetworkContext> receiver,
......@@ -258,6 +262,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
net::NetLog* net_log_;
std::unique_ptr<NetLogProxySink> net_log_proxy_sink_;
std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
net::TraceNetLogObserver trace_net_log_observer_;
......
......@@ -242,6 +242,7 @@ source_set("tests") {
"is_potentially_trustworthy_unittest.cc",
"mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc",
"mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc",
"net_log_mojom_traits_unittest.cc",
"network_connection_tracker_unittest.cc",
"network_isolation_key_mojom_traits_unittest.cc",
"network_mojom_traits_unittest.cc",
......
......@@ -3,12 +3,14 @@
# found in the LICENSE file.
mojom = "//services/network/public/mojom/net_log.mojom"
public_headers = [ "//net/log/net_log_capture_mode.h" ]
traits_headers = [ "/services/network/public/cpp/net_log_mojom_traits.h" ]
sources = [
"//services/network/public/cpp/net_log_mojom_traits.cc",
public_headers = [
"//net/log/net_log_capture_mode.h",
"//net/log/net_log_event_type.h",
]
type_mappings = [ "network.mojom.NetLogCaptureMode=::net::NetLogCaptureMode" ]
public_deps = [
"//net",
traits_headers = [ "/services/network/public/cpp/net_log_mojom_traits.h" ]
sources = [ "//services/network/public/cpp/net_log_mojom_traits.cc" ]
type_mappings = [
"network.mojom.NetLogCaptureMode=::net::NetLogCaptureMode",
"network.mojom.NetLogEventPhase=::net::NetLogEventPhase",
]
public_deps = [ "//net" ]
......@@ -41,4 +41,39 @@ EnumTraits<network::mojom::NetLogCaptureMode, net::NetLogCaptureMode>::ToMojom(
return network::mojom::NetLogCaptureMode::DEFAULT;
}
// static
bool EnumTraits<network::mojom::NetLogEventPhase, net::NetLogEventPhase>::
FromMojom(network::mojom::NetLogEventPhase capture_mode,
net::NetLogEventPhase* out) {
switch (capture_mode) {
case network::mojom::NetLogEventPhase::BEGIN:
*out = net::NetLogEventPhase::BEGIN;
return true;
case network::mojom::NetLogEventPhase::END:
*out = net::NetLogEventPhase::END;
return true;
case network::mojom::NetLogEventPhase::NONE:
*out = net::NetLogEventPhase::NONE;
return true;
}
return false;
}
// static
network::mojom::NetLogEventPhase
EnumTraits<network::mojom::NetLogEventPhase, net::NetLogEventPhase>::ToMojom(
net::NetLogEventPhase capture_mode) {
switch (capture_mode) {
case net::NetLogEventPhase::BEGIN:
return network::mojom::NetLogEventPhase::BEGIN;
case net::NetLogEventPhase::END:
return network::mojom::NetLogEventPhase::END;
case net::NetLogEventPhase::NONE:
return network::mojom::NetLogEventPhase::NONE;
}
NOTREACHED();
return network::mojom::NetLogEventPhase::NONE;
}
} // namespace mojo
......@@ -18,6 +18,14 @@ struct EnumTraits<network::mojom::NetLogCaptureMode, net::NetLogCaptureMode> {
net::NetLogCaptureMode* out);
};
template <>
struct EnumTraits<network::mojom::NetLogEventPhase, net::NetLogEventPhase> {
static network::mojom::NetLogEventPhase ToMojom(
net::NetLogEventPhase capture_mode);
static bool FromMojom(network::mojom::NetLogEventPhase capture_mode,
net::NetLogEventPhase* out);
};
} // namespace mojo
#endif // SERVICES_NETWORK_PUBLIC_CPP_NET_LOG_MOJOM_TRAITS_H_
// Copyright 2020 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 "services/network/public/cpp/net_log_mojom_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
namespace {
template <typename MojoType, typename NativeType>
bool SerializeAndDeserializeEnum(NativeType in, NativeType* out) {
MojoType intermediate = mojo::EnumTraits<MojoType, NativeType>::ToMojom(in);
return mojo::EnumTraits<MojoType, NativeType>::FromMojom(intermediate, out);
}
TEST(NetLogTraitsTest, Roundtrips_CaptureMode) {
for (const net::NetLogCaptureMode capture_mode :
{net::NetLogCaptureMode::kDefault,
net::NetLogCaptureMode::kIncludeSensitive,
net::NetLogCaptureMode::kEverything}) {
net::NetLogCaptureMode roundtrip;
ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::NetLogCaptureMode>(
capture_mode, &roundtrip));
EXPECT_EQ(capture_mode, roundtrip);
}
}
TEST(NetLogTraitsTest, Roundtrips_EventPhase) {
for (const net::NetLogEventPhase event_phase :
{net::NetLogEventPhase::NONE, net::NetLogEventPhase::BEGIN,
net::NetLogEventPhase::END}) {
net::NetLogEventPhase roundtrip;
ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::NetLogEventPhase>(
event_phase, &roundtrip));
EXPECT_EQ(event_phase, roundtrip);
}
}
} // namespace
} // namespace network
......@@ -5,6 +5,7 @@
module network.mojom;
import "mojo/public/mojom/base/file.mojom";
import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/values.mojom";
enum NetLogCaptureMode {
......@@ -51,3 +52,31 @@ interface NetLogExporter {
// the file has been fully written.
Stop(mojo_base.mojom.DictionaryValue polled_values) => (int32 net_error);
};
// Equivalent to NetLogEventPhase in net/log/net_log_event_type.h.
enum NetLogEventPhase {
BEGIN,
END,
NONE
};
// Sources that generate NetLog events outside the network service implement
// this interface to receive notifications when the NetLog capture mode
// changes.
interface NetLogProxySource {
// |modes| is a NetLogCaptureModeSet, a bitfield.
UpdateCaptureModes(uint32 modes);
};
// Receives NetLog events from another process and inserts them into the main
// NetLog.
interface NetLogProxySink {
// Adds a NetLog entry. |source_id| values must not conflict with the source
// IDs generated in the network service or in other sources. The process
// sending the entries can use the net::NetLog::InitializeSourceIdPartition()
// function to ensure this, see the comments for that function for caveats.
AddEntry(/*NetLogEventType*/ uint32 type,
/*NetLogSourceType*/ uint32 source_type, uint32 source_id,
mojo_base.mojom.TimeTicks source_start_time, NetLogEventPhase phase,
mojo_base.mojom.TimeTicks time, mojo_base.mojom.Value params);
};
......@@ -188,6 +188,13 @@ interface NetworkService {
NetLogCaptureMode capture_mode,
mojo_base.mojom.DictionaryValue constants);
// Attaches an external source of NetLog events. Control events will be sent
// to the |proxy_source| pipe indicating when netlogging is active, the
// NetLog events should be sent to the |proxy_sink| pipe, and must use a
// non-conflicting source id space.
AttachNetLogProxy(pending_remote<NetLogProxySource> proxy_source,
pending_receiver<NetLogProxySink> proxy_sink);
// Starts logging SSL key material to the |file|. This must be called before
// any SSL connections are made. (See |SSLClientSocket::SetSSLKeyLogger()|
// for more details).
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment