• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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