1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
6
7 #include <algorithm>
8 #include <list>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/base64.h"
14 #include "base/bind.h"
15 #include "base/bind_helpers.h"
16 #include "base/command_line.h"
17 #include "base/files/file.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/memory/weak_ptr.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/prefs/pref_member.h"
23 #include "base/sequenced_task_runner_helpers.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_piece.h"
26 #include "base/strings/string_split.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/task/cancelable_task_tracker.h"
30 #include "base/values.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/browsing_data/browsing_data_helper.h"
33 #include "chrome/browser/browsing_data/browsing_data_remover.h"
34 #include "chrome/browser/chrome_notification_types.h"
35 #include "chrome/browser/download/download_prefs.h"
36 #include "chrome/browser/io_thread.h"
37 #include "chrome/browser/net/chrome_net_log.h"
38 #include "chrome/browser/net/chrome_network_delegate.h"
39 #include "chrome/browser/net/connection_tester.h"
40 #include "chrome/browser/prerender/prerender_manager.h"
41 #include "chrome/browser/prerender/prerender_manager_factory.h"
42 #include "chrome/browser/profiles/profile.h"
43 #include "chrome/common/chrome_paths.h"
44 #include "chrome/common/chrome_version_info.h"
45 #include "chrome/common/pref_names.h"
46 #include "chrome/common/url_constants.h"
47 #include "components/onc/onc_constants.h"
48 #include "components/url_fixer/url_fixer.h"
49 #include "content/public/browser/browser_thread.h"
50 #include "content/public/browser/notification_details.h"
51 #include "content/public/browser/resource_dispatcher_host.h"
52 #include "content/public/browser/web_contents.h"
53 #include "content/public/browser/web_ui.h"
54 #include "content/public/browser/web_ui_data_source.h"
55 #include "content/public/browser/web_ui_message_handler.h"
56 #include "grit/net_internals_resources.h"
57 #include "net/base/net_errors.h"
58 #include "net/base/net_log_logger.h"
59 #include "net/base/net_util.h"
60 #include "net/disk_cache/disk_cache.h"
61 #include "net/dns/host_cache.h"
62 #include "net/dns/host_resolver.h"
63 #include "net/http/http_cache.h"
64 #include "net/http/http_network_layer.h"
65 #include "net/http/http_network_session.h"
66 #include "net/http/http_server_properties.h"
67 #include "net/http/http_stream_factory.h"
68 #include "net/http/transport_security_state.h"
69 #include "net/proxy/proxy_service.h"
70 #include "net/url_request/url_request_context.h"
71 #include "net/url_request/url_request_context_getter.h"
72
73 #if defined(OS_CHROMEOS)
74 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
75 #include "chrome/browser/chromeos/net/onc_utils.h"
76 #include "chrome/browser/chromeos/profiles/profile_helper.h"
77 #include "chrome/browser/chromeos/system/syslogs_provider.h"
78 #include "chrome/browser/chromeos/system_logs/debug_log_writer.h"
79 #include "chrome/browser/net/nss_context.h"
80 #include "chromeos/dbus/dbus_thread_manager.h"
81 #include "chromeos/dbus/debug_daemon_client.h"
82 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
83 #include "chromeos/network/onc/onc_utils.h"
84 #include "components/user_manager/user.h"
85 #endif
86
87 #if defined(OS_WIN)
88 #include "chrome/browser/net/service_providers_win.h"
89 #endif
90
91 #if defined(ENABLE_EXTENSIONS)
92 #include "chrome/browser/extensions/extension_service.h"
93 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
94 #include "extensions/browser/extension_registry.h"
95 #include "extensions/browser/extension_system.h"
96 #include "extensions/common/extension_set.h"
97 #endif
98
99 using base::StringValue;
100 using content::BrowserThread;
101 using content::WebContents;
102 using content::WebUIMessageHandler;
103
104 namespace {
105
106 // Delay between when an event occurs and when it is passed to the Javascript
107 // page. All events that occur during this period are grouped together and
108 // sent to the page at once, which reduces context switching and CPU usage.
109 const int kNetLogEventDelayMilliseconds = 100;
110
111 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
112 // there is none.
GetHostResolverCache(net::URLRequestContext * context)113 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
114 return context->host_resolver()->GetHostCache();
115 }
116
HashesToBase64String(const net::HashValueVector & hashes)117 std::string HashesToBase64String(const net::HashValueVector& hashes) {
118 std::string str;
119 for (size_t i = 0; i != hashes.size(); ++i) {
120 if (i != 0)
121 str += ",";
122 str += hashes[i].ToString();
123 }
124 return str;
125 }
126
Base64StringToHashes(const std::string & hashes_str,net::HashValueVector * hashes)127 bool Base64StringToHashes(const std::string& hashes_str,
128 net::HashValueVector* hashes) {
129 hashes->clear();
130 std::vector<std::string> vector_hash_str;
131 base::SplitString(hashes_str, ',', &vector_hash_str);
132
133 for (size_t i = 0; i != vector_hash_str.size(); ++i) {
134 std::string hash_str;
135 base::RemoveChars(vector_hash_str[i], " \t\r\n", &hash_str);
136 net::HashValue hash;
137 // Skip past unrecognized hash algos
138 // But return false on malformatted input
139 if (hash_str.empty())
140 return false;
141 if (hash_str.compare(0, 5, "sha1/") != 0 &&
142 hash_str.compare(0, 7, "sha256/") != 0) {
143 continue;
144 }
145 if (!hash.FromString(hash_str))
146 return false;
147 hashes->push_back(hash);
148 }
149 return true;
150 }
151
152 // Returns a Value representing the state of a pre-existing URLRequest when
153 // net-internals was opened.
GetRequestStateAsValue(const net::URLRequest * request,net::NetLog::LogLevel log_level)154 base::Value* GetRequestStateAsValue(const net::URLRequest* request,
155 net::NetLog::LogLevel log_level) {
156 return request->GetStateAsValue();
157 }
158
159 // Returns true if |request1| was created before |request2|.
RequestCreatedBefore(const net::URLRequest * request1,const net::URLRequest * request2)160 bool RequestCreatedBefore(const net::URLRequest* request1,
161 const net::URLRequest* request2) {
162 return request1->creation_time() < request2->creation_time();
163 }
164
165 // Returns the disk cache backend for |context| if there is one, or NULL.
GetDiskCacheBackend(net::URLRequestContext * context)166 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
167 if (!context->http_transaction_factory())
168 return NULL;
169
170 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
171 if (!http_cache)
172 return NULL;
173
174 return http_cache->GetCurrentBackend();
175 }
176
177 // Returns the http network session for |context| if there is one.
178 // Otherwise, returns NULL.
GetHttpNetworkSession(net::URLRequestContext * context)179 net::HttpNetworkSession* GetHttpNetworkSession(
180 net::URLRequestContext* context) {
181 if (!context->http_transaction_factory())
182 return NULL;
183
184 return context->http_transaction_factory()->GetSession();
185 }
186
ExperimentToValue(const ConnectionTester::Experiment & experiment)187 base::Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
188 base::DictionaryValue* dict = new base::DictionaryValue();
189
190 if (experiment.url.is_valid())
191 dict->SetString("url", experiment.url.spec());
192
193 dict->SetString("proxy_settings_experiment",
194 ConnectionTester::ProxySettingsExperimentDescription(
195 experiment.proxy_settings_experiment));
196 dict->SetString("host_resolver_experiment",
197 ConnectionTester::HostResolverExperimentDescription(
198 experiment.host_resolver_experiment));
199 return dict;
200 }
201
CreateNetInternalsHTMLSource()202 content::WebUIDataSource* CreateNetInternalsHTMLSource() {
203 content::WebUIDataSource* source =
204 content::WebUIDataSource::Create(chrome::kChromeUINetInternalsHost);
205
206 source->SetUseJsonJSFormatV2();
207 source->SetDefaultResource(IDR_NET_INTERNALS_INDEX_HTML);
208 source->AddResourcePath("index.js", IDR_NET_INTERNALS_INDEX_JS);
209 source->SetJsonPath("strings.js");
210 return source;
211 }
212
213 // This class receives javascript messages from the renderer.
214 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
215 // this class's methods are expected to run on the UI thread.
216 //
217 // Since the network code we want to run lives on the IO thread, we proxy
218 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
219 // runs on the IO thread.
220 //
221 // TODO(eroman): Can we start on the IO thread to begin with?
222 class NetInternalsMessageHandler
223 : public WebUIMessageHandler,
224 public base::SupportsWeakPtr<NetInternalsMessageHandler> {
225 public:
226 NetInternalsMessageHandler();
227 virtual ~NetInternalsMessageHandler();
228
229 // WebUIMessageHandler implementation.
230 virtual void RegisterMessages() OVERRIDE;
231
232 // Calls g_browser.receive in the renderer, passing in |command| and |arg|.
233 // Takes ownership of |arg|. If the renderer is displaying a log file, the
234 // message will be ignored.
235 void SendJavascriptCommand(const std::string& command, base::Value* arg);
236
237 // Javascript message handlers.
238 void OnRendererReady(const base::ListValue* list);
239 void OnClearBrowserCache(const base::ListValue* list);
240 void OnGetPrerenderInfo(const base::ListValue* list);
241 void OnGetHistoricNetworkStats(const base::ListValue* list);
242 void OnGetExtensionInfo(const base::ListValue* list);
243 #if defined(OS_CHROMEOS)
244 void OnRefreshSystemLogs(const base::ListValue* list);
245 void OnGetSystemLog(const base::ListValue* list);
246 void OnImportONCFile(const base::ListValue* list);
247 void OnStoreDebugLogs(const base::ListValue* list);
248 void OnStoreDebugLogsCompleted(const base::FilePath& log_path,
249 bool succeeded);
250 void OnSetNetworkDebugMode(const base::ListValue* list);
251 void OnSetNetworkDebugModeCompleted(const std::string& subsystem,
252 bool succeeded);
253
254 // Callback to |GetNSSCertDatabaseForProfile| used to retrieve the database
255 // to which user's ONC defined certificates should be imported.
256 // It parses and imports |onc_blob|.
257 void ImportONCFileToNSSDB(const std::string& onc_blob,
258 const std::string& passcode,
259 net::NSSCertDatabase* nssdb);
260
261 // Called back by the CertificateImporter when a certificate import finished.
262 // |previous_error| contains earlier errors during this import.
263 void OnCertificatesImported(
264 const std::string& previous_error,
265 bool success,
266 const net::CertificateList& onc_trusted_certificates);
267 #endif
268
269 private:
270 class IOThreadImpl;
271
272 #if defined(OS_CHROMEOS)
273 // Class that is used for getting network related ChromeOS logs.
274 // Logs are fetched from ChromeOS libcros on user request, and only when we
275 // don't yet have a copy of logs. If a copy is present, we send back data from
276 // it, else we save request and answer to it when we get logs from libcros.
277 // If needed, we also send request for system logs to libcros.
278 // Logs refresh has to be done explicitly, by deleting old logs and then
279 // loading them again.
280 class SystemLogsGetter {
281 public:
282 SystemLogsGetter(NetInternalsMessageHandler* handler,
283 chromeos::system::SyslogsProvider* syslogs_provider);
284 ~SystemLogsGetter();
285
286 // Deletes logs copy we currently have, and resets logs_requested and
287 // logs_received flags.
288 void DeleteSystemLogs();
289 // Starts log fetching. If logs copy is present, requested logs are sent
290 // back.
291 // If syslogs load request hasn't been sent to libcros yet, we do that now,
292 // and postpone sending response.
293 // Request data is specified by args:
294 // $1 : key of the log we are interested in.
295 // $2 : string used to identify request.
296 void RequestSystemLog(const base::ListValue* args);
297 // Requests logs from libcros, but only if we don't have a copy.
298 void LoadSystemLogs();
299 // Processes callback from libcros containing system logs. Postponed
300 // request responses are sent.
301 void OnSystemLogsLoaded(chromeos::system::LogDictionaryType* sys_info,
302 std::string* ignored_content);
303
304 private:
305 // Struct we save postponed log request in.
306 struct SystemLogRequest {
307 std::string log_key;
308 std::string cell_id;
309 };
310
311 // Processes request.
312 void SendLogs(const SystemLogRequest& request);
313
314 NetInternalsMessageHandler* handler_;
315 chromeos::system::SyslogsProvider* syslogs_provider_;
316 // List of postponed requests.
317 std::list<SystemLogRequest> requests_;
318 scoped_ptr<chromeos::system::LogDictionaryType> logs_;
319 bool logs_received_;
320 bool logs_requested_;
321 base::CancelableTaskTracker tracker_;
322 // Libcros request task ID.
323 base::CancelableTaskTracker::TaskId syslogs_task_id_;
324 };
325 #endif // defined(OS_CHROMEOS)
326
327 // This is the "real" message handler, which lives on the IO thread.
328 scoped_refptr<IOThreadImpl> proxy_;
329
330 base::WeakPtr<prerender::PrerenderManager> prerender_manager_;
331
332 #if defined(OS_CHROMEOS)
333 // Class that handles getting and filtering system logs.
334 scoped_ptr<SystemLogsGetter> syslogs_getter_;
335 #endif
336
337 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
338 };
339
340 // This class is the "real" message handler. It is allocated and destroyed on
341 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
342 // SendJavascriptCommand, its methods are all expected to be called from the IO
343 // thread. OnAddEntry and SendJavascriptCommand can be called from any thread,
344 // and OnWebUIDeleted can only be called from the UI thread.
345 class NetInternalsMessageHandler::IOThreadImpl
346 : public base::RefCountedThreadSafe<
347 NetInternalsMessageHandler::IOThreadImpl,
348 BrowserThread::DeleteOnUIThread>,
349 public net::NetLog::ThreadSafeObserver,
350 public ConnectionTester::Delegate {
351 public:
352 // Type for methods that can be used as MessageHandler callbacks.
353 typedef void (IOThreadImpl::*MessageHandler)(const base::ListValue*);
354
355 // Creates a proxy for |handler| that will live on the IO thread.
356 // |handler| is a weak pointer, since it is possible for the
357 // WebUIMessageHandler to be deleted on the UI thread while we were executing
358 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
359 // an argument since we need to grab it from the UI thread).
360 IOThreadImpl(
361 const base::WeakPtr<NetInternalsMessageHandler>& handler,
362 IOThread* io_thread,
363 net::URLRequestContextGetter* main_context_getter);
364
365 // Called on UI thread just after creation, to add a ContextGetter to
366 // |context_getters_|.
367 void AddRequestContextGetter(net::URLRequestContextGetter* context_getter);
368
369 // Helper method to enable a callback that will be executed on the IO thread.
370 static void CallbackHelper(MessageHandler method,
371 scoped_refptr<IOThreadImpl> io_thread,
372 const base::ListValue* list);
373
374 // Called once the WebUI has been deleted (i.e. renderer went away), on the
375 // IO thread.
376 void Detach();
377
378 // Called when the WebUI is deleted. Prevents calling Javascript functions
379 // afterwards. Called on UI thread.
380 void OnWebUIDeleted();
381
382 //--------------------------------
383 // Javascript message handlers:
384 //--------------------------------
385
386 void OnRendererReady(const base::ListValue* list);
387
388 void OnGetProxySettings(const base::ListValue* list);
389 void OnReloadProxySettings(const base::ListValue* list);
390 void OnGetBadProxies(const base::ListValue* list);
391 void OnClearBadProxies(const base::ListValue* list);
392 void OnGetHostResolverInfo(const base::ListValue* list);
393 void OnClearHostResolverCache(const base::ListValue* list);
394 void OnEnableIPv6(const base::ListValue* list);
395 void OnStartConnectionTests(const base::ListValue* list);
396 void OnHSTSQuery(const base::ListValue* list);
397 void OnHSTSAdd(const base::ListValue* list);
398 void OnHSTSDelete(const base::ListValue* list);
399 void OnGetHttpCacheInfo(const base::ListValue* list);
400 void OnGetSocketPoolInfo(const base::ListValue* list);
401 void OnGetSessionNetworkStats(const base::ListValue* list);
402 void OnCloseIdleSockets(const base::ListValue* list);
403 void OnFlushSocketPools(const base::ListValue* list);
404 void OnGetSpdySessionInfo(const base::ListValue* list);
405 void OnGetSpdyStatus(const base::ListValue* list);
406 void OnGetSpdyAlternateProtocolMappings(const base::ListValue* list);
407 void OnGetQuicInfo(const base::ListValue* list);
408 #if defined(OS_WIN)
409 void OnGetServiceProviders(const base::ListValue* list);
410 #endif
411 void OnSetLogLevel(const base::ListValue* list);
412
413 // ChromeNetLog::ThreadSafeObserver implementation:
414 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
415
416 // ConnectionTester::Delegate implementation:
417 virtual void OnStartConnectionTestSuite() OVERRIDE;
418 virtual void OnStartConnectionTestExperiment(
419 const ConnectionTester::Experiment& experiment) OVERRIDE;
420 virtual void OnCompletedConnectionTestExperiment(
421 const ConnectionTester::Experiment& experiment,
422 int result) OVERRIDE;
423 virtual void OnCompletedConnectionTestSuite() OVERRIDE;
424
425 // Helper that calls g_browser.receive in the renderer, passing in |command|
426 // and |arg|. Takes ownership of |arg|. If the renderer is displaying a log
427 // file, the message will be ignored. Note that this can be called from any
428 // thread.
429 void SendJavascriptCommand(const std::string& command, base::Value* arg);
430
431 private:
432 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
433 friend class base::DeleteHelper<IOThreadImpl>;
434
435 typedef std::list<scoped_refptr<net::URLRequestContextGetter> >
436 ContextGetterList;
437
438 virtual ~IOThreadImpl();
439
440 // Adds |entry| to the queue of pending log entries to be sent to the page via
441 // Javascript. Must be called on the IO Thread. Also creates a delayed task
442 // that will call PostPendingEntries, if there isn't one already.
443 void AddEntryToQueue(base::Value* entry);
444
445 // Sends all pending entries to the page via Javascript, and clears the list
446 // of pending entries. Sending multiple entries at once results in a
447 // significant reduction of CPU usage when a lot of events are happening.
448 // Must be called on the IO Thread.
449 void PostPendingEntries();
450
451 // Adds entries with the states of ongoing URL requests.
452 void PrePopulateEventList();
453
GetMainContext()454 net::URLRequestContext* GetMainContext() {
455 return main_context_getter_->GetURLRequestContext();
456 }
457
458 // Pointer to the UI-thread message handler. Only access this from
459 // the UI thread.
460 base::WeakPtr<NetInternalsMessageHandler> handler_;
461
462 // The global IOThread, which contains the global NetLog to observer.
463 IOThread* io_thread_;
464
465 // The main URLRequestContextGetter for the tab's profile.
466 scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
467
468 // Helper that runs the suite of connection tests.
469 scoped_ptr<ConnectionTester> connection_tester_;
470
471 // True if the Web UI has been deleted. This is used to prevent calling
472 // Javascript functions after the Web UI is destroyed. On refresh, the
473 // messages can end up being sent to the refreshed page, causing duplicate
474 // or partial entries.
475 //
476 // This is only read and written to on the UI thread.
477 bool was_webui_deleted_;
478
479 // Log entries that have yet to be passed along to Javascript page. Non-NULL
480 // when and only when there is a pending delayed task to call
481 // PostPendingEntries. Read and written to exclusively on the IO Thread.
482 scoped_ptr<base::ListValue> pending_entries_;
483
484 // Used for getting current status of URLRequests when net-internals is
485 // opened. |main_context_getter_| is automatically added on construction.
486 // Duplicates are allowed.
487 ContextGetterList context_getters_;
488
489 DISALLOW_COPY_AND_ASSIGN(IOThreadImpl);
490 };
491
492 ////////////////////////////////////////////////////////////////////////////////
493 //
494 // NetInternalsMessageHandler
495 //
496 ////////////////////////////////////////////////////////////////////////////////
497
NetInternalsMessageHandler()498 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
499
~NetInternalsMessageHandler()500 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
501 if (proxy_.get()) {
502 proxy_.get()->OnWebUIDeleted();
503 // Notify the handler on the IO thread that the renderer is gone.
504 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
505 base::Bind(&IOThreadImpl::Detach, proxy_.get()));
506 }
507 }
508
RegisterMessages()509 void NetInternalsMessageHandler::RegisterMessages() {
510 DCHECK_CURRENTLY_ON(BrowserThread::UI);
511
512 Profile* profile = Profile::FromWebUI(web_ui());
513
514 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
515 profile->GetRequestContext());
516 proxy_->AddRequestContextGetter(profile->GetMediaRequestContext());
517 proxy_->AddRequestContextGetter(profile->GetRequestContextForExtensions());
518 #if defined(OS_CHROMEOS)
519 syslogs_getter_.reset(new SystemLogsGetter(this,
520 chromeos::system::SyslogsProvider::GetInstance()));
521 #endif
522
523 prerender::PrerenderManager* prerender_manager =
524 prerender::PrerenderManagerFactory::GetForProfile(profile);
525 if (prerender_manager) {
526 prerender_manager_ = prerender_manager->AsWeakPtr();
527 } else {
528 prerender_manager_ = base::WeakPtr<prerender::PrerenderManager>();
529 }
530
531 web_ui()->RegisterMessageCallback(
532 "notifyReady",
533 base::Bind(&NetInternalsMessageHandler::OnRendererReady,
534 base::Unretained(this)));
535 web_ui()->RegisterMessageCallback(
536 "getProxySettings",
537 base::Bind(&IOThreadImpl::CallbackHelper,
538 &IOThreadImpl::OnGetProxySettings, proxy_));
539 web_ui()->RegisterMessageCallback(
540 "reloadProxySettings",
541 base::Bind(&IOThreadImpl::CallbackHelper,
542 &IOThreadImpl::OnReloadProxySettings, proxy_));
543 web_ui()->RegisterMessageCallback(
544 "getBadProxies",
545 base::Bind(&IOThreadImpl::CallbackHelper,
546 &IOThreadImpl::OnGetBadProxies, proxy_));
547 web_ui()->RegisterMessageCallback(
548 "clearBadProxies",
549 base::Bind(&IOThreadImpl::CallbackHelper,
550 &IOThreadImpl::OnClearBadProxies, proxy_));
551 web_ui()->RegisterMessageCallback(
552 "getHostResolverInfo",
553 base::Bind(&IOThreadImpl::CallbackHelper,
554 &IOThreadImpl::OnGetHostResolverInfo, proxy_));
555 web_ui()->RegisterMessageCallback(
556 "clearHostResolverCache",
557 base::Bind(&IOThreadImpl::CallbackHelper,
558 &IOThreadImpl::OnClearHostResolverCache, proxy_));
559 web_ui()->RegisterMessageCallback(
560 "enableIPv6",
561 base::Bind(&IOThreadImpl::CallbackHelper,
562 &IOThreadImpl::OnEnableIPv6, proxy_));
563 web_ui()->RegisterMessageCallback(
564 "startConnectionTests",
565 base::Bind(&IOThreadImpl::CallbackHelper,
566 &IOThreadImpl::OnStartConnectionTests, proxy_));
567 web_ui()->RegisterMessageCallback(
568 "hstsQuery",
569 base::Bind(&IOThreadImpl::CallbackHelper,
570 &IOThreadImpl::OnHSTSQuery, proxy_));
571 web_ui()->RegisterMessageCallback(
572 "hstsAdd",
573 base::Bind(&IOThreadImpl::CallbackHelper,
574 &IOThreadImpl::OnHSTSAdd, proxy_));
575 web_ui()->RegisterMessageCallback(
576 "hstsDelete",
577 base::Bind(&IOThreadImpl::CallbackHelper,
578 &IOThreadImpl::OnHSTSDelete, proxy_));
579 web_ui()->RegisterMessageCallback(
580 "getHttpCacheInfo",
581 base::Bind(&IOThreadImpl::CallbackHelper,
582 &IOThreadImpl::OnGetHttpCacheInfo, proxy_));
583 web_ui()->RegisterMessageCallback(
584 "getSocketPoolInfo",
585 base::Bind(&IOThreadImpl::CallbackHelper,
586 &IOThreadImpl::OnGetSocketPoolInfo, proxy_));
587 web_ui()->RegisterMessageCallback(
588 "getSessionNetworkStats",
589 base::Bind(&IOThreadImpl::CallbackHelper,
590 &IOThreadImpl::OnGetSessionNetworkStats, proxy_));
591 web_ui()->RegisterMessageCallback(
592 "closeIdleSockets",
593 base::Bind(&IOThreadImpl::CallbackHelper,
594 &IOThreadImpl::OnCloseIdleSockets, proxy_));
595 web_ui()->RegisterMessageCallback(
596 "flushSocketPools",
597 base::Bind(&IOThreadImpl::CallbackHelper,
598 &IOThreadImpl::OnFlushSocketPools, proxy_));
599 web_ui()->RegisterMessageCallback(
600 "getSpdySessionInfo",
601 base::Bind(&IOThreadImpl::CallbackHelper,
602 &IOThreadImpl::OnGetSpdySessionInfo, proxy_));
603 web_ui()->RegisterMessageCallback(
604 "getSpdyStatus",
605 base::Bind(&IOThreadImpl::CallbackHelper,
606 &IOThreadImpl::OnGetSpdyStatus, proxy_));
607 web_ui()->RegisterMessageCallback(
608 "getSpdyAlternateProtocolMappings",
609 base::Bind(&IOThreadImpl::CallbackHelper,
610 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings, proxy_));
611 web_ui()->RegisterMessageCallback(
612 "getQuicInfo",
613 base::Bind(&IOThreadImpl::CallbackHelper,
614 &IOThreadImpl::OnGetQuicInfo, proxy_));
615 #if defined(OS_WIN)
616 web_ui()->RegisterMessageCallback(
617 "getServiceProviders",
618 base::Bind(&IOThreadImpl::CallbackHelper,
619 &IOThreadImpl::OnGetServiceProviders, proxy_));
620 #endif
621
622 web_ui()->RegisterMessageCallback(
623 "setLogLevel",
624 base::Bind(&IOThreadImpl::CallbackHelper,
625 &IOThreadImpl::OnSetLogLevel, proxy_));
626 web_ui()->RegisterMessageCallback(
627 "clearBrowserCache",
628 base::Bind(&NetInternalsMessageHandler::OnClearBrowserCache,
629 base::Unretained(this)));
630 web_ui()->RegisterMessageCallback(
631 "getPrerenderInfo",
632 base::Bind(&NetInternalsMessageHandler::OnGetPrerenderInfo,
633 base::Unretained(this)));
634 web_ui()->RegisterMessageCallback(
635 "getHistoricNetworkStats",
636 base::Bind(&NetInternalsMessageHandler::OnGetHistoricNetworkStats,
637 base::Unretained(this)));
638 web_ui()->RegisterMessageCallback(
639 "getExtensionInfo",
640 base::Bind(&NetInternalsMessageHandler::OnGetExtensionInfo,
641 base::Unretained(this)));
642 #if defined(OS_CHROMEOS)
643 web_ui()->RegisterMessageCallback(
644 "refreshSystemLogs",
645 base::Bind(&NetInternalsMessageHandler::OnRefreshSystemLogs,
646 base::Unretained(this)));
647 web_ui()->RegisterMessageCallback(
648 "getSystemLog",
649 base::Bind(&NetInternalsMessageHandler::OnGetSystemLog,
650 base::Unretained(this)));
651 web_ui()->RegisterMessageCallback(
652 "importONCFile",
653 base::Bind(&NetInternalsMessageHandler::OnImportONCFile,
654 base::Unretained(this)));
655 web_ui()->RegisterMessageCallback(
656 "storeDebugLogs",
657 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogs,
658 base::Unretained(this)));
659 web_ui()->RegisterMessageCallback(
660 "setNetworkDebugMode",
661 base::Bind(&NetInternalsMessageHandler::OnSetNetworkDebugMode,
662 base::Unretained(this)));
663 #endif
664 }
665
SendJavascriptCommand(const std::string & command,base::Value * arg)666 void NetInternalsMessageHandler::SendJavascriptCommand(
667 const std::string& command,
668 base::Value* arg) {
669 scoped_ptr<base::Value> command_value(new base::StringValue(command));
670 scoped_ptr<base::Value> value(arg);
671 DCHECK_CURRENTLY_ON(BrowserThread::UI);
672 if (value.get()) {
673 web_ui()->CallJavascriptFunction("g_browser.receive",
674 *command_value.get(),
675 *value.get());
676 } else {
677 web_ui()->CallJavascriptFunction("g_browser.receive",
678 *command_value.get());
679 }
680 }
681
OnRendererReady(const base::ListValue * list)682 void NetInternalsMessageHandler::OnRendererReady(const base::ListValue* list) {
683 IOThreadImpl::CallbackHelper(&IOThreadImpl::OnRendererReady, proxy_, list);
684 }
685
OnClearBrowserCache(const base::ListValue * list)686 void NetInternalsMessageHandler::OnClearBrowserCache(
687 const base::ListValue* list) {
688 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForUnboundedRange(
689 Profile::FromWebUI(web_ui()));
690 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
691 BrowsingDataHelper::UNPROTECTED_WEB);
692 // BrowsingDataRemover deletes itself.
693 }
694
OnGetPrerenderInfo(const base::ListValue * list)695 void NetInternalsMessageHandler::OnGetPrerenderInfo(
696 const base::ListValue* list) {
697 DCHECK_CURRENTLY_ON(BrowserThread::UI);
698
699 base::DictionaryValue* value = NULL;
700 prerender::PrerenderManager* prerender_manager = prerender_manager_.get();
701 if (!prerender_manager) {
702 value = new base::DictionaryValue();
703 value->SetBoolean("enabled", false);
704 value->SetBoolean("omnibox_enabled", false);
705 } else {
706 value = prerender_manager->GetAsValue();
707 }
708 SendJavascriptCommand("receivedPrerenderInfo", value);
709 }
710
OnGetHistoricNetworkStats(const base::ListValue * list)711 void NetInternalsMessageHandler::OnGetHistoricNetworkStats(
712 const base::ListValue* list) {
713 DCHECK_CURRENTLY_ON(BrowserThread::UI);
714 base::Value* historic_network_info =
715 ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue();
716 SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info);
717 }
718
OnGetExtensionInfo(const base::ListValue * list)719 void NetInternalsMessageHandler::OnGetExtensionInfo(
720 const base::ListValue* list) {
721 DCHECK_CURRENTLY_ON(BrowserThread::UI);
722 base::ListValue* extension_list = new base::ListValue();
723 #if defined(ENABLE_EXTENSIONS)
724 Profile* profile = Profile::FromWebUI(web_ui());
725 extensions::ExtensionSystem* extension_system =
726 extensions::ExtensionSystem::Get(profile);
727 if (extension_system) {
728 ExtensionService* extension_service = extension_system->extension_service();
729 if (extension_service) {
730 scoped_ptr<const extensions::ExtensionSet> extensions(
731 extensions::ExtensionRegistry::Get(profile)
732 ->GenerateInstalledExtensionsSet());
733 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
734 it != extensions->end(); ++it) {
735 base::DictionaryValue* extension_info = new base::DictionaryValue();
736 bool enabled = extension_service->IsExtensionEnabled((*it)->id());
737 extensions::GetExtensionBasicInfo(it->get(), enabled, extension_info);
738 extension_list->Append(extension_info);
739 }
740 }
741 }
742 #endif
743 SendJavascriptCommand("receivedExtensionInfo", extension_list);
744 }
745
746 #if defined(OS_CHROMEOS)
747 ////////////////////////////////////////////////////////////////////////////////
748 //
749 // NetInternalsMessageHandler::SystemLogsGetter
750 //
751 ////////////////////////////////////////////////////////////////////////////////
752
SystemLogsGetter(NetInternalsMessageHandler * handler,chromeos::system::SyslogsProvider * syslogs_provider)753 NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter(
754 NetInternalsMessageHandler* handler,
755 chromeos::system::SyslogsProvider* syslogs_provider)
756 : handler_(handler),
757 syslogs_provider_(syslogs_provider),
758 logs_received_(false),
759 logs_requested_(false) {
760 if (!syslogs_provider_)
761 LOG(ERROR) << "System access library not loaded";
762 }
763
~SystemLogsGetter()764 NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() {
765 DeleteSystemLogs();
766 }
767
DeleteSystemLogs()768 void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() {
769 if (syslogs_provider_ && logs_requested_ && !logs_received_) {
770 tracker_.TryCancel(syslogs_task_id_);
771 }
772 logs_requested_ = false;
773 logs_received_ = false;
774 logs_.reset();
775 }
776
RequestSystemLog(const base::ListValue * args)777 void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog(
778 const base::ListValue* args) {
779 if (!logs_requested_) {
780 DCHECK(!logs_received_);
781 LoadSystemLogs();
782 }
783 SystemLogRequest log_request;
784 args->GetString(0, &log_request.log_key);
785 args->GetString(1, &log_request.cell_id);
786
787 if (logs_received_) {
788 SendLogs(log_request);
789 } else {
790 requests_.push_back(log_request);
791 }
792 }
793
LoadSystemLogs()794 void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() {
795 if (logs_requested_ || !syslogs_provider_)
796 return;
797 logs_requested_ = true;
798 syslogs_task_id_ = syslogs_provider_->RequestSyslogs(
799 false, // compress logs.
800 chromeos::system::SyslogsProvider::SYSLOGS_NETWORK,
801 base::Bind(
802 &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded,
803 base::Unretained(this)),
804 &tracker_);
805 }
806
OnSystemLogsLoaded(chromeos::system::LogDictionaryType * sys_info,std::string * ignored_content)807 void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded(
808 chromeos::system::LogDictionaryType* sys_info,
809 std::string* ignored_content) {
810 DCHECK(!ignored_content);
811 logs_.reset(sys_info);
812 logs_received_ = true;
813 for (std::list<SystemLogRequest>::iterator request_it = requests_.begin();
814 request_it != requests_.end();
815 ++request_it) {
816 SendLogs(*request_it);
817 }
818 requests_.clear();
819 }
820
SendLogs(const SystemLogRequest & request)821 void NetInternalsMessageHandler::SystemLogsGetter::SendLogs(
822 const SystemLogRequest& request) {
823 base::DictionaryValue* result = new base::DictionaryValue();
824 chromeos::system::LogDictionaryType::iterator log_it =
825 logs_->find(request.log_key);
826 if (log_it != logs_->end()) {
827 if (!log_it->second.empty()) {
828 result->SetString("log", log_it->second);
829 } else {
830 result->SetString("log", "<no relevant lines found>");
831 }
832 } else {
833 result->SetString("log", "<invalid log name>");
834 }
835 result->SetString("cellId", request.cell_id);
836
837 handler_->SendJavascriptCommand("getSystemLogCallback", result);
838 }
839 #endif // defined(OS_CHROMEOS)
840
841 ////////////////////////////////////////////////////////////////////////////////
842 //
843 // NetInternalsMessageHandler::IOThreadImpl
844 //
845 ////////////////////////////////////////////////////////////////////////////////
846
IOThreadImpl(const base::WeakPtr<NetInternalsMessageHandler> & handler,IOThread * io_thread,net::URLRequestContextGetter * main_context_getter)847 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
848 const base::WeakPtr<NetInternalsMessageHandler>& handler,
849 IOThread* io_thread,
850 net::URLRequestContextGetter* main_context_getter)
851 : handler_(handler),
852 io_thread_(io_thread),
853 main_context_getter_(main_context_getter),
854 was_webui_deleted_(false) {
855 DCHECK_CURRENTLY_ON(BrowserThread::UI);
856 AddRequestContextGetter(main_context_getter);
857 }
858
~IOThreadImpl()859 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
860 DCHECK_CURRENTLY_ON(BrowserThread::UI);
861 }
862
AddRequestContextGetter(net::URLRequestContextGetter * context_getter)863 void NetInternalsMessageHandler::IOThreadImpl::AddRequestContextGetter(
864 net::URLRequestContextGetter* context_getter) {
865 DCHECK_CURRENTLY_ON(BrowserThread::UI);
866 context_getters_.push_back(context_getter);
867 }
868
CallbackHelper(MessageHandler method,scoped_refptr<IOThreadImpl> io_thread,const base::ListValue * list)869 void NetInternalsMessageHandler::IOThreadImpl::CallbackHelper(
870 MessageHandler method,
871 scoped_refptr<IOThreadImpl> io_thread,
872 const base::ListValue* list) {
873 DCHECK_CURRENTLY_ON(BrowserThread::UI);
874
875 // We need to make a copy of the value in order to pass it over to the IO
876 // thread. |list_copy| will be deleted when the task is destroyed. The called
877 // |method| cannot take ownership of |list_copy|.
878 base::ListValue* list_copy =
879 (list && list->GetSize()) ? list->DeepCopy() : NULL;
880
881 BrowserThread::PostTask(
882 BrowserThread::IO, FROM_HERE,
883 base::Bind(method, io_thread, base::Owned(list_copy)));
884 }
885
Detach()886 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
887 DCHECK_CURRENTLY_ON(BrowserThread::IO);
888 // Unregister with network stack to observe events.
889 if (net_log())
890 net_log()->RemoveThreadSafeObserver(this);
891
892 // Cancel any in-progress connection tests.
893 connection_tester_.reset();
894 }
895
OnWebUIDeleted()896 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
897 DCHECK_CURRENTLY_ON(BrowserThread::UI);
898 was_webui_deleted_ = true;
899 }
900
OnRendererReady(const base::ListValue * list)901 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
902 const base::ListValue* list) {
903 DCHECK_CURRENTLY_ON(BrowserThread::IO);
904
905 // If we have any pending entries, go ahead and get rid of them, so they won't
906 // appear before the REQUEST_ALIVE events we add for currently active
907 // URLRequests.
908 PostPendingEntries();
909
910 SendJavascriptCommand("receivedConstants", NetInternalsUI::GetConstants());
911
912 // Add entries for ongoing URL requests.
913 PrePopulateEventList();
914
915 if (!net_log()) {
916 // Register with network stack to observe events.
917 io_thread_->net_log()->AddThreadSafeObserver(this,
918 net::NetLog::LOG_ALL_BUT_BYTES);
919 }
920 }
921
OnGetProxySettings(const base::ListValue * list)922 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
923 const base::ListValue* list) {
924 DCHECK(!list);
925 net::ProxyService* proxy_service = GetMainContext()->proxy_service();
926
927 base::DictionaryValue* dict = new base::DictionaryValue();
928 if (proxy_service->fetched_config().is_valid())
929 dict->Set("original", proxy_service->fetched_config().ToValue());
930 if (proxy_service->config().is_valid())
931 dict->Set("effective", proxy_service->config().ToValue());
932
933 SendJavascriptCommand("receivedProxySettings", dict);
934 }
935
OnReloadProxySettings(const base::ListValue * list)936 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
937 const base::ListValue* list) {
938 DCHECK(!list);
939 GetMainContext()->proxy_service()->ForceReloadProxyConfig();
940
941 // Cause the renderer to be notified of the new values.
942 OnGetProxySettings(NULL);
943 }
944
OnGetBadProxies(const base::ListValue * list)945 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
946 const base::ListValue* list) {
947 DCHECK(!list);
948
949 const net::ProxyRetryInfoMap& bad_proxies_map =
950 GetMainContext()->proxy_service()->proxy_retry_info();
951
952 base::ListValue* dict_list = new base::ListValue();
953
954 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
955 it != bad_proxies_map.end(); ++it) {
956 const std::string& proxy_uri = it->first;
957 const net::ProxyRetryInfo& retry_info = it->second;
958
959 base::DictionaryValue* dict = new base::DictionaryValue();
960 dict->SetString("proxy_uri", proxy_uri);
961 dict->SetString("bad_until",
962 net::NetLog::TickCountToString(retry_info.bad_until));
963
964 dict_list->Append(dict);
965 }
966
967 SendJavascriptCommand("receivedBadProxies", dict_list);
968 }
969
OnClearBadProxies(const base::ListValue * list)970 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
971 const base::ListValue* list) {
972 DCHECK(!list);
973 GetMainContext()->proxy_service()->ClearBadProxiesCache();
974
975 // Cause the renderer to be notified of the new values.
976 OnGetBadProxies(NULL);
977 }
978
OnGetHostResolverInfo(const base::ListValue * list)979 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
980 const base::ListValue* list) {
981 DCHECK(!list);
982 net::URLRequestContext* context = GetMainContext();
983 net::HostCache* cache = GetHostResolverCache(context);
984
985 if (!cache) {
986 SendJavascriptCommand("receivedHostResolverInfo", NULL);
987 return;
988 }
989
990 base::DictionaryValue* dict = new base::DictionaryValue();
991
992 base::Value* dns_config = context->host_resolver()->GetDnsConfigAsValue();
993 if (dns_config)
994 dict->Set("dns_config", dns_config);
995
996 dict->SetInteger(
997 "default_address_family",
998 static_cast<int>(context->host_resolver()->GetDefaultAddressFamily()));
999
1000 base::DictionaryValue* cache_info_dict = new base::DictionaryValue();
1001
1002 cache_info_dict->SetInteger(
1003 "capacity",
1004 static_cast<int>(cache->max_entries()));
1005
1006 base::ListValue* entry_list = new base::ListValue();
1007
1008 net::HostCache::EntryMap::Iterator it(cache->entries());
1009 for (; it.HasNext(); it.Advance()) {
1010 const net::HostCache::Key& key = it.key();
1011 const net::HostCache::Entry& entry = it.value();
1012
1013 base::DictionaryValue* entry_dict = new base::DictionaryValue();
1014
1015 entry_dict->SetString("hostname", key.hostname);
1016 entry_dict->SetInteger("address_family",
1017 static_cast<int>(key.address_family));
1018 entry_dict->SetString("expiration",
1019 net::NetLog::TickCountToString(it.expiration()));
1020
1021 if (entry.error != net::OK) {
1022 entry_dict->SetInteger("error", entry.error);
1023 } else {
1024 // Append all of the resolved addresses.
1025 base::ListValue* address_list = new base::ListValue();
1026 for (size_t i = 0; i < entry.addrlist.size(); ++i) {
1027 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort());
1028 }
1029 entry_dict->Set("addresses", address_list);
1030 }
1031
1032 entry_list->Append(entry_dict);
1033 }
1034
1035 cache_info_dict->Set("entries", entry_list);
1036 dict->Set("cache", cache_info_dict);
1037
1038 SendJavascriptCommand("receivedHostResolverInfo", dict);
1039 }
1040
OnClearHostResolverCache(const base::ListValue * list)1041 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1042 const base::ListValue* list) {
1043 DCHECK(!list);
1044 net::HostCache* cache = GetHostResolverCache(GetMainContext());
1045
1046 if (cache)
1047 cache->clear();
1048
1049 // Cause the renderer to be notified of the new values.
1050 OnGetHostResolverInfo(NULL);
1051 }
1052
OnEnableIPv6(const base::ListValue * list)1053 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1054 const base::ListValue* list) {
1055 DCHECK(!list);
1056 net::HostResolver* host_resolver = GetMainContext()->host_resolver();
1057
1058 host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_UNSPECIFIED);
1059
1060 // Cause the renderer to be notified of the new value.
1061 OnGetHostResolverInfo(NULL);
1062 }
1063
OnStartConnectionTests(const base::ListValue * list)1064 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
1065 const base::ListValue* list) {
1066 // |value| should be: [<URL to test>].
1067 base::string16 url_str;
1068 CHECK(list->GetString(0, &url_str));
1069
1070 // Try to fix-up the user provided URL into something valid.
1071 // For example, turn "www.google.com" into "http://www.google.com".
1072 GURL url(url_fixer::FixupURL(base::UTF16ToUTF8(url_str), std::string()));
1073
1074 connection_tester_.reset(new ConnectionTester(
1075 this,
1076 io_thread_->globals()->proxy_script_fetcher_context.get(),
1077 net_log()));
1078 connection_tester_->RunAllTests(url);
1079 }
1080
OnHSTSQuery(const base::ListValue * list)1081 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1082 const base::ListValue* list) {
1083 // |list| should be: [<domain to query>].
1084 std::string domain;
1085 CHECK(list->GetString(0, &domain));
1086 base::DictionaryValue* result = new base::DictionaryValue();
1087
1088 if (!base::IsStringASCII(domain)) {
1089 result->SetString("error", "non-ASCII domain name");
1090 } else {
1091 net::TransportSecurityState* transport_security_state =
1092 GetMainContext()->transport_security_state();
1093 if (!transport_security_state) {
1094 result->SetString("error", "no TransportSecurityState active");
1095 } else {
1096 net::TransportSecurityState::DomainState static_state;
1097 const bool found_static = transport_security_state->GetStaticDomainState(
1098 domain, &static_state);
1099 if (found_static) {
1100 result->SetBoolean("has_static_sts",
1101 found_static && static_state.ShouldUpgradeToSSL());
1102 result->SetInteger("static_upgrade_mode",
1103 static_cast<int>(static_state.sts.upgrade_mode));
1104 result->SetBoolean("static_sts_include_subdomains",
1105 static_state.sts.include_subdomains);
1106 result->SetDouble("static_sts_observed",
1107 static_state.sts.last_observed.ToDoubleT());
1108 result->SetDouble("static_sts_expiry",
1109 static_state.sts.expiry.ToDoubleT());
1110 result->SetBoolean("has_static_pkp",
1111 found_static && static_state.HasPublicKeyPins());
1112 result->SetBoolean("static_pkp_include_subdomains",
1113 static_state.pkp.include_subdomains);
1114 result->SetDouble("static_pkp_observed",
1115 static_state.pkp.last_observed.ToDoubleT());
1116 result->SetDouble("static_pkp_expiry",
1117 static_state.pkp.expiry.ToDoubleT());
1118 result->SetString("static_spki_hashes",
1119 HashesToBase64String(static_state.pkp.spki_hashes));
1120 }
1121
1122 net::TransportSecurityState::DomainState dynamic_state;
1123 const bool found_dynamic =
1124 transport_security_state->GetDynamicDomainState(domain,
1125 &dynamic_state);
1126 if (found_dynamic) {
1127 result->SetInteger("dynamic_upgrade_mode",
1128 static_cast<int>(dynamic_state.sts.upgrade_mode));
1129 result->SetBoolean("dynamic_sts_include_subdomains",
1130 dynamic_state.sts.include_subdomains);
1131 result->SetBoolean("dynamic_pkp_include_subdomains",
1132 dynamic_state.pkp.include_subdomains);
1133 result->SetDouble("dynamic_sts_observed",
1134 dynamic_state.sts.last_observed.ToDoubleT());
1135 result->SetDouble("dynamic_pkp_observed",
1136 dynamic_state.pkp.last_observed.ToDoubleT());
1137 result->SetDouble("dynamic_sts_expiry",
1138 dynamic_state.sts.expiry.ToDoubleT());
1139 result->SetDouble("dynamic_pkp_expiry",
1140 dynamic_state.pkp.expiry.ToDoubleT());
1141 result->SetString("dynamic_spki_hashes",
1142 HashesToBase64String(dynamic_state.pkp.spki_hashes));
1143 }
1144
1145 result->SetBoolean("result", found_static || found_dynamic);
1146 if (found_static) {
1147 result->SetString("domain", static_state.domain);
1148 } else if (found_dynamic) {
1149 result->SetString("domain", dynamic_state.domain);
1150 } else {
1151 result->SetString("domain", domain);
1152 }
1153 }
1154 }
1155
1156 SendJavascriptCommand("receivedHSTSResult", result);
1157 }
1158
OnHSTSAdd(const base::ListValue * list)1159 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
1160 const base::ListValue* list) {
1161 // |list| should be: [<domain to query>, <STS include subdomains>, <PKP
1162 // include subdomains>, <key pins>].
1163 std::string domain;
1164 CHECK(list->GetString(0, &domain));
1165 if (!base::IsStringASCII(domain)) {
1166 // Silently fail. The user will get a helpful error if they query for the
1167 // name.
1168 return;
1169 }
1170 bool sts_include_subdomains;
1171 CHECK(list->GetBoolean(1, &sts_include_subdomains));
1172 bool pkp_include_subdomains;
1173 CHECK(list->GetBoolean(2, &pkp_include_subdomains));
1174 std::string hashes_str;
1175 CHECK(list->GetString(3, &hashes_str));
1176
1177 net::TransportSecurityState* transport_security_state =
1178 GetMainContext()->transport_security_state();
1179 if (!transport_security_state)
1180 return;
1181
1182 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
1183 net::HashValueVector hashes;
1184 if (!hashes_str.empty()) {
1185 if (!Base64StringToHashes(hashes_str, &hashes))
1186 return;
1187 }
1188
1189 transport_security_state->AddHSTS(domain, expiry, sts_include_subdomains);
1190 transport_security_state->AddHPKP(domain, expiry, pkp_include_subdomains,
1191 hashes);
1192 }
1193
OnHSTSDelete(const base::ListValue * list)1194 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1195 const base::ListValue* list) {
1196 // |list| should be: [<domain to query>].
1197 std::string domain;
1198 CHECK(list->GetString(0, &domain));
1199 if (!base::IsStringASCII(domain)) {
1200 // There cannot be a unicode entry in the HSTS set.
1201 return;
1202 }
1203 net::TransportSecurityState* transport_security_state =
1204 GetMainContext()->transport_security_state();
1205 if (!transport_security_state)
1206 return;
1207
1208 transport_security_state->DeleteDynamicDataForHost(domain);
1209 }
1210
OnGetHttpCacheInfo(const base::ListValue * list)1211 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1212 const base::ListValue* list) {
1213 DCHECK(!list);
1214 base::DictionaryValue* info_dict = new base::DictionaryValue();
1215 base::DictionaryValue* stats_dict = new base::DictionaryValue();
1216
1217 disk_cache::Backend* disk_cache = GetDiskCacheBackend(GetMainContext());
1218
1219 if (disk_cache) {
1220 // Extract the statistics key/value pairs from the backend.
1221 base::StringPairs stats;
1222 disk_cache->GetStats(&stats);
1223 for (size_t i = 0; i < stats.size(); ++i) {
1224 stats_dict->SetStringWithoutPathExpansion(
1225 stats[i].first, stats[i].second);
1226 }
1227 }
1228
1229 info_dict->Set("stats", stats_dict);
1230
1231 SendJavascriptCommand("receivedHttpCacheInfo", info_dict);
1232 }
1233
OnGetSocketPoolInfo(const base::ListValue * list)1234 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1235 const base::ListValue* list) {
1236 DCHECK(!list);
1237 net::HttpNetworkSession* http_network_session =
1238 GetHttpNetworkSession(GetMainContext());
1239
1240 base::Value* socket_pool_info = NULL;
1241 if (http_network_session)
1242 socket_pool_info = http_network_session->SocketPoolInfoToValue();
1243
1244 SendJavascriptCommand("receivedSocketPoolInfo", socket_pool_info);
1245 }
1246
OnGetSessionNetworkStats(const base::ListValue * list)1247 void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats(
1248 const base::ListValue* list) {
1249 DCHECK(!list);
1250 net::HttpNetworkSession* http_network_session =
1251 GetHttpNetworkSession(main_context_getter_->GetURLRequestContext());
1252
1253 base::Value* network_info = NULL;
1254 if (http_network_session) {
1255 ChromeNetworkDelegate* net_delegate =
1256 static_cast<ChromeNetworkDelegate*>(
1257 http_network_session->network_delegate());
1258 if (net_delegate) {
1259 network_info = net_delegate->SessionNetworkStatsInfoToValue();
1260 }
1261 }
1262 SendJavascriptCommand("receivedSessionNetworkStats", network_info);
1263 }
1264
OnFlushSocketPools(const base::ListValue * list)1265 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1266 const base::ListValue* list) {
1267 DCHECK(!list);
1268 net::HttpNetworkSession* http_network_session =
1269 GetHttpNetworkSession(GetMainContext());
1270
1271 if (http_network_session)
1272 http_network_session->CloseAllConnections();
1273 }
1274
OnCloseIdleSockets(const base::ListValue * list)1275 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1276 const base::ListValue* list) {
1277 DCHECK(!list);
1278 net::HttpNetworkSession* http_network_session =
1279 GetHttpNetworkSession(GetMainContext());
1280
1281 if (http_network_session)
1282 http_network_session->CloseIdleConnections();
1283 }
1284
OnGetSpdySessionInfo(const base::ListValue * list)1285 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1286 const base::ListValue* list) {
1287 DCHECK(!list);
1288 net::HttpNetworkSession* http_network_session =
1289 GetHttpNetworkSession(GetMainContext());
1290
1291 base::Value* spdy_info = http_network_session ?
1292 http_network_session->SpdySessionPoolInfoToValue() : NULL;
1293 SendJavascriptCommand("receivedSpdySessionInfo", spdy_info);
1294 }
1295
OnGetSpdyStatus(const base::ListValue * list)1296 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1297 const base::ListValue* list) {
1298 DCHECK(!list);
1299 base::DictionaryValue* status_dict = new base::DictionaryValue();
1300
1301 net::HttpNetworkSession* http_network_session =
1302 GetHttpNetworkSession(GetMainContext());
1303
1304 status_dict->SetBoolean("spdy_enabled",
1305 net::HttpStreamFactory::spdy_enabled());
1306 status_dict->SetBoolean(
1307 "use_alternate_protocols",
1308 http_network_session->params().use_alternate_protocols);
1309 status_dict->SetBoolean("force_spdy_over_ssl",
1310 http_network_session->params().force_spdy_over_ssl);
1311 status_dict->SetBoolean("force_spdy_always",
1312 http_network_session->params().force_spdy_always);
1313
1314 std::vector<std::string> next_protos;
1315 http_network_session->GetNextProtos(&next_protos);
1316 std::string next_protos_string = JoinString(next_protos, ',');
1317 status_dict->SetString("next_protos", next_protos_string);
1318
1319 SendJavascriptCommand("receivedSpdyStatus", status_dict);
1320 }
1321
1322 void
OnGetSpdyAlternateProtocolMappings(const base::ListValue * list)1323 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1324 const base::ListValue* list) {
1325 DCHECK(!list);
1326 base::ListValue* dict_list = new base::ListValue();
1327
1328 const net::HttpServerProperties& http_server_properties =
1329 *GetMainContext()->http_server_properties();
1330
1331 const net::AlternateProtocolMap& map =
1332 http_server_properties.alternate_protocol_map();
1333
1334 for (net::AlternateProtocolMap::const_iterator it = map.begin();
1335 it != map.end(); ++it) {
1336 base::DictionaryValue* dict = new base::DictionaryValue();
1337 dict->SetString("host_port_pair", it->first.ToString());
1338 dict->SetString("alternate_protocol", it->second.ToString());
1339 dict_list->Append(dict);
1340 }
1341
1342 SendJavascriptCommand("receivedSpdyAlternateProtocolMappings", dict_list);
1343 }
1344
OnGetQuicInfo(const base::ListValue * list)1345 void NetInternalsMessageHandler::IOThreadImpl::OnGetQuicInfo(
1346 const base::ListValue* list) {
1347 DCHECK(!list);
1348 net::HttpNetworkSession* http_network_session =
1349 GetHttpNetworkSession(GetMainContext());
1350
1351 base::Value* quic_info = http_network_session ?
1352 http_network_session->QuicInfoToValue() : NULL;
1353 SendJavascriptCommand("receivedQuicInfo", quic_info);
1354 }
1355
1356 #if defined(OS_WIN)
OnGetServiceProviders(const base::ListValue * list)1357 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1358 const base::ListValue* list) {
1359 DCHECK(!list);
1360
1361 base::DictionaryValue* service_providers = new base::DictionaryValue();
1362
1363 WinsockLayeredServiceProviderList layered_providers;
1364 GetWinsockLayeredServiceProviders(&layered_providers);
1365 base::ListValue* layered_provider_list = new base::ListValue();
1366 for (size_t i = 0; i < layered_providers.size(); ++i) {
1367 base::DictionaryValue* service_dict = new base::DictionaryValue();
1368 service_dict->SetString("name", layered_providers[i].name);
1369 service_dict->SetInteger("version", layered_providers[i].version);
1370 service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
1371 service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
1372 service_dict->SetInteger("socket_protocol",
1373 layered_providers[i].socket_protocol);
1374 service_dict->SetString("path", layered_providers[i].path);
1375
1376 layered_provider_list->Append(service_dict);
1377 }
1378 service_providers->Set("service_providers", layered_provider_list);
1379
1380 WinsockNamespaceProviderList namespace_providers;
1381 GetWinsockNamespaceProviders(&namespace_providers);
1382 base::ListValue* namespace_list = new base::ListValue;
1383 for (size_t i = 0; i < namespace_providers.size(); ++i) {
1384 base::DictionaryValue* namespace_dict = new base::DictionaryValue();
1385 namespace_dict->SetString("name", namespace_providers[i].name);
1386 namespace_dict->SetBoolean("active", namespace_providers[i].active);
1387 namespace_dict->SetInteger("version", namespace_providers[i].version);
1388 namespace_dict->SetInteger("type", namespace_providers[i].type);
1389
1390 namespace_list->Append(namespace_dict);
1391 }
1392 service_providers->Set("namespace_providers", namespace_list);
1393
1394 SendJavascriptCommand("receivedServiceProviders", service_providers);
1395 }
1396 #endif
1397
1398 #if defined(OS_CHROMEOS)
OnRefreshSystemLogs(const base::ListValue * list)1399 void NetInternalsMessageHandler::OnRefreshSystemLogs(
1400 const base::ListValue* list) {
1401 DCHECK(!list);
1402 DCHECK(syslogs_getter_.get());
1403 syslogs_getter_->DeleteSystemLogs();
1404 syslogs_getter_->LoadSystemLogs();
1405 }
1406
OnGetSystemLog(const base::ListValue * list)1407 void NetInternalsMessageHandler::OnGetSystemLog(
1408 const base::ListValue* list) {
1409 DCHECK(syslogs_getter_.get());
1410 syslogs_getter_->RequestSystemLog(list);
1411 }
1412
ImportONCFileToNSSDB(const std::string & onc_blob,const std::string & passcode,net::NSSCertDatabase * nssdb)1413 void NetInternalsMessageHandler::ImportONCFileToNSSDB(
1414 const std::string& onc_blob,
1415 const std::string& passcode,
1416 net::NSSCertDatabase* nssdb) {
1417 user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(
1418 Profile::FromWebUI(web_ui()));
1419
1420 if (!user) {
1421 std::string error = "User not found.";
1422 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1423 return;
1424 }
1425
1426 std::string error;
1427 onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
1428 base::ListValue network_configs;
1429 base::DictionaryValue global_network_config;
1430 base::ListValue certificates;
1431 if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
1432 onc_source,
1433 passcode,
1434 &network_configs,
1435 &global_network_config,
1436 &certificates)) {
1437 error = "Errors occurred during the ONC parsing. ";
1438 }
1439
1440 std::string network_error;
1441 chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
1442 if (!network_error.empty())
1443 error += network_error;
1444
1445 chromeos::onc::CertificateImporterImpl cert_importer(
1446 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), nssdb);
1447 cert_importer.ImportCertificates(
1448 certificates,
1449 onc_source,
1450 base::Bind(&NetInternalsMessageHandler::OnCertificatesImported,
1451 AsWeakPtr(),
1452 error));
1453 }
1454
OnCertificatesImported(const std::string & previous_error,bool success,const net::CertificateList &)1455 void NetInternalsMessageHandler::OnCertificatesImported(
1456 const std::string& previous_error,
1457 bool success,
1458 const net::CertificateList& /* unused onc_trusted_certificates */) {
1459 std::string error = previous_error;
1460 if (!success)
1461 error += "Some certificates couldn't be imported. ";
1462
1463 SendJavascriptCommand("receivedONCFileParse", new base::StringValue(error));
1464 }
1465
OnImportONCFile(const base::ListValue * list)1466 void NetInternalsMessageHandler::OnImportONCFile(
1467 const base::ListValue* list) {
1468 std::string onc_blob;
1469 std::string passcode;
1470 if (list->GetSize() != 2 ||
1471 !list->GetString(0, &onc_blob) ||
1472 !list->GetString(1, &passcode)) {
1473 NOTREACHED();
1474 }
1475
1476 GetNSSCertDatabaseForProfile(
1477 Profile::FromWebUI(web_ui()),
1478 base::Bind(&NetInternalsMessageHandler::ImportONCFileToNSSDB, AsWeakPtr(),
1479 onc_blob, passcode));
1480 }
1481
OnStoreDebugLogs(const base::ListValue * list)1482 void NetInternalsMessageHandler::OnStoreDebugLogs(const base::ListValue* list) {
1483 DCHECK(list);
1484
1485 SendJavascriptCommand("receivedStoreDebugLogs",
1486 new base::StringValue("Creating log file..."));
1487 Profile* profile = Profile::FromWebUI(web_ui());
1488 const DownloadPrefs* const prefs = DownloadPrefs::FromBrowserContext(profile);
1489 base::FilePath path = prefs->DownloadPath();
1490 if (file_manager::util::IsUnderNonNativeLocalPath(profile, path))
1491 path = prefs->GetDefaultDownloadDirectoryForProfile();
1492 chromeos::DebugLogWriter::StoreLogs(
1493 path,
1494 true, // should_compress
1495 base::Bind(&NetInternalsMessageHandler::OnStoreDebugLogsCompleted,
1496 AsWeakPtr()));
1497 }
1498
OnStoreDebugLogsCompleted(const base::FilePath & log_path,bool succeeded)1499 void NetInternalsMessageHandler::OnStoreDebugLogsCompleted(
1500 const base::FilePath& log_path, bool succeeded) {
1501 std::string status;
1502 if (succeeded)
1503 status = "Created log file: " + log_path.BaseName().AsUTF8Unsafe();
1504 else
1505 status = "Failed to create log file";
1506 SendJavascriptCommand("receivedStoreDebugLogs",
1507 new base::StringValue(status));
1508 }
1509
OnSetNetworkDebugMode(const base::ListValue * list)1510 void NetInternalsMessageHandler::OnSetNetworkDebugMode(
1511 const base::ListValue* list) {
1512 std::string subsystem;
1513 if (list->GetSize() != 1 || !list->GetString(0, &subsystem))
1514 NOTREACHED();
1515 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
1516 SetDebugMode(
1517 subsystem,
1518 base::Bind(
1519 &NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted,
1520 AsWeakPtr(),
1521 subsystem));
1522 }
1523
OnSetNetworkDebugModeCompleted(const std::string & subsystem,bool succeeded)1524 void NetInternalsMessageHandler::OnSetNetworkDebugModeCompleted(
1525 const std::string& subsystem,
1526 bool succeeded) {
1527 std::string status;
1528 if (succeeded)
1529 status = "Debug mode is changed to " + subsystem;
1530 else
1531 status = "Failed to change debug mode to " + subsystem;
1532 SendJavascriptCommand("receivedSetNetworkDebugMode",
1533 new base::StringValue(status));
1534 }
1535 #endif // defined(OS_CHROMEOS)
1536
OnSetLogLevel(const base::ListValue * list)1537 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1538 const base::ListValue* list) {
1539 int log_level;
1540 std::string log_level_string;
1541 if (!list->GetString(0, &log_level_string) ||
1542 !base::StringToInt(log_level_string, &log_level)) {
1543 NOTREACHED();
1544 return;
1545 }
1546
1547 DCHECK_GE(log_level, net::NetLog::LOG_ALL);
1548 DCHECK_LT(log_level, net::NetLog::LOG_NONE);
1549 net_log()->SetObserverLogLevel(
1550 this, static_cast<net::NetLog::LogLevel>(log_level));
1551 }
1552
1553 // Note that unlike other methods of IOThreadImpl, this function
1554 // can be called from ANY THREAD.
OnAddEntry(const net::NetLog::Entry & entry)1555 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1556 const net::NetLog::Entry& entry) {
1557 BrowserThread::PostTask(
1558 BrowserThread::IO, FROM_HERE,
1559 base::Bind(&IOThreadImpl::AddEntryToQueue, this, entry.ToValue()));
1560 }
1561
OnStartConnectionTestSuite()1562 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1563 SendJavascriptCommand("receivedStartConnectionTestSuite", NULL);
1564 }
1565
OnStartConnectionTestExperiment(const ConnectionTester::Experiment & experiment)1566 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1567 const ConnectionTester::Experiment& experiment) {
1568 SendJavascriptCommand(
1569 "receivedStartConnectionTestExperiment",
1570 ExperimentToValue(experiment));
1571 }
1572
1573 void
OnCompletedConnectionTestExperiment(const ConnectionTester::Experiment & experiment,int result)1574 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1575 const ConnectionTester::Experiment& experiment,
1576 int result) {
1577 base::DictionaryValue* dict = new base::DictionaryValue();
1578
1579 dict->Set("experiment", ExperimentToValue(experiment));
1580 dict->SetInteger("result", result);
1581
1582 SendJavascriptCommand(
1583 "receivedCompletedConnectionTestExperiment",
1584 dict);
1585 }
1586
1587 void
OnCompletedConnectionTestSuite()1588 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1589 SendJavascriptCommand(
1590 "receivedCompletedConnectionTestSuite",
1591 NULL);
1592 }
1593
1594 // Note that this can be called from ANY THREAD.
SendJavascriptCommand(const std::string & command,base::Value * arg)1595 void NetInternalsMessageHandler::IOThreadImpl::SendJavascriptCommand(
1596 const std::string& command,
1597 base::Value* arg) {
1598 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1599 if (handler_.get() && !was_webui_deleted_) {
1600 // We check |handler_| in case it was deleted on the UI thread earlier
1601 // while we were running on the IO thread.
1602 handler_->SendJavascriptCommand(command, arg);
1603 } else {
1604 delete arg;
1605 }
1606 return;
1607 }
1608
1609 if (!BrowserThread::PostTask(
1610 BrowserThread::UI, FROM_HERE,
1611 base::Bind(&IOThreadImpl::SendJavascriptCommand, this, command, arg))) {
1612 // Failed posting the task, avoid leaking.
1613 delete arg;
1614 }
1615 }
1616
AddEntryToQueue(base::Value * entry)1617 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(
1618 base::Value* entry) {
1619 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1620 if (!pending_entries_.get()) {
1621 pending_entries_.reset(new base::ListValue());
1622 BrowserThread::PostDelayedTask(
1623 BrowserThread::IO, FROM_HERE,
1624 base::Bind(&IOThreadImpl::PostPendingEntries, this),
1625 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds));
1626 }
1627 pending_entries_->Append(entry);
1628 }
1629
PostPendingEntries()1630 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1631 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1632 if (pending_entries_.get())
1633 SendJavascriptCommand("receivedLogEntries", pending_entries_.release());
1634 }
1635
PrePopulateEventList()1636 void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() {
1637 // Use a set to prevent duplicates.
1638 std::set<net::URLRequestContext*> contexts;
1639 for (ContextGetterList::const_iterator getter = context_getters_.begin();
1640 getter != context_getters_.end(); ++getter) {
1641 contexts.insert((*getter)->GetURLRequestContext());
1642 }
1643 contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get());
1644 contexts.insert(io_thread_->globals()->system_request_context.get());
1645
1646 // Put together the list of all requests.
1647 std::vector<const net::URLRequest*> requests;
1648 for (std::set<net::URLRequestContext*>::const_iterator context =
1649 contexts.begin();
1650 context != contexts.end(); ++context) {
1651 std::set<const net::URLRequest*>* context_requests =
1652 (*context)->url_requests();
1653 for (std::set<const net::URLRequest*>::const_iterator request_it =
1654 context_requests->begin();
1655 request_it != context_requests->end(); ++request_it) {
1656 DCHECK_EQ(io_thread_->net_log(), (*request_it)->net_log().net_log());
1657 requests.push_back(*request_it);
1658 }
1659 }
1660
1661 // Sort by creation time.
1662 std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
1663
1664 // Create fake events.
1665 for (std::vector<const net::URLRequest*>::const_iterator request_it =
1666 requests.begin();
1667 request_it != requests.end(); ++request_it) {
1668 const net::URLRequest* request = *request_it;
1669 net::NetLog::ParametersCallback callback =
1670 base::Bind(&GetRequestStateAsValue, base::Unretained(request));
1671
1672 // Create and add the entry directly, to avoid sending it to any other
1673 // NetLog observers.
1674 net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE,
1675 request->net_log().source(),
1676 net::NetLog::PHASE_BEGIN,
1677 request->creation_time(),
1678 &callback);
1679 net::NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel());
1680
1681 // Have to add |entry| to the queue synchronously, as there may already
1682 // be posted tasks queued up to add other events for |request|, which we
1683 // want |entry| to precede.
1684 AddEntryToQueue(entry.ToValue());
1685 }
1686 }
1687
1688 } // namespace
1689
1690
1691 ////////////////////////////////////////////////////////////////////////////////
1692 //
1693 // NetInternalsUI
1694 //
1695 ////////////////////////////////////////////////////////////////////////////////
1696
1697 // static
GetConstants()1698 base::Value* NetInternalsUI::GetConstants() {
1699 base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
1700 DCHECK(constants_dict);
1701
1702 // Add a dictionary with the version of the client and its command line
1703 // arguments.
1704 {
1705 base::DictionaryValue* dict = new base::DictionaryValue();
1706
1707 chrome::VersionInfo version_info;
1708
1709 if (!version_info.is_valid()) {
1710 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
1711 } else {
1712 // We have everything we need to send the right values.
1713 dict->SetString("name", version_info.Name());
1714 dict->SetString("version", version_info.Version());
1715 dict->SetString("cl", version_info.LastChange());
1716 dict->SetString("version_mod",
1717 chrome::VersionInfo::GetVersionStringModifier());
1718 dict->SetString("official",
1719 version_info.IsOfficialBuild() ? "official" :
1720 "unofficial");
1721 dict->SetString("os_type", version_info.OSType());
1722 dict->SetString("command_line",
1723 CommandLine::ForCurrentProcess()->GetCommandLineString());
1724 }
1725
1726 constants_dict->Set("clientInfo", dict);
1727 }
1728
1729 return constants_dict;
1730 }
1731
NetInternalsUI(content::WebUI * web_ui)1732 NetInternalsUI::NetInternalsUI(content::WebUI* web_ui)
1733 : WebUIController(web_ui) {
1734 web_ui->AddMessageHandler(new NetInternalsMessageHandler());
1735
1736 // Set up the chrome://net-internals/ source.
1737 Profile* profile = Profile::FromWebUI(web_ui);
1738 content::WebUIDataSource::Add(profile, CreateNetInternalsHTMLSource());
1739 }
1740