forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmojo_net_log.cc
251 lines (213 loc) · 9.05 KB
/
mojo_net_log.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright 2018 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/mojo_net_log.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "base/values.h"
#include "net/log/file_net_log_observer.h"
#include "net/log/net_log_util.h"
#include "net/url_request/url_request_context.h"
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/network_switches.h"
namespace network {
MojoNetLog::MojoNetLog() {}
MojoNetLog::~MojoNetLog() {
if (file_net_log_observer_)
file_net_log_observer_->StopObserving(nullptr /*polled_data*/,
base::OnceClosure());
}
void MojoNetLog::ProcessCommandLine(const base::CommandLine& command_line) {
if (!command_line.HasSwitch(switches::kLogNetLog))
return;
base::FilePath log_path =
command_line.GetSwitchValuePath(switches::kLogNetLog);
// TODO(eroman): Should get capture mode from the command line.
net::NetLogCaptureMode capture_mode =
net::NetLogCaptureMode::IncludeCookiesAndCredentials();
file_net_log_observer_ = net::FileNetLogObserver::CreateUnbounded(
log_path, nullptr /* constants */);
file_net_log_observer_->StartObserving(this, capture_mode);
}
NetLogExporter::NetLogExporter(NetworkContext* network_context)
: network_context_(network_context), state_(STATE_IDLE) {}
NetLogExporter::~NetLogExporter() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// In case scratch directory creation didn't finish by the time |this| is
// destroyed, |destination_| is still owned here (rather than handed over to
// FileNetLogObserver); ask the scheduler to close it someplace suitable.
if (destination_.IsValid())
CloseFileOffThread(std::move(destination_));
// ~FileNetLogObserver will take care of unregistering from NetLog even
// if StopObserving isn't invoked.
}
void NetLogExporter::Start(base::File destination,
base::Value extra_constants,
NetLogExporter::CaptureMode capture_mode,
uint64_t max_file_size,
StartCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(destination.IsValid());
if (state_ != STATE_IDLE) {
CloseFileOffThread(std::move(destination));
std::move(callback).Run(net::ERR_UNEXPECTED);
return;
}
// Store the file explicitly since destroying it involves disk I/O, so must
// be carefully controlled.
destination_ = std::move(destination);
net::NetLogCaptureMode net_capture_mode;
switch (capture_mode) {
case NetLogExporter::CaptureMode::DEFAULT:
net_capture_mode = net::NetLogCaptureMode::Default();
break;
case NetLogExporter::CaptureMode::INCLUDE_COOKIES_AND_CREDENTIALS:
net_capture_mode = net::NetLogCaptureMode::IncludeCookiesAndCredentials();
break;
case NetLogExporter::CaptureMode::INCLUDE_SOCKET_BYTES:
net_capture_mode = net::NetLogCaptureMode::IncludeSocketBytes();
break;
}
state_ = STATE_WAITING_DIR;
static_assert(kUnlimitedFileSize == net::FileNetLogObserver::kNoLimit,
"Inconsistent unbounded size constants");
if (max_file_size != kUnlimitedFileSize) {
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&NetLogExporter::CreateScratchDir,
scratch_dir_create_handler_for_tests_),
// Note: this a static method which takes a weak pointer as an argument,
// so it will run if |this| is deleted.
base::BindOnce(&NetLogExporter::StartWithScratchDirOrCleanup,
AsWeakPtr(), std::move(extra_constants),
net_capture_mode, max_file_size, std::move(callback)));
} else {
StartWithScratchDir(std::move(extra_constants), net_capture_mode,
max_file_size, std::move(callback), base::FilePath());
}
}
void NetLogExporter::Stop(base::Value polled_data_value,
StopCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::DictionaryValue* polled_data = nullptr;
bool ok = polled_data_value.GetAsDictionary(&polled_data);
DCHECK(ok); // mojo is supposed to enforce that.
if (state_ != STATE_RUNNING) {
std::move(callback).Run(net::ERR_UNEXPECTED);
return;
}
std::unique_ptr<base::DictionaryValue> net_info = net::GetNetInfo(
network_context_->url_request_context(), net::NET_INFO_ALL_SOURCES);
if (polled_data)
net_info->MergeDictionary(polled_data);
file_net_observer_->StopObserving(
std::move(net_info),
base::BindOnce([](StopCallback sc) { std::move(sc).Run(net::OK); },
std::move(callback)));
file_net_observer_ = nullptr;
state_ = STATE_IDLE;
}
void NetLogExporter::SetCreateScratchDirHandlerForTesting(
const base::RepeatingCallback<base::FilePath()>& handler) {
scratch_dir_create_handler_for_tests_ = handler;
}
void NetLogExporter::CloseFileOffThread(base::File file) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (file.IsValid()) {
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce([](base::File f) { f.Close(); }, std::move(file)));
}
}
base::FilePath NetLogExporter::CreateScratchDir(
base::RepeatingCallback<base::FilePath()>
scratch_dir_create_handler_for_tests) {
if (scratch_dir_create_handler_for_tests)
return scratch_dir_create_handler_for_tests.Run();
base::ScopedTempDir scratch_dir;
if (scratch_dir.CreateUniqueTempDir())
return scratch_dir.Take();
else
return base::FilePath();
}
void NetLogExporter::StartWithScratchDirOrCleanup(
base::WeakPtr<NetLogExporter> object,
base::Value extra_constants,
net::NetLogCaptureMode capture_mode,
uint64_t max_file_size,
StartCallback callback,
const base::FilePath& scratch_dir_path) {
NetLogExporter* instance = object.get();
if (instance) {
instance->StartWithScratchDir(std::move(extra_constants), capture_mode,
max_file_size, std::move(callback),
scratch_dir_path);
} else if (!scratch_dir_path.empty()) {
// An NetLogExporter got destroyed while it was trying to create a scratch
// dir.
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(
[](const base::FilePath& dir) {
// The delete is non-recursive (2nd argument false) since the
// only time this is invoked the directory is expected to be
// empty.
base::DeleteFile(dir, false);
},
scratch_dir_path));
}
}
void NetLogExporter::StartWithScratchDir(
base::Value extra_constants_value,
net::NetLogCaptureMode capture_mode,
uint64_t max_file_size,
StartCallback callback,
const base::FilePath& scratch_dir_path) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::DictionaryValue* extra_constants = nullptr;
bool ok = extra_constants_value.GetAsDictionary(&extra_constants);
DCHECK(ok); // mojo is supposed to enforce that before Start() is invoked.
if (scratch_dir_path.empty() && max_file_size != kUnlimitedFileSize) {
state_ = STATE_IDLE;
CloseFileOffThread(std::move(destination_));
std::move(callback).Run(net::ERR_INSUFFICIENT_RESOURCES);
return;
}
state_ = STATE_RUNNING;
std::unique_ptr<base::DictionaryValue> constants = net::GetNetConstants();
if (extra_constants)
constants->MergeDictionary(extra_constants);
if (max_file_size != kUnlimitedFileSize) {
file_net_observer_ = net::FileNetLogObserver::CreateBoundedPreExisting(
scratch_dir_path, std::move(destination_), max_file_size,
std::move(constants));
} else {
DCHECK(scratch_dir_path.empty());
file_net_observer_ = net::FileNetLogObserver::CreateUnboundedPreExisting(
std::move(destination_), std::move(constants));
}
// There might not be a NetworkService object e.g. on iOS; in that case
// assume this present NetworkContext is all there is.
if (network_context_->network_service()) {
network_context_->network_service()->CreateNetLogEntriesForActiveObjects(
file_net_observer_.get());
} else {
std::set<net::URLRequestContext*> contexts;
contexts.insert(network_context_->url_request_context());
net::CreateNetLogEntriesForActiveObjects(contexts,
file_net_observer_.get());
}
file_net_observer_->StartObserving(
network_context_->url_request_context()->net_log(), capture_mode);
std::move(callback).Run(net::OK);
}
} // namespace network