Home | History | Annotate | Download | only in webui
      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.
     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.
     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.
    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 
    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:
    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:
    374   CallbackHelper(IOThreadImpl* instance, IOThreadImpl::MessageHandler method)
    375       : instance_(instance),
    376         method_(method) {
    377     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    378   }
    379 
    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 
    409 NetInternalsHTMLSource::NetInternalsHTMLSource()
    410     : DataSource(chrome::kChromeUINetInternalsHost, MessageLoop::current()) {
    411 }
    412 
    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 
    453 std::string NetInternalsHTMLSource::GetMimeType(const std::string&) const {
    454   return "text/html";
    455 }
    456 
    457 ////////////////////////////////////////////////////////////////////////////////
    458 //
    459 // NetInternalsMessageHandler
    460 //
    461 ////////////////////////////////////////////////////////////////////////////////
    462 
    463 NetInternalsMessageHandler::NetInternalsMessageHandler() {}
    464 
    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 
    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 
    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 
    500 void NetInternalsMessageHandler::FileSelectionCanceled(void* params) {
    501   select_log_file_dialog_.release();
    502 }
    503 
    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 
    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 
    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 
    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 
    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 
    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 
    650 NetInternalsMessageHandler::ReadLogFileTask::ReadLogFileTask(
    651     IOThreadImpl* proxy, const FilePath& path)
    652     : proxy_(proxy), path_(path) {
    653 }
    654 
    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 
    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 
    682 NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() {
    683   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    684 }
    685 
    686 WebUI::MessageCallback*
    687 NetInternalsMessageHandler::IOThreadImpl::CreateCallback(
    688     MessageHandler method) {
    689   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    690   return new CallbackHelper(this, method);
    691 }
    692 
    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 
    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 
    720 void NetInternalsMessageHandler::IOThreadImpl::OnWebUIDeleted() {
    721   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    722   was_webui_deleted_ = true;
    723 }
    724 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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
   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
   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 
   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.
   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 
   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 
   1368 void NetInternalsMessageHandler::IOThreadImpl::PostPendingEntries() {
   1369   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   1370   CallJavascriptFunction(
   1371       L"g_browser.receivedLogEntries",
   1372       pending_entries_.release());
   1373 }
   1374 
   1375 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
   1376   CallJavascriptFunction(L"g_browser.receivedStartConnectionTestSuite", NULL);
   1377 }
   1378 
   1379 void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestExperiment(
   1380     const ConnectionTester::Experiment& experiment) {
   1381   CallJavascriptFunction(
   1382       L"g_browser.receivedStartConnectionTestExperiment",
   1383       ExperimentToValue(experiment));
   1384 }
   1385 
   1386 void
   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
   1401 NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
   1402   CallJavascriptFunction(
   1403       L"g_browser.receivedCompletedConnectionTestSuite",
   1404       NULL);
   1405 }
   1406 
   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.
   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 
   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