1 // Copyright (c) 2011 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_ui.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/base64.h"
13 #include "base/command_line.h"
14 #include "base/file_util.h"
15 #include "base/memory/singleton.h"
16 #include "base/message_loop.h"
17 #include "base/path_service.h"
18 #include "base/string_number_conversions.h"
19 #include "base/string_piece.h"
20 #include "base/string_split.h"
21 #include "base/string_util.h"
22 #include "base/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/io_thread.h"
26 #include "chrome/browser/net/chrome_net_log.h"
27 #include "chrome/browser/net/connection_tester.h"
28 #include "chrome/browser/net/passive_log_collector.h"
29 #include "chrome/browser/net/url_fixer_upper.h"
30 #include "chrome/browser/platform_util.h"
31 #include "chrome/browser/prefs/pref_member.h"
32 #include "chrome/browser/profiles/profile.h"
33 #include "chrome/browser/ui/shell_dialogs.h"
34 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
35 #include "chrome/common/chrome_paths.h"
36 #include "chrome/common/chrome_version_info.h"
37 #include "chrome/common/jstemplate_builder.h"
38 #include "chrome/common/pref_names.h"
39 #include "chrome/common/url_constants.h"
40 #include "content/browser/browser_thread.h"
41 #include "content/browser/tab_contents/tab_contents.h"
42 #include "content/browser/tab_contents/tab_contents_view.h"
43 #include "content/common/notification_details.h"
44 #include "grit/generated_resources.h"
45 #include "grit/net_internals_resources.h"
46 #include "net/base/escape.h"
47 #include "net/base/host_resolver_impl.h"
48 #include "net/base/net_errors.h"
49 #include "net/base/net_util.h"
50 #include "net/base/sys_addrinfo.h"
51 #include "net/base/x509_cert_types.h"
52 #include "net/disk_cache/disk_cache.h"
53 #include "net/http/http_alternate_protocols.h"
54 #include "net/http/http_cache.h"
55 #include "net/http/http_network_layer.h"
56 #include "net/http/http_network_session.h"
57 #include "net/http/http_stream_factory.h"
58 #include "net/proxy/proxy_service.h"
59 #include "net/url_request/url_request_context.h"
60 #include "net/url_request/url_request_context_getter.h"
61 #include "ui/base/l10n/l10n_util.h"
62 #include "ui/base/resource/resource_bundle.h"
63
64 #ifdef OS_WIN
65 #include "chrome/browser/net/service_providers_win.h"
66 #endif
67
68 namespace {
69
70 // Delay between when an event occurs and when it is passed to the Javascript
71 // page. All events that occur during this period are grouped together and
72 // sent to the page at once, which reduces context switching and CPU usage.
73 const int kNetLogEventDelayMilliseconds = 100;
74
75 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
76 // there is none.
GetHostResolverCache(net::URLRequestContext * context)77 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
78 net::HostResolverImpl* host_resolver_impl =
79 context->host_resolver()->GetAsHostResolverImpl();
80
81 if (!host_resolver_impl)
82 return NULL;
83
84 return host_resolver_impl->cache();
85 }
86
87 // Returns the disk cache backend for |context| if there is one, or NULL.
GetDiskCacheBackend(net::URLRequestContext * context)88 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) {
89 if (!context->http_transaction_factory())
90 return NULL;
91
92 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache();
93 if (!http_cache)
94 return NULL;
95
96 return http_cache->GetCurrentBackend();
97 }
98
99 // Returns the http network session for |context| if there is one.
100 // Otherwise, returns NULL.
GetHttpNetworkSession(net::URLRequestContext * context)101 net::HttpNetworkSession* GetHttpNetworkSession(
102 net::URLRequestContext* context) {
103 if (!context->http_transaction_factory())
104 return NULL;
105
106 return context->http_transaction_factory()->GetSession();
107 }
108
ExperimentToValue(const ConnectionTester::Experiment & experiment)109 Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
110 DictionaryValue* dict = new DictionaryValue();
111
112 if (experiment.url.is_valid())
113 dict->SetString("url", experiment.url.spec());
114
115 dict->SetString("proxy_settings_experiment",
116 ConnectionTester::ProxySettingsExperimentDescription(
117 experiment.proxy_settings_experiment));
118 dict->SetString("host_resolver_experiment",
119 ConnectionTester::HostResolverExperimentDescription(
120 experiment.host_resolver_experiment));
121 return dict;
122 }
123
124 class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource {
125 public:
126 NetInternalsHTMLSource();
127
128 // Called when the network layer has requested a resource underneath
129 // the path we registered.
130 virtual void StartDataRequest(const std::string& path,
131 bool is_incognito,
132 int request_id);
133 virtual std::string GetMimeType(const std::string&) const;
134
135 private:
~NetInternalsHTMLSource()136 ~NetInternalsHTMLSource() {}
137 DISALLOW_COPY_AND_ASSIGN(NetInternalsHTMLSource);
138 };
139
140 // This class receives javascript messages from the renderer.
141 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
142 // this class's methods are expected to run on the UI thread.
143 //
144 // Since the network code we want to run lives on the IO thread, we proxy
145 // almost everything over to NetInternalsMessageHandler::IOThreadImpl, which
146 // runs on the IO thread.
147 //
148 // TODO(eroman): Can we start on the IO thread to begin with?
149 class NetInternalsMessageHandler
150 : public WebUIMessageHandler,
151 public SelectFileDialog::Listener,
152 public base::SupportsWeakPtr<NetInternalsMessageHandler>,
153 public NotificationObserver {
154 public:
155 NetInternalsMessageHandler();
156 virtual ~NetInternalsMessageHandler();
157
158 // WebUIMessageHandler implementation.
159 virtual WebUIMessageHandler* Attach(WebUI* web_ui);
160 virtual void RegisterMessages();
161
162 // Executes the javascript function |function_name| in the renderer, passing
163 // it the argument |value|.
164 void CallJavascriptFunction(const std::wstring& function_name,
165 const Value* value);
166
167 // NotificationObserver implementation.
168 virtual void Observe(NotificationType type,
169 const NotificationSource& source,
170 const NotificationDetails& details);
171
172 // Javascript message handlers.
173 void OnRendererReady(const ListValue* list);
174 void OnEnableHttpThrottling(const ListValue* list);
175
176 // SelectFileDialog::Listener implementation
177 virtual void FileSelected(const FilePath& path, int index, void* params);
178 virtual void FileSelectionCanceled(void* params);
179
180 // The only callback handled on the UI thread. As it needs to access fields
181 // from |web_ui_|, it can't be called on the IO thread.
182 void OnLoadLogFile(const ListValue* list);
183
184 private:
185 class IOThreadImpl;
186
187 // Task run on the FILE thread to read the contents of a log file. The result
188 // is then passed to IOThreadImpl's CallJavascriptFunction, which sends it
189 // back to the web page. IOThreadImpl is used instead of the
190 // NetInternalsMessageHandler directly because it checks if the message
191 // handler has been destroyed in the meantime.
192 class ReadLogFileTask : public Task {
193 public:
194 ReadLogFileTask(IOThreadImpl* proxy, const FilePath& path);
195
196 virtual void Run();
197
198 private:
199 // IOThreadImpl implements existence checks already. Simpler to reused them
200 // then to reimplement them.
201 scoped_refptr<IOThreadImpl> proxy_;
202
203 // Path of the file to open.
204 const FilePath path_;
205 };
206
207 // The pref member about whether HTTP throttling is enabled, which needs to
208 // be accessed on the UI thread.
209 BooleanPrefMember http_throttling_enabled_;
210
211 // OnRendererReady invokes this callback to do the part of message handling
212 // that needs to happen on the IO thread.
213 scoped_ptr<WebUI::MessageCallback> renderer_ready_io_callback_;
214
215 // This is the "real" message handler, which lives on the IO thread.
216 scoped_refptr<IOThreadImpl> proxy_;
217
218 // Used for loading log files.
219 scoped_refptr<SelectFileDialog> select_log_file_dialog_;
220
221 DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
222 };
223
224 // This class is the "real" message handler. It is allocated and destroyed on
225 // the UI thread. With the exception of OnAddEntry, OnWebUIDeleted, and
226 // CallJavascriptFunction, its methods are all expected to be called from the IO
227 // thread. OnAddEntry and CallJavascriptFunction can be called from any thread,
228 // and OnWebUIDeleted can only be called from the UI thread.
229 class NetInternalsMessageHandler::IOThreadImpl
230 : public base::RefCountedThreadSafe<
231 NetInternalsMessageHandler::IOThreadImpl,
232 BrowserThread::DeleteOnUIThread>,
233 public ChromeNetLog::ThreadSafeObserver,
234 public ConnectionTester::Delegate {
235 public:
236 // Type for methods that can be used as MessageHandler callbacks.
237 typedef void (IOThreadImpl::*MessageHandler)(const ListValue*);
238
239 // Creates a proxy for |handler| that will live on the IO thread.
240 // |handler| is a weak pointer, since it is possible for the
241 // WebUIMessageHandler to be deleted on the UI thread while we were executing
242 // on the IO thread. |io_thread| is the global IOThread (it is passed in as
243 // an argument since we need to grab it from the UI thread).
244 IOThreadImpl(
245 const base::WeakPtr<NetInternalsMessageHandler>& handler,
246 IOThread* io_thread,
247 net::URLRequestContextGetter* context_getter);
248
249 // Creates a callback that will run |method| on the IO thread.
250 //
251 // This can be used with WebUI::RegisterMessageCallback() to bind to a method
252 // on the IO thread.
253 WebUI::MessageCallback* CreateCallback(MessageHandler method);
254
255 // Called once the WebUI has been deleted (i.e. renderer went away), on the
256 // IO thread.
257 void Detach();
258
259 // Sends all passive log entries in |passive_entries| to the Javascript
260 // handler, called on the IO thread.
261 void SendPassiveLogEntries(const ChromeNetLog::EntryList& passive_entries);
262
263 // Called when the WebUI is deleted. Prevents calling Javascript functions
264 // afterwards. Called on UI thread.
265 void OnWebUIDeleted();
266
267 //--------------------------------
268 // Javascript message handlers:
269 //--------------------------------
270
271 void OnRendererReady(const ListValue* list);
272
273 void OnGetProxySettings(const ListValue* list);
274 void OnReloadProxySettings(const ListValue* list);
275 void OnGetBadProxies(const ListValue* list);
276 void OnClearBadProxies(const ListValue* list);
277 void OnGetHostResolverInfo(const ListValue* list);
278 void OnClearHostResolverCache(const ListValue* list);
279 void OnEnableIPv6(const ListValue* list);
280 void OnStartConnectionTests(const ListValue* list);
281 void OnHSTSQuery(const ListValue* list);
282 void OnHSTSAdd(const ListValue* list);
283 void OnHSTSDelete(const ListValue* list);
284 void OnGetHttpCacheInfo(const ListValue* list);
285 void OnGetSocketPoolInfo(const ListValue* list);
286 void OnCloseIdleSockets(const ListValue* list);
287 void OnFlushSocketPools(const ListValue* list);
288 void OnGetSpdySessionInfo(const ListValue* list);
289 void OnGetSpdyStatus(const ListValue* list);
290 void OnGetSpdyAlternateProtocolMappings(const ListValue* list);
291 #ifdef OS_WIN
292 void OnGetServiceProviders(const ListValue* list);
293 #endif
294
295 void OnSetLogLevel(const ListValue* list);
296
297 // ChromeNetLog::ThreadSafeObserver implementation:
298 virtual void OnAddEntry(net::NetLog::EventType type,
299 const base::TimeTicks& time,
300 const net::NetLog::Source& source,
301 net::NetLog::EventPhase phase,
302 net::NetLog::EventParameters* params);
303
304 // ConnectionTester::Delegate implementation:
305 virtual void OnStartConnectionTestSuite();
306 virtual void OnStartConnectionTestExperiment(
307 const ConnectionTester::Experiment& experiment);
308 virtual void OnCompletedConnectionTestExperiment(
309 const ConnectionTester::Experiment& experiment,
310 int result);
311 virtual void OnCompletedConnectionTestSuite();
312
313 // Helper that executes |function_name| in the attached renderer.
314 // The function takes ownership of |arg|. Note that this can be called from
315 // any thread.
316 void CallJavascriptFunction(const std::wstring& function_name, Value* arg);
317
318 private:
319 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
320 friend class DeleteTask<IOThreadImpl>;
321
322 ~IOThreadImpl();
323
324 class CallbackHelper;
325
326 // Helper that runs |method| with |arg|, and deletes |arg| on completion.
327 void DispatchToMessageHandler(ListValue* arg, MessageHandler method);
328
329 // Adds |entry| to the queue of pending log entries to be sent to the page via
330 // Javascript. Must be called on the IO Thread. Also creates a delayed task
331 // that will call PostPendingEntries, if there isn't one already.
332 void AddEntryToQueue(Value* entry);
333
334 // Sends all pending entries to the page via Javascript, and clears the list
335 // of pending entries. Sending multiple entries at once results in a
336 // significant reduction of CPU usage when a lot of events are happening.
337 // Must be called on the IO Thread.
338 void PostPendingEntries();
339
340 // Pointer to the UI-thread message handler. Only access this from
341 // the UI thread.
342 base::WeakPtr<NetInternalsMessageHandler> handler_;
343
344 // The global IOThread, which contains the global NetLog to observer.
345 IOThread* io_thread_;
346
347 scoped_refptr<net::URLRequestContextGetter> context_getter_;
348
349 // Helper that runs the suite of connection tests.
350 scoped_ptr<ConnectionTester> connection_tester_;
351
352 // True if the Web UI has been deleted. This is used to prevent calling
353 // Javascript functions after the Web UI is destroyed. On refresh, the
354 // messages can end up being sent to the refreshed page, causing duplicate
355 // or partial entries.
356 //
357 // This is only read and written to on the UI thread.
358 bool was_webui_deleted_;
359
360 // True if we have attached an observer to the NetLog already.
361 bool is_observing_log_;
362
363 // Log entries that have yet to be passed along to Javascript page. Non-NULL
364 // when and only when there is a pending delayed task to call
365 // PostPendingEntries. Read and written to exclusively on the IO Thread.
366 scoped_ptr<ListValue> pending_entries_;
367 };
368
369 // Helper class for a WebUI::MessageCallback which when executed calls
370 // instance->*method(value) on the IO thread.
371 class NetInternalsMessageHandler::IOThreadImpl::CallbackHelper
372 : public WebUI::MessageCallback {
373 public:
CallbackHelper(IOThreadImpl * instance,IOThreadImpl::MessageHandler method)374 CallbackHelper(IOThreadImpl* instance, IOThreadImpl::MessageHandler method)
375 : instance_(instance),
376 method_(method) {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 }
379
RunWithParams(const Tuple1<const ListValue * > & params)380 virtual void RunWithParams(const Tuple1<const ListValue*>& params) {
381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
382
383 // We need to make a copy of the value in order to pass it over to the IO
384 // thread. We will delete this in IOThreadImpl::DispatchMessageHandler().
385 ListValue* list_copy = static_cast<ListValue*>(
386 params.a ? params.a->DeepCopy() : NULL);
387
388 if (!BrowserThread::PostTask(
389 BrowserThread::IO, FROM_HERE,
390 NewRunnableMethod(instance_.get(),
391 &IOThreadImpl::DispatchToMessageHandler,
392 list_copy, method_))) {
393 // Failed posting the task, avoid leaking |list_copy|.
394 delete list_copy;
395 }
396 }
397
398 private:
399 scoped_refptr<IOThreadImpl> instance_;
400 IOThreadImpl::MessageHandler method_;
401 };
402
403 ////////////////////////////////////////////////////////////////////////////////
404 //
405 // NetInternalsHTMLSource
406 //
407 ////////////////////////////////////////////////////////////////////////////////
408
NetInternalsHTMLSource()409 NetInternalsHTMLSource::NetInternalsHTMLSource()
410 : DataSource(chrome::kChromeUINetInternalsHost, MessageLoop::current()) {
411 }
412
StartDataRequest(const std::string & path,bool is_incognito,int request_id)413 void NetInternalsHTMLSource::StartDataRequest(const std::string& path,
414 bool is_incognito,
415 int request_id) {
416 DictionaryValue localized_strings;
417 SetFontAndTextDirection(&localized_strings);
418
419 // The provided "path" may contain a fragment, or query section. We only
420 // care about the path itself, and will disregard anything else.
421 std::string filename =
422 GURL(std::string("chrome://net/") + path).path().substr(1);
423
424 // The source for the net internals page is flattened during compilation, so
425 // the only resource that should legitimately be requested is the main file.
426 // Note that users can type anything into the address bar, though, so we must
427 // handle arbitrary input.
428 if (filename.empty() || filename == "index.html") {
429 base::StringPiece html(
430 ResourceBundle::GetSharedInstance().GetRawDataResource(
431 IDR_NET_INTERNALS_INDEX_HTML));
432 std::string full_html(html.data(), html.size());
433 jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
434 jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
435 jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
436 jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
437
438 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
439 html_bytes->data.resize(full_html.size());
440 std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
441 SendResponse(request_id, html_bytes);
442 return;
443 }
444
445 const std::string data_string("<p style='color:red'>Failed to read resource" +
446 EscapeForHTML(filename) + "</p>");
447 scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes);
448 bytes->data.resize(data_string.size());
449 std::copy(data_string.begin(), data_string.end(), bytes->data.begin());
450 SendResponse(request_id, bytes);
451 }
452
GetMimeType(const std::string &) const453 std::string NetInternalsHTMLSource::GetMimeType(const std::string&) const {
454 return "text/html";
455 }
456
457 ////////////////////////////////////////////////////////////////////////////////
458 //
459 // NetInternalsMessageHandler
460 //
461 ////////////////////////////////////////////////////////////////////////////////
462
NetInternalsMessageHandler()463 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
464
~NetInternalsMessageHandler()465 NetInternalsMessageHandler::~NetInternalsMessageHandler() {
466 if (proxy_) {
467 proxy_.get()->OnWebUIDeleted();
468 // Notify the handler on the IO thread that the renderer is gone.
469 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
470 NewRunnableMethod(proxy_.get(), &IOThreadImpl::Detach));
471 }
472 if (select_log_file_dialog_)
473 select_log_file_dialog_->ListenerDestroyed();
474 }
475
Attach(WebUI * web_ui)476 WebUIMessageHandler* NetInternalsMessageHandler::Attach(WebUI* web_ui) {
477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
478
479 PrefService* pref_service = web_ui->GetProfile()->GetPrefs();
480 http_throttling_enabled_.Init(prefs::kHttpThrottlingEnabled, pref_service,
481 this);
482
483 proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(),
484 web_ui->GetProfile()->GetRequestContext());
485 renderer_ready_io_callback_.reset(
486 proxy_->CreateCallback(&IOThreadImpl::OnRendererReady));
487
488 WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
489 return result;
490 }
491
FileSelected(const FilePath & path,int index,void * params)492 void NetInternalsMessageHandler::FileSelected(
493 const FilePath& path, int index, void* params) {
494 select_log_file_dialog_.release();
495 BrowserThread::PostTask(
496 BrowserThread::FILE, FROM_HERE,
497 new ReadLogFileTask(proxy_.get(), path));
498 }
499
FileSelectionCanceled(void * params)500 void NetInternalsMessageHandler::FileSelectionCanceled(void* params) {
501 select_log_file_dialog_.release();
502 }
503
OnLoadLogFile(const ListValue * list)504 void NetInternalsMessageHandler::OnLoadLogFile(const ListValue* list) {
505 // Only allow a single dialog at a time.
506 if (select_log_file_dialog_.get())
507 return;
508 select_log_file_dialog_ = SelectFileDialog::Create(this);
509 select_log_file_dialog_->SelectFile(
510 SelectFileDialog::SELECT_OPEN_FILE, string16(), FilePath(), NULL, 0,
511 FILE_PATH_LITERAL(""), web_ui_->tab_contents(),
512 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL);
513 }
514
RegisterMessages()515 void NetInternalsMessageHandler::RegisterMessages() {
516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517 // Only callback handled on UI thread.
518 web_ui_->RegisterMessageCallback(
519 "loadLogFile",
520 NewCallback(this, &NetInternalsMessageHandler::OnLoadLogFile));
521
522 web_ui_->RegisterMessageCallback(
523 "notifyReady",
524 NewCallback(this, &NetInternalsMessageHandler::OnRendererReady));
525 web_ui_->RegisterMessageCallback(
526 "getProxySettings",
527 proxy_->CreateCallback(&IOThreadImpl::OnGetProxySettings));
528 web_ui_->RegisterMessageCallback(
529 "reloadProxySettings",
530 proxy_->CreateCallback(&IOThreadImpl::OnReloadProxySettings));
531 web_ui_->RegisterMessageCallback(
532 "getBadProxies",
533 proxy_->CreateCallback(&IOThreadImpl::OnGetBadProxies));
534 web_ui_->RegisterMessageCallback(
535 "clearBadProxies",
536 proxy_->CreateCallback(&IOThreadImpl::OnClearBadProxies));
537 web_ui_->RegisterMessageCallback(
538 "getHostResolverInfo",
539 proxy_->CreateCallback(&IOThreadImpl::OnGetHostResolverInfo));
540 web_ui_->RegisterMessageCallback(
541 "clearHostResolverCache",
542 proxy_->CreateCallback(&IOThreadImpl::OnClearHostResolverCache));
543 web_ui_->RegisterMessageCallback(
544 "enableIPv6",
545 proxy_->CreateCallback(&IOThreadImpl::OnEnableIPv6));
546 web_ui_->RegisterMessageCallback(
547 "startConnectionTests",
548 proxy_->CreateCallback(&IOThreadImpl::OnStartConnectionTests));
549 web_ui_->RegisterMessageCallback(
550 "hstsQuery",
551 proxy_->CreateCallback(&IOThreadImpl::OnHSTSQuery));
552 web_ui_->RegisterMessageCallback(
553 "hstsAdd",
554 proxy_->CreateCallback(&IOThreadImpl::OnHSTSAdd));
555 web_ui_->RegisterMessageCallback(
556 "hstsDelete",
557 proxy_->CreateCallback(&IOThreadImpl::OnHSTSDelete));
558 web_ui_->RegisterMessageCallback(
559 "getHttpCacheInfo",
560 proxy_->CreateCallback(&IOThreadImpl::OnGetHttpCacheInfo));
561 web_ui_->RegisterMessageCallback(
562 "getSocketPoolInfo",
563 proxy_->CreateCallback(&IOThreadImpl::OnGetSocketPoolInfo));
564 web_ui_->RegisterMessageCallback(
565 "closeIdleSockets",
566 proxy_->CreateCallback(&IOThreadImpl::OnCloseIdleSockets));
567 web_ui_->RegisterMessageCallback(
568 "flushSocketPools",
569 proxy_->CreateCallback(&IOThreadImpl::OnFlushSocketPools));
570 web_ui_->RegisterMessageCallback(
571 "getSpdySessionInfo",
572 proxy_->CreateCallback(&IOThreadImpl::OnGetSpdySessionInfo));
573 web_ui_->RegisterMessageCallback(
574 "getSpdyStatus",
575 proxy_->CreateCallback(&IOThreadImpl::OnGetSpdyStatus));
576 web_ui_->RegisterMessageCallback(
577 "getSpdyAlternateProtocolMappings",
578 proxy_->CreateCallback(
579 &IOThreadImpl::OnGetSpdyAlternateProtocolMappings));
580 #ifdef OS_WIN
581 web_ui_->RegisterMessageCallback(
582 "getServiceProviders",
583 proxy_->CreateCallback(&IOThreadImpl::OnGetServiceProviders));
584 #endif
585
586 web_ui_->RegisterMessageCallback(
587 "setLogLevel",
588 proxy_->CreateCallback(&IOThreadImpl::OnSetLogLevel));
589
590 web_ui_->RegisterMessageCallback(
591 "enableHttpThrottling",
592 NewCallback(this, &NetInternalsMessageHandler::OnEnableHttpThrottling));
593 }
594
CallJavascriptFunction(const std::wstring & function_name,const Value * value)595 void NetInternalsMessageHandler::CallJavascriptFunction(
596 const std::wstring& function_name,
597 const Value* value) {
598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
599 if (value) {
600 web_ui_->CallJavascriptFunction(WideToASCII(function_name), *value);
601 } else {
602 web_ui_->CallJavascriptFunction(WideToASCII(function_name));
603 }
604 }
605
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)606 void NetInternalsMessageHandler::Observe(NotificationType type,
607 const NotificationSource& source,
608 const NotificationDetails& details) {
609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
610 DCHECK_EQ(type.value, NotificationType::PREF_CHANGED);
611
612 std::string* pref_name = Details<std::string>(details).ptr();
613 if (*pref_name == prefs::kHttpThrottlingEnabled) {
614 scoped_ptr<Value> enabled(
615 Value::CreateBooleanValue(*http_throttling_enabled_));
616
617 CallJavascriptFunction(
618 L"g_browser.receivedHttpThrottlingEnabledPrefChanged", enabled.get());
619 }
620 }
621
OnRendererReady(const ListValue * list)622 void NetInternalsMessageHandler::OnRendererReady(const ListValue* list) {
623 CHECK(renderer_ready_io_callback_.get());
624 renderer_ready_io_callback_->Run(list);
625
626 scoped_ptr<Value> enabled(
627 Value::CreateBooleanValue(*http_throttling_enabled_));
628 CallJavascriptFunction(
629 L"g_browser.receivedHttpThrottlingEnabledPrefChanged", enabled.get());
630 }
631
OnEnableHttpThrottling(const ListValue * list)632 void NetInternalsMessageHandler::OnEnableHttpThrottling(const ListValue* list) {
633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
634
635 bool enable = false;
636 if (!list->GetBoolean(0, &enable)) {
637 NOTREACHED();
638 return;
639 }
640
641 http_throttling_enabled_.SetValue(enable);
642 }
643
644 ////////////////////////////////////////////////////////////////////////////////
645 //
646 // NetInternalsMessageHandler::ReadLogFileTask
647 //
648 ////////////////////////////////////////////////////////////////////////////////
649
ReadLogFileTask(IOThreadImpl * proxy,const FilePath & path)650 NetInternalsMessageHandler::ReadLogFileTask::ReadLogFileTask(
651 IOThreadImpl* proxy, const FilePath& path)
652 : proxy_(proxy), path_(path) {
653 }
654
Run()655 void NetInternalsMessageHandler::ReadLogFileTask::Run() {
656 std::string file_contents;
657 if (!file_util::ReadFileToString(path_, &file_contents))
658 return;
659 proxy_->CallJavascriptFunction(L"g_browser.loadedLogFile",
660 new StringValue(file_contents));
661 }
662
663 ////////////////////////////////////////////////////////////////////////////////
664 //
665 // NetInternalsMessageHandler::IOThreadImpl
666 //
667 ////////////////////////////////////////////////////////////////////////////////
668
IOThreadImpl(const base::WeakPtr<NetInternalsMessageHandler> & handler,IOThread * io_thread,net::URLRequestContextGetter * context_getter)669 NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
670 const base::WeakPtr<NetInternalsMessageHandler>& handler,
671 IOThread* io_thread,
672 net::URLRequestContextGetter* context_getter)
673 : ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES),
674 handler_(handler),
675 io_thread_(io_thread),
676 context_getter_(context_getter),
677 was_webui_deleted_(false),
678 is_observing_log_(false) {
679 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
680 }
681
~IOThreadImpl()682 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
684 }
685
686 WebUI::MessageCallback*
CreateCallback(MessageHandler method)687 NetInternalsMessageHandler::IOThreadImpl::CreateCallback(
688 MessageHandler method) {
689 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
690 return new CallbackHelper(this, method);
691 }
692
Detach()693 void NetInternalsMessageHandler::IOThreadImpl::Detach() {
694 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
695 // Unregister with network stack to observe events.
696 if (is_observing_log_)
697 io_thread_->net_log()->RemoveObserver(this);
698
699 // Cancel any in-progress connection tests.
700 connection_tester_.reset();
701 }
702
SendPassiveLogEntries(const ChromeNetLog::EntryList & passive_entries)703 void NetInternalsMessageHandler::IOThreadImpl::SendPassiveLogEntries(
704 const ChromeNetLog::EntryList& passive_entries) {
705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
706 ListValue* dict_list = new ListValue();
707 for (size_t i = 0; i < passive_entries.size(); ++i) {
708 const ChromeNetLog::Entry& e = passive_entries[i];
709 dict_list->Append(net::NetLog::EntryToDictionaryValue(e.type,
710 e.time,
711 e.source,
712 e.phase,
713 e.params,
714 false));
715 }
716
717 CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", dict_list);
718 }
719
OnWebUIDeleted()720 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
721 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
722 was_webui_deleted_ = true;
723 }
724
OnRendererReady(const ListValue * list)725 void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
726 const ListValue* list) {
727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
728 DCHECK(!is_observing_log_) << "notifyReady called twice";
729
730 // Tell the javascript about the relationship between event type enums and
731 // their symbolic name.
732 {
733 std::vector<net::NetLog::EventType> event_types =
734 net::NetLog::GetAllEventTypes();
735
736 DictionaryValue* dict = new DictionaryValue();
737
738 for (size_t i = 0; i < event_types.size(); ++i) {
739 const char* name = net::NetLog::EventTypeToString(event_types[i]);
740 dict->SetInteger(name, static_cast<int>(event_types[i]));
741 }
742
743 CallJavascriptFunction(L"g_browser.receivedLogEventTypeConstants", dict);
744 }
745
746 // Tell the javascript about the version of the client and its
747 // command line arguments.
748 {
749 DictionaryValue* dict = new DictionaryValue();
750
751 chrome::VersionInfo version_info;
752
753 if (!version_info.is_valid()) {
754 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
755 } else {
756 // We have everything we need to send the right values.
757 dict->SetString("version", version_info.Version());
758 dict->SetString("cl", version_info.LastChange());
759 dict->SetString("version_mod",
760 platform_util::GetVersionStringModifier());
761 dict->SetString("official",
762 l10n_util::GetStringUTF16(
763 version_info.IsOfficialBuild() ?
764 IDS_ABOUT_VERSION_OFFICIAL
765 : IDS_ABOUT_VERSION_UNOFFICIAL));
766
767 dict->SetString("command_line",
768 CommandLine::ForCurrentProcess()->command_line_string());
769 }
770
771 CallJavascriptFunction(L"g_browser.receivedClientInfo",
772 dict);
773 }
774
775 // Tell the javascript about the relationship between load flag enums and
776 // their symbolic name.
777 {
778 DictionaryValue* dict = new DictionaryValue();
779
780 #define LOAD_FLAG(label, value) \
781 dict->SetInteger(# label, static_cast<int>(value));
782 #include "net/base/load_flags_list.h"
783 #undef LOAD_FLAG
784
785 CallJavascriptFunction(L"g_browser.receivedLoadFlagConstants", dict);
786 }
787
788 // Tell the javascript about the relationship between net error codes and
789 // their symbolic name.
790 {
791 DictionaryValue* dict = new DictionaryValue();
792
793 #define NET_ERROR(label, value) \
794 dict->SetInteger(# label, static_cast<int>(value));
795 #include "net/base/net_error_list.h"
796 #undef NET_ERROR
797
798 CallJavascriptFunction(L"g_browser.receivedNetErrorConstants", dict);
799 }
800
801 // Tell the javascript about the relationship between event phase enums and
802 // their symbolic name.
803 {
804 DictionaryValue* dict = new DictionaryValue();
805
806 dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN);
807 dict->SetInteger("PHASE_END", net::NetLog::PHASE_END);
808 dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE);
809
810 CallJavascriptFunction(L"g_browser.receivedLogEventPhaseConstants", dict);
811 }
812
813 // Tell the javascript about the relationship between source type enums and
814 // their symbolic names.
815 {
816 DictionaryValue* dict = new DictionaryValue();
817
818 #define SOURCE_TYPE(label, value) dict->SetInteger(# label, value);
819 #include "net/base/net_log_source_type_list.h"
820 #undef SOURCE_TYPE
821
822 CallJavascriptFunction(L"g_browser.receivedLogSourceTypeConstants", dict);
823 }
824
825 // Tell the javascript about the relationship between LogLevel enums and their
826 // symbolic names.
827 {
828 DictionaryValue* dict = new DictionaryValue();
829
830 dict->SetInteger("LOG_ALL", net::NetLog::LOG_ALL);
831 dict->SetInteger("LOG_ALL_BUT_BYTES", net::NetLog::LOG_ALL_BUT_BYTES);
832 dict->SetInteger("LOG_BASIC", net::NetLog::LOG_BASIC);
833
834 CallJavascriptFunction(L"g_browser.receivedLogLevelConstants", dict);
835 }
836
837 // Tell the javascript about the relationship between address family enums and
838 // their symbolic names.
839 {
840 DictionaryValue* dict = new DictionaryValue();
841
842 dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED",
843 net::ADDRESS_FAMILY_UNSPECIFIED);
844 dict->SetInteger("ADDRESS_FAMILY_IPV4",
845 net::ADDRESS_FAMILY_IPV4);
846 dict->SetInteger("ADDRESS_FAMILY_IPV6",
847 net::ADDRESS_FAMILY_IPV6);
848
849 CallJavascriptFunction(L"g_browser.receivedAddressFamilyConstants", dict);
850 }
851
852 // Tell the javascript how the "time ticks" values we have given it relate to
853 // actual system times. (We used time ticks throughout since they are stable
854 // across system clock changes).
855 {
856 int64 cur_time_ms = (base::Time::Now() - base::Time()).InMilliseconds();
857
858 int64 cur_time_ticks_ms =
859 (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
860
861 // If we add this number to a time tick value, it gives the timestamp.
862 int64 tick_to_time_ms = cur_time_ms - cur_time_ticks_ms;
863
864 // Chrome on all platforms stores times using the Windows epoch
865 // (Jan 1 1601), but the javascript wants a unix epoch.
866 // TODO(eroman): Getting the timestamp relative the to unix epoch should
867 // be part of the time library.
868 const int64 kUnixEpochMs = 11644473600000LL;
869 int64 tick_to_unix_time_ms = tick_to_time_ms - kUnixEpochMs;
870
871 // Pass it as a string, since it may be too large to fit in an integer.
872 CallJavascriptFunction(L"g_browser.receivedTimeTickOffset",
873 Value::CreateStringValue(
874 base::Int64ToString(tick_to_unix_time_ms)));
875 }
876
877 // Register with network stack to observe events.
878 is_observing_log_ = true;
879 ChromeNetLog::EntryList entries;
880 io_thread_->net_log()->AddObserverAndGetAllPassivelyCapturedEvents(this,
881 &entries);
882 SendPassiveLogEntries(entries);
883 }
884
OnGetProxySettings(const ListValue * list)885 void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
886 const ListValue* list) {
887 net::URLRequestContext* context = context_getter_->GetURLRequestContext();
888 net::ProxyService* proxy_service = context->proxy_service();
889
890 DictionaryValue* dict = new DictionaryValue();
891 if (proxy_service->fetched_config().is_valid())
892 dict->Set("original", proxy_service->fetched_config().ToValue());
893 if (proxy_service->config().is_valid())
894 dict->Set("effective", proxy_service->config().ToValue());
895
896 CallJavascriptFunction(L"g_browser.receivedProxySettings", dict);
897 }
898
OnReloadProxySettings(const ListValue * list)899 void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
900 const ListValue* list) {
901 net::URLRequestContext* context = context_getter_->GetURLRequestContext();
902 context->proxy_service()->ForceReloadProxyConfig();
903
904 // Cause the renderer to be notified of the new values.
905 OnGetProxySettings(NULL);
906 }
907
OnGetBadProxies(const ListValue * list)908 void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
909 const ListValue* list) {
910 net::URLRequestContext* context = context_getter_->GetURLRequestContext();
911
912 const net::ProxyRetryInfoMap& bad_proxies_map =
913 context->proxy_service()->proxy_retry_info();
914
915 ListValue* dict_list = new ListValue();
916
917 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
918 it != bad_proxies_map.end(); ++it) {
919 const std::string& proxy_uri = it->first;
920 const net::ProxyRetryInfo& retry_info = it->second;
921
922 DictionaryValue* dict = new DictionaryValue();
923 dict->SetString("proxy_uri", proxy_uri);
924 dict->SetString("bad_until",
925 net::NetLog::TickCountToString(retry_info.bad_until));
926
927 dict_list->Append(dict);
928 }
929
930 CallJavascriptFunction(L"g_browser.receivedBadProxies", dict_list);
931 }
932
OnClearBadProxies(const ListValue * list)933 void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
934 const ListValue* list) {
935 net::URLRequestContext* context = context_getter_->GetURLRequestContext();
936 context->proxy_service()->ClearBadProxiesCache();
937
938 // Cause the renderer to be notified of the new values.
939 OnGetBadProxies(NULL);
940 }
941
OnGetHostResolverInfo(const ListValue * list)942 void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverInfo(
943 const ListValue* list) {
944 net::URLRequestContext* context = context_getter_->GetURLRequestContext();
945 net::HostResolverImpl* host_resolver_impl =
946 context->host_resolver()->GetAsHostResolverImpl();
947 net::HostCache* cache = GetHostResolverCache(context);
948
949 if (!host_resolver_impl || !cache) {
950 CallJavascriptFunction(L"g_browser.receivedHostResolverInfo", NULL);
951 return;
952 }
953
954 DictionaryValue* dict = new DictionaryValue();
955
956 dict->SetInteger(
957 "default_address_family",
958 static_cast<int>(host_resolver_impl->GetDefaultAddressFamily()));
959
960 DictionaryValue* cache_info_dict = new DictionaryValue();
961
962 cache_info_dict->SetInteger(
963 "capacity",
964 static_cast<int>(cache->max_entries()));
965 cache_info_dict->SetInteger(
966 "ttl_success_ms",
967 static_cast<int>(cache->success_entry_ttl().InMilliseconds()));
968 cache_info_dict->SetInteger(
969 "ttl_failure_ms",
970 static_cast<int>(cache->failure_entry_ttl().InMilliseconds()));
971
972 ListValue* entry_list = new ListValue();
973
974 for (net::HostCache::EntryMap::const_iterator it =
975 cache->entries().begin();
976 it != cache->entries().end();
977 ++it) {
978 const net::HostCache::Key& key = it->first;
979 const net::HostCache::Entry* entry = it->second.get();
980
981 DictionaryValue* entry_dict = new DictionaryValue();
982
983 entry_dict->SetString("hostname", key.hostname);
984 entry_dict->SetInteger("address_family",
985 static_cast<int>(key.address_family));
986 entry_dict->SetString("expiration",
987 net::NetLog::TickCountToString(entry->expiration));
988
989 if (entry->error != net::OK) {
990 entry_dict->SetInteger("error", entry->error);
991 } else {
992 // Append all of the resolved addresses.
993 ListValue* address_list = new ListValue();
994 const struct addrinfo* current_address = entry->addrlist.head();
995 while (current_address) {
996 address_list->Append(Value::CreateStringValue(
997 net::NetAddressToStringWithPort(current_address)));
998 current_address = current_address->ai_next;
999 }
1000 entry_dict->Set("addresses", address_list);
1001 }
1002
1003 entry_list->Append(entry_dict);
1004 }
1005
1006 cache_info_dict->Set("entries", entry_list);
1007 dict->Set("cache", cache_info_dict);
1008
1009 CallJavascriptFunction(L"g_browser.receivedHostResolverInfo", dict);
1010 }
1011
OnClearHostResolverCache(const ListValue * list)1012 void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
1013 const ListValue* list) {
1014 net::HostCache* cache =
1015 GetHostResolverCache(context_getter_->GetURLRequestContext());
1016
1017 if (cache)
1018 cache->clear();
1019
1020 // Cause the renderer to be notified of the new values.
1021 OnGetHostResolverInfo(NULL);
1022 }
1023
OnEnableIPv6(const ListValue * list)1024 void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
1025 const ListValue* list) {
1026 net::URLRequestContext* context = context_getter_->GetURLRequestContext();
1027 net::HostResolverImpl* host_resolver_impl =
1028 context->host_resolver()->GetAsHostResolverImpl();
1029
1030 if (host_resolver_impl) {
1031 host_resolver_impl->SetDefaultAddressFamily(
1032 net::ADDRESS_FAMILY_UNSPECIFIED);
1033 }
1034
1035 // Cause the renderer to be notified of the new value.
1036 OnGetHostResolverInfo(NULL);
1037 }
1038
OnStartConnectionTests(const ListValue * list)1039 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
1040 const ListValue* list) {
1041 // |value| should be: [<URL to test>].
1042 string16 url_str;
1043 CHECK(list->GetString(0, &url_str));
1044
1045 // Try to fix-up the user provided URL into something valid.
1046 // For example, turn "www.google.com" into "http://www.google.com".
1047 GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(url_str), std::string()));
1048
1049 connection_tester_.reset(new ConnectionTester(
1050 this, io_thread_->globals()->proxy_script_fetcher_context.get()));
1051 connection_tester_->RunAllTests(url);
1052 }
1053
OnHSTSQuery(const ListValue * list)1054 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSQuery(
1055 const ListValue* list) {
1056 // |list| should be: [<domain to query>].
1057 std::string domain;
1058 CHECK(list->GetString(0, &domain));
1059 DictionaryValue* result = new(DictionaryValue);
1060
1061 if (!IsStringASCII(domain)) {
1062 result->SetString("error", "non-ASCII domain name");
1063 } else {
1064 net::TransportSecurityState* transport_security_state =
1065 context_getter_->GetURLRequestContext()->transport_security_state();
1066 if (!transport_security_state) {
1067 result->SetString("error", "no TransportSecurityState active");
1068 } else {
1069 net::TransportSecurityState::DomainState state;
1070 const bool found = transport_security_state->IsEnabledForHost(
1071 &state, domain, true);
1072
1073 result->SetBoolean("result", found);
1074 if (found) {
1075 result->SetInteger("mode", static_cast<int>(state.mode));
1076 result->SetBoolean("subdomains", state.include_subdomains);
1077 result->SetBoolean("preloaded", state.preloaded);
1078 result->SetString("domain", state.domain);
1079
1080 std::vector<std::string> parts;
1081 for (std::vector<net::SHA1Fingerprint>::const_iterator
1082 i = state.public_key_hashes.begin();
1083 i != state.public_key_hashes.end(); i++) {
1084 std::string part = "sha1/";
1085 std::string hash_str(reinterpret_cast<const char*>(i->data),
1086 sizeof(i->data));
1087 std::string b64;
1088 base::Base64Encode(hash_str, &b64);
1089 part += b64;
1090 parts.push_back(part);
1091 }
1092 result->SetString("public_key_hashes", JoinString(parts, ','));
1093 }
1094 }
1095 }
1096
1097 CallJavascriptFunction(L"g_browser.receivedHSTSResult", result);
1098 }
1099
OnHSTSAdd(const ListValue * list)1100 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd(
1101 const ListValue* list) {
1102 // |list| should be: [<domain to query>, <include subdomains>, <cert pins>].
1103 std::string domain;
1104 CHECK(list->GetString(0, &domain));
1105 if (!IsStringASCII(domain)) {
1106 // Silently fail. The user will get a helpful error if they query for the
1107 // name.
1108 return;
1109 }
1110 bool include_subdomains;
1111 CHECK(list->GetBoolean(1, &include_subdomains));
1112 std::string hashes_str;
1113 CHECK(list->GetString(2, &hashes_str));
1114
1115 net::TransportSecurityState* transport_security_state =
1116 context_getter_->GetURLRequestContext()->transport_security_state();
1117 if (!transport_security_state)
1118 return;
1119
1120 net::TransportSecurityState::DomainState state;
1121 state.expiry = state.created + base::TimeDelta::FromDays(1000);
1122 state.include_subdomains = include_subdomains;
1123 state.public_key_hashes.clear();
1124 if (!hashes_str.empty()) {
1125 std::vector<std::string> type_and_b64s;
1126 base::SplitString(hashes_str, ',', &type_and_b64s);
1127 for (std::vector<std::string>::const_iterator
1128 i = type_and_b64s.begin(); i != type_and_b64s.end(); i++) {
1129 std::string type_and_b64;
1130 RemoveChars(*i, " \t\r\n", &type_and_b64);
1131 if (type_and_b64.find("sha1/") != 0)
1132 continue;
1133 std::string b64 = type_and_b64.substr(5, type_and_b64.size() - 5);
1134 std::string hash_str;
1135 if (!base::Base64Decode(b64, &hash_str))
1136 continue;
1137 net::SHA1Fingerprint hash;
1138 if (hash_str.size() != sizeof(hash.data))
1139 continue;
1140 memcpy(hash.data, hash_str.data(), sizeof(hash.data));
1141 state.public_key_hashes.push_back(hash);
1142 }
1143 }
1144
1145 transport_security_state->EnableHost(domain, state);
1146 }
1147
OnHSTSDelete(const ListValue * list)1148 void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete(
1149 const ListValue* list) {
1150 // |list| should be: [<domain to query>].
1151 std::string domain;
1152 CHECK(list->GetString(0, &domain));
1153 if (!IsStringASCII(domain)) {
1154 // There cannot be a unicode entry in the HSTS set.
1155 return;
1156 }
1157 net::TransportSecurityState* transport_security_state =
1158 context_getter_->GetURLRequestContext()->transport_security_state();
1159 if (!transport_security_state)
1160 return;
1161
1162 transport_security_state->DeleteHost(domain);
1163 }
1164
OnGetHttpCacheInfo(const ListValue * list)1165 void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
1166 const ListValue* list) {
1167 DictionaryValue* info_dict = new DictionaryValue();
1168 DictionaryValue* stats_dict = new DictionaryValue();
1169
1170 disk_cache::Backend* disk_cache = GetDiskCacheBackend(
1171 context_getter_->GetURLRequestContext());
1172
1173 if (disk_cache) {
1174 // Extract the statistics key/value pairs from the backend.
1175 std::vector<std::pair<std::string, std::string> > stats;
1176 disk_cache->GetStats(&stats);
1177 for (size_t i = 0; i < stats.size(); ++i) {
1178 stats_dict->Set(stats[i].first,
1179 Value::CreateStringValue(stats[i].second));
1180 }
1181 }
1182
1183 info_dict->Set("stats", stats_dict);
1184
1185 CallJavascriptFunction(L"g_browser.receivedHttpCacheInfo", info_dict);
1186 }
1187
OnGetSocketPoolInfo(const ListValue * list)1188 void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
1189 const ListValue* list) {
1190 net::HttpNetworkSession* http_network_session =
1191 GetHttpNetworkSession(context_getter_->GetURLRequestContext());
1192
1193 Value* socket_pool_info = NULL;
1194 if (http_network_session)
1195 socket_pool_info = http_network_session->SocketPoolInfoToValue();
1196
1197 CallJavascriptFunction(L"g_browser.receivedSocketPoolInfo", socket_pool_info);
1198 }
1199
1200
OnFlushSocketPools(const ListValue * list)1201 void NetInternalsMessageHandler::IOThreadImpl::OnFlushSocketPools(
1202 const ListValue* list) {
1203 net::HttpNetworkSession* http_network_session =
1204 GetHttpNetworkSession(context_getter_->GetURLRequestContext());
1205
1206 if (http_network_session)
1207 http_network_session->CloseAllConnections();
1208 }
1209
OnCloseIdleSockets(const ListValue * list)1210 void NetInternalsMessageHandler::IOThreadImpl::OnCloseIdleSockets(
1211 const ListValue* list) {
1212 net::HttpNetworkSession* http_network_session =
1213 GetHttpNetworkSession(context_getter_->GetURLRequestContext());
1214
1215 if (http_network_session)
1216 http_network_session->CloseIdleConnections();
1217 }
1218
OnGetSpdySessionInfo(const ListValue * list)1219 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdySessionInfo(
1220 const ListValue* list) {
1221 net::HttpNetworkSession* http_network_session =
1222 GetHttpNetworkSession(context_getter_->GetURLRequestContext());
1223
1224 Value* spdy_info = NULL;
1225 if (http_network_session) {
1226 spdy_info = http_network_session->SpdySessionPoolInfoToValue();
1227 }
1228
1229 CallJavascriptFunction(L"g_browser.receivedSpdySessionInfo", spdy_info);
1230 }
1231
OnGetSpdyStatus(const ListValue * list)1232 void NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyStatus(
1233 const ListValue* list) {
1234 DictionaryValue* status_dict = new DictionaryValue();
1235
1236 status_dict->Set("spdy_enabled",
1237 Value::CreateBooleanValue(
1238 net::HttpStreamFactory::spdy_enabled()));
1239 status_dict->Set("use_alternate_protocols",
1240 Value::CreateBooleanValue(
1241 net::HttpStreamFactory::use_alternate_protocols()));
1242 status_dict->Set("force_spdy_over_ssl",
1243 Value::CreateBooleanValue(
1244 net::HttpStreamFactory::force_spdy_over_ssl()));
1245 status_dict->Set("force_spdy_always",
1246 Value::CreateBooleanValue(
1247 net::HttpStreamFactory::force_spdy_always()));
1248 status_dict->Set("next_protos",
1249 Value::CreateStringValue(
1250 *net::HttpStreamFactory::next_protos()));
1251
1252 CallJavascriptFunction(L"g_browser.receivedSpdyStatus", status_dict);
1253 }
1254
1255 void
OnGetSpdyAlternateProtocolMappings(const ListValue * list)1256 NetInternalsMessageHandler::IOThreadImpl::OnGetSpdyAlternateProtocolMappings(
1257 const ListValue* list) {
1258 net::HttpNetworkSession* http_network_session =
1259 GetHttpNetworkSession(context_getter_->GetURLRequestContext());
1260
1261 ListValue* dict_list = new ListValue();
1262
1263 if (http_network_session) {
1264 const net::HttpAlternateProtocols& http_alternate_protocols =
1265 http_network_session->alternate_protocols();
1266 const net::HttpAlternateProtocols::ProtocolMap& map =
1267 http_alternate_protocols.protocol_map();
1268
1269 for (net::HttpAlternateProtocols::ProtocolMap::const_iterator it =
1270 map.begin();
1271 it != map.end(); ++it) {
1272 DictionaryValue* dict = new DictionaryValue();
1273 dict->SetString("host_port_pair", it->first.ToString());
1274 dict->SetString("alternate_protocol", it->second.ToString());
1275 dict_list->Append(dict);
1276 }
1277 }
1278
1279 CallJavascriptFunction(L"g_browser.receivedSpdyAlternateProtocolMappings",
1280 dict_list);
1281 }
1282
1283 #ifdef OS_WIN
OnGetServiceProviders(const ListValue * list)1284 void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
1285 const ListValue* list) {
1286
1287 DictionaryValue* service_providers = new DictionaryValue();
1288
1289 WinsockLayeredServiceProviderList layered_providers;
1290 GetWinsockLayeredServiceProviders(&layered_providers);
1291 ListValue* layered_provider_list = new ListValue();
1292 for (size_t i = 0; i < layered_providers.size(); ++i) {
1293 DictionaryValue* service_dict = new DictionaryValue();
1294 service_dict->SetString("name", layered_providers[i].name);
1295 service_dict->SetInteger("version", layered_providers[i].version);
1296 service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
1297 service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
1298 service_dict->SetInteger("socket_protocol",
1299 layered_providers[i].socket_protocol);
1300 service_dict->SetString("path", layered_providers[i].path);
1301
1302 layered_provider_list->Append(service_dict);
1303 }
1304 service_providers->Set("service_providers", layered_provider_list);
1305
1306 WinsockNamespaceProviderList namespace_providers;
1307 GetWinsockNamespaceProviders(&namespace_providers);
1308 ListValue* namespace_list = new ListValue;
1309 for (size_t i = 0; i < namespace_providers.size(); ++i) {
1310 DictionaryValue* namespace_dict = new DictionaryValue();
1311 namespace_dict->SetString("name", namespace_providers[i].name);
1312 namespace_dict->SetBoolean("active", namespace_providers[i].active);
1313 namespace_dict->SetInteger("version", namespace_providers[i].version);
1314 namespace_dict->SetInteger("type", namespace_providers[i].type);
1315
1316 namespace_list->Append(namespace_dict);
1317 }
1318 service_providers->Set("namespace_providers", namespace_list);
1319
1320 CallJavascriptFunction(L"g_browser.receivedServiceProviders",
1321 service_providers);
1322 }
1323 #endif
1324
OnSetLogLevel(const ListValue * list)1325 void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
1326 const ListValue* list) {
1327 int log_level;
1328 std::string log_level_string;
1329 if (!list->GetString(0, &log_level_string) ||
1330 !base::StringToInt(log_level_string, &log_level)) {
1331 NOTREACHED();
1332 return;
1333 }
1334
1335 DCHECK_GE(log_level, net::NetLog::LOG_ALL);
1336 DCHECK_LE(log_level, net::NetLog::LOG_BASIC);
1337 SetLogLevel(static_cast<net::NetLog::LogLevel>(log_level));
1338 }
1339
1340 // Note that unlike other methods of IOThreadImpl, this function
1341 // can be called from ANY THREAD.
OnAddEntry(net::NetLog::EventType type,const base::TimeTicks & time,const net::NetLog::Source & source,net::NetLog::EventPhase phase,net::NetLog::EventParameters * params)1342 void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
1343 net::NetLog::EventType type,
1344 const base::TimeTicks& time,
1345 const net::NetLog::Source& source,
1346 net::NetLog::EventPhase phase,
1347 net::NetLog::EventParameters* params) {
1348 BrowserThread::PostTask(
1349 BrowserThread::IO, FROM_HERE,
1350 NewRunnableMethod(
1351 this, &IOThreadImpl::AddEntryToQueue,
1352 net::NetLog::EntryToDictionaryValue(type, time, source, phase,
1353 params, false)));
1354 }
1355
AddEntryToQueue(Value * entry)1356 void NetInternalsMessageHandler::IOThreadImpl::AddEntryToQueue(Value* entry) {
1357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1358 if (!pending_entries_.get()) {
1359 pending_entries_.reset(new ListValue());
1360 BrowserThread::PostDelayedTask(
1361 BrowserThread::IO, FROM_HERE,
1362 NewRunnableMethod(this, &IOThreadImpl::PostPendingEntries),
1363 kNetLogEventDelayMilliseconds);
1364 }
1365 pending_entries_->Append(entry);
1366 }
1367
PostPendingEntries()1368 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
1369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1370 CallJavascriptFunction(
1371 L"g_browser.receivedLogEntries",
1372 pending_entries_.release());
1373 }
1374
OnStartConnectionTestSuite()1375 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
1376 CallJavascriptFunction(L"g_browser.receivedStartConnectionTestSuite", NULL);
1377 }
1378
OnStartConnectionTestExperiment(const ConnectionTester::Experiment & experiment)1379 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
1380 const ConnectionTester::Experiment& experiment) {
1381 CallJavascriptFunction(
1382 L"g_browser.receivedStartConnectionTestExperiment",
1383 ExperimentToValue(experiment));
1384 }
1385
1386 void
OnCompletedConnectionTestExperiment(const ConnectionTester::Experiment & experiment,int result)1387 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
1388 const ConnectionTester::Experiment& experiment,
1389 int result) {
1390 DictionaryValue* dict = new DictionaryValue();
1391
1392 dict->Set("experiment", ExperimentToValue(experiment));
1393 dict->SetInteger("result", result);
1394
1395 CallJavascriptFunction(
1396 L"g_browser.receivedCompletedConnectionTestExperiment",
1397 dict);
1398 }
1399
1400 void
OnCompletedConnectionTestSuite()1401 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
1402 CallJavascriptFunction(
1403 L"g_browser.receivedCompletedConnectionTestSuite",
1404 NULL);
1405 }
1406
DispatchToMessageHandler(ListValue * arg,MessageHandler method)1407 void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler(
1408 ListValue* arg, MessageHandler method) {
1409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1410 (this->*method)(arg);
1411 delete arg;
1412 }
1413
1414 // Note that this can be called from ANY THREAD.
CallJavascriptFunction(const std::wstring & function_name,Value * arg)1415 void NetInternalsMessageHandler::IOThreadImpl::CallJavascriptFunction(
1416 const std::wstring& function_name,
1417 Value* arg) {
1418 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1419 if (handler_ && !was_webui_deleted_) {
1420 // We check |handler_| in case it was deleted on the UI thread earlier
1421 // while we were running on the IO thread.
1422 handler_->CallJavascriptFunction(function_name, arg);
1423 }
1424 delete arg;
1425 return;
1426 }
1427
1428 if (!BrowserThread::PostTask(
1429 BrowserThread::UI, FROM_HERE,
1430 NewRunnableMethod(
1431 this,
1432 &IOThreadImpl::CallJavascriptFunction,
1433 function_name, arg))) {
1434 // Failed posting the task, avoid leaking.
1435 delete arg;
1436 }
1437 }
1438
1439 } // namespace
1440
1441
1442 ////////////////////////////////////////////////////////////////////////////////
1443 //
1444 // NetInternalsUI
1445 //
1446 ////////////////////////////////////////////////////////////////////////////////
1447
NetInternalsUI(TabContents * contents)1448 NetInternalsUI::NetInternalsUI(TabContents* contents) : WebUI(contents) {
1449 AddMessageHandler((new NetInternalsMessageHandler())->Attach(this));
1450
1451 NetInternalsHTMLSource* html_source = new NetInternalsHTMLSource();
1452
1453 // Set up the chrome://net-internals/ source.
1454 contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
1455 }
1456