Home | History | Annotate | Download | only in net_internals
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/command_line.h"
     10 #include "base/file_util.h"
     11 #include "base/files/file_path.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/browser_process.h"
     15 #include "chrome/browser/io_thread.h"
     16 #include "chrome/browser/net/chrome_net_log.h"
     17 #include "chrome/browser/prerender/prerender_manager.h"
     18 #include "chrome/browser/prerender/prerender_manager_factory.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     22 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
     23 #include "chrome/common/chrome_switches.h"
     24 #include "chrome/test/base/ui_test_utils.h"
     25 #include "content/public/browser/render_view_host.h"
     26 #include "content/public/browser/web_contents.h"
     27 #include "content/public/browser/web_ui_message_handler.h"
     28 #include "net/base/address_list.h"
     29 #include "net/base/net_errors.h"
     30 #include "net/base/net_log.h"
     31 #include "net/base/net_log_logger.h"
     32 #include "net/dns/host_cache.h"
     33 #include "net/dns/host_resolver.h"
     34 #include "net/dns/mock_host_resolver.h"
     35 #include "net/http/http_network_session.h"
     36 #include "net/http/http_pipelined_host_capability.h"
     37 #include "net/http/http_transaction_factory.h"
     38 #include "net/url_request/url_request_context.h"
     39 #include "net/url_request/url_request_context_getter.h"
     40 #include "testing/gtest/include/gtest/gtest.h"
     41 #include "url/gurl.h"
     42 
     43 using content::BrowserThread;
     44 using content::WebUIMessageHandler;
     45 
     46 namespace {
     47 
     48 // Called on IO thread.  Adds an entry to the cache for the specified hostname.
     49 // Either |net_error| must be net::OK, or |address| must be NULL.
     50 void AddCacheEntryOnIOThread(net::URLRequestContextGetter* context_getter,
     51                              const std::string& hostname,
     52                              const std::string& ip_literal,
     53                              int net_error,
     54                              int expire_days_from_now) {
     55   ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
     56   net::URLRequestContext* context = context_getter->GetURLRequestContext();
     57   net::HostCache* cache = context->host_resolver()->GetHostCache();
     58   ASSERT_TRUE(cache);
     59 
     60   net::HostCache::Key key(hostname, net::ADDRESS_FAMILY_UNSPECIFIED, 0);
     61   base::TimeDelta ttl = base::TimeDelta::FromDays(expire_days_from_now);
     62 
     63   net::AddressList address_list;
     64   if (net_error == net::OK) {
     65     // If |net_error| does not indicate an error, convert |ip_literal| to a
     66     // net::AddressList, so it can be used with the cache.
     67     int rv = net::ParseAddressList(ip_literal, hostname, &address_list);
     68     ASSERT_EQ(net::OK, rv);
     69   } else {
     70     ASSERT_TRUE(ip_literal.empty());
     71   }
     72 
     73   // Add entry to the cache.
     74   cache->Set(net::HostCache::Key(hostname, net::ADDRESS_FAMILY_UNSPECIFIED, 0),
     75              net::HostCache::Entry(net_error, address_list),
     76              base::TimeTicks::Now(),
     77              ttl);
     78 }
     79 
     80 // Called on IO thread.  Adds an entry to the list of known HTTP pipelining
     81 // hosts.
     82 void AddDummyHttpPipelineFeedbackOnIOThread(
     83     net::URLRequestContextGetter* context_getter,
     84     const std::string& hostname,
     85     int port,
     86     net::HttpPipelinedHostCapability capability) {
     87   ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
     88   net::URLRequestContext* context = context_getter->GetURLRequestContext();
     89   net::HttpNetworkSession* http_network_session =
     90       context->http_transaction_factory()->GetSession();
     91   base::WeakPtr<net::HttpServerProperties> http_server_properties =
     92       http_network_session->http_server_properties();
     93   net::HostPortPair origin(hostname, port);
     94   http_server_properties->SetPipelineCapability(origin, capability);
     95 }
     96 
     97 // Called on IO thread.  Adds an entry to the list of known HTTP pipelining
     98 // hosts.
     99 void EnableHttpPipeliningOnIOThread(
    100     net::URLRequestContextGetter* context_getter, bool enable) {
    101   ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    102   net::URLRequestContext* context = context_getter->GetURLRequestContext();
    103   net::HttpNetworkSession* http_network_session =
    104       context->http_transaction_factory()->GetSession();
    105   http_network_session->set_http_pipelining_enabled(enable);
    106 }
    107 
    108 }  // namespace
    109 
    110 ////////////////////////////////////////////////////////////////////////////////
    111 // NetInternalsTest::MessageHandler
    112 ////////////////////////////////////////////////////////////////////////////////
    113 
    114 // Class to handle messages from the renderer needed by certain tests.
    115 class NetInternalsTest::MessageHandler : public content::WebUIMessageHandler {
    116  public:
    117   explicit MessageHandler(NetInternalsTest* net_internals_test);
    118 
    119  private:
    120   virtual void RegisterMessages() OVERRIDE;
    121 
    122   // Runs NetInternalsTest.callback with the given value.
    123   void RunJavascriptCallback(base::Value* value);
    124 
    125   // Takes a string and provides the corresponding URL from the test server,
    126   // which must already have been started.
    127   void GetTestServerURL(const base::ListValue* list_value);
    128 
    129   // Called on UI thread.  Adds an entry to the cache for the specified
    130   // hostname by posting a task to the IO thread.  Takes the host name,
    131   // ip address, net error code, and expiration time in days from now
    132   // as parameters.  If the error code indicates failure, the ip address
    133   // must be an empty string.
    134   void AddCacheEntry(const base::ListValue* list_value);
    135 
    136   // Opens the given URL in a new tab.
    137   void LoadPage(const base::ListValue* list_value);
    138 
    139   // Opens a page in a new tab that prerenders the given URL.
    140   void PrerenderPage(const base::ListValue* list_value);
    141 
    142   // Navigates to the prerender in the background tab. This assumes that
    143   // there is a "Click()" function in the background tab which will navigate
    144   // there, and that the background tab exists at slot 1.
    145   void NavigateToPrerender(const base::ListValue* list_value);
    146 
    147   // Creates an incognito browser.  Once creation is complete, passes a
    148   // message to the Javascript test harness.
    149   void CreateIncognitoBrowser(const base::ListValue* list_value);
    150 
    151   // Closes an incognito browser created with CreateIncognitoBrowser.
    152   void CloseIncognitoBrowser(const base::ListValue* list_value);
    153 
    154   // Takes in a boolean and enables/disabled HTTP pipelining accordingly.
    155   void EnableHttpPipelining(const base::ListValue* list_value);
    156 
    157   // Called on UI thread. Adds an entry to the list of known HTTP pipelining
    158   // hosts.
    159   void AddDummyHttpPipelineFeedback(const base::ListValue* list_value);
    160 
    161   // Creates a simple log with a NetLogLogger, and returns it to the
    162   // Javascript callback.
    163   void GetNetLogLoggerLog(const ListValue* list_value);
    164 
    165   Browser* browser() { return net_internals_test_->browser(); }
    166 
    167   NetInternalsTest* net_internals_test_;
    168   Browser* incognito_browser_;
    169 
    170   DISALLOW_COPY_AND_ASSIGN(MessageHandler);
    171 };
    172 
    173 NetInternalsTest::MessageHandler::MessageHandler(
    174     NetInternalsTest* net_internals_test)
    175     : net_internals_test_(net_internals_test),
    176       incognito_browser_(NULL) {
    177 }
    178 
    179 void NetInternalsTest::MessageHandler::RegisterMessages() {
    180   web_ui()->RegisterMessageCallback("getTestServerURL",
    181       base::Bind(&NetInternalsTest::MessageHandler::GetTestServerURL,
    182                  base::Unretained(this)));
    183   web_ui()->RegisterMessageCallback("addCacheEntry",
    184       base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry,
    185                  base::Unretained(this)));
    186   web_ui()->RegisterMessageCallback("loadPage",
    187       base::Bind(&NetInternalsTest::MessageHandler::LoadPage,
    188                   base::Unretained(this)));
    189   web_ui()->RegisterMessageCallback("prerenderPage",
    190       base::Bind(&NetInternalsTest::MessageHandler::PrerenderPage,
    191                   base::Unretained(this)));
    192   web_ui()->RegisterMessageCallback("navigateToPrerender",
    193       base::Bind(&NetInternalsTest::MessageHandler::NavigateToPrerender,
    194                  base::Unretained(this)));
    195   web_ui()->RegisterMessageCallback("createIncognitoBrowser",
    196       base::Bind(&NetInternalsTest::MessageHandler::CreateIncognitoBrowser,
    197                  base::Unretained(this)));
    198   web_ui()->RegisterMessageCallback("closeIncognitoBrowser",
    199       base::Bind(&NetInternalsTest::MessageHandler::CloseIncognitoBrowser,
    200                  base::Unretained(this)));
    201   web_ui()->RegisterMessageCallback("enableHttpPipelining",
    202       base::Bind(&NetInternalsTest::MessageHandler::EnableHttpPipelining,
    203                  base::Unretained(this)));
    204   web_ui()->RegisterMessageCallback("addDummyHttpPipelineFeedback",
    205       base::Bind(
    206           &NetInternalsTest::MessageHandler::AddDummyHttpPipelineFeedback,
    207           base::Unretained(this)));
    208   web_ui()->RegisterMessageCallback("getNetLogLoggerLog",
    209       base::Bind(
    210           &NetInternalsTest::MessageHandler::GetNetLogLoggerLog,
    211           base::Unretained(this)));
    212 }
    213 
    214 void NetInternalsTest::MessageHandler::RunJavascriptCallback(
    215     Value* value) {
    216   web_ui()->CallJavascriptFunction("NetInternalsTest.callback", *value);
    217 }
    218 
    219 void NetInternalsTest::MessageHandler::GetTestServerURL(
    220     const ListValue* list_value) {
    221   ASSERT_TRUE(net_internals_test_->StartTestServer());
    222   std::string path;
    223   ASSERT_TRUE(list_value->GetString(0, &path));
    224   GURL url = net_internals_test_->test_server()->GetURL(path);
    225   scoped_ptr<Value> url_value(Value::CreateStringValue(url.spec()));
    226   RunJavascriptCallback(url_value.get());
    227 }
    228 
    229 void NetInternalsTest::MessageHandler::AddCacheEntry(
    230     const ListValue* list_value) {
    231   std::string hostname;
    232   std::string ip_literal;
    233   double net_error;
    234   double expire_days_from_now;
    235   ASSERT_TRUE(list_value->GetString(0, &hostname));
    236   ASSERT_TRUE(list_value->GetString(1, &ip_literal));
    237   ASSERT_TRUE(list_value->GetDouble(2, &net_error));
    238   ASSERT_TRUE(list_value->GetDouble(3, &expire_days_from_now));
    239   ASSERT_TRUE(browser());
    240 
    241   BrowserThread::PostTask(
    242       BrowserThread::IO, FROM_HERE,
    243       base::Bind(&AddCacheEntryOnIOThread,
    244                  make_scoped_refptr(browser()->profile()->GetRequestContext()),
    245                  hostname,
    246                  ip_literal,
    247                  static_cast<int>(net_error),
    248                  static_cast<int>(expire_days_from_now)));
    249 }
    250 
    251 void NetInternalsTest::MessageHandler::LoadPage(
    252     const ListValue* list_value) {
    253   std::string url;
    254   ASSERT_TRUE(list_value->GetString(0, &url));
    255   LOG(WARNING) << "url: [" << url << "]";
    256   ui_test_utils::NavigateToURLWithDisposition(
    257       browser(),
    258       GURL(url),
    259       NEW_BACKGROUND_TAB,
    260       ui_test_utils::BROWSER_TEST_NONE);
    261 }
    262 
    263 void NetInternalsTest::MessageHandler::PrerenderPage(
    264     const ListValue* list_value) {
    265   std::string prerender_url;
    266   ASSERT_TRUE(list_value->GetString(0, &prerender_url));
    267   GURL loader_url =
    268       net_internals_test_->CreatePrerenderLoaderUrl(GURL(prerender_url));
    269   ui_test_utils::NavigateToURLWithDisposition(
    270       browser(),
    271       GURL(loader_url),
    272       NEW_BACKGROUND_TAB,
    273       ui_test_utils::BROWSER_TEST_NONE);
    274 }
    275 
    276 void NetInternalsTest::MessageHandler::NavigateToPrerender(
    277     const ListValue* list_value) {
    278   content::RenderViewHost* host =
    279       browser()->tab_strip_model()->GetWebContentsAt(1)->GetRenderViewHost();
    280   host->ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16("Click()"));
    281 }
    282 
    283 void NetInternalsTest::MessageHandler::CreateIncognitoBrowser(
    284     const ListValue* list_value) {
    285   ASSERT_FALSE(incognito_browser_);
    286   incognito_browser_ = net_internals_test_->CreateIncognitoBrowser();
    287 
    288   // Tell the test harness that creation is complete.
    289   StringValue command_value("onIncognitoBrowserCreatedForTest");
    290   web_ui()->CallJavascriptFunction("g_browser.receive", command_value);
    291 }
    292 
    293 void NetInternalsTest::MessageHandler::CloseIncognitoBrowser(
    294     const ListValue* list_value) {
    295   ASSERT_TRUE(incognito_browser_);
    296   incognito_browser_->tab_strip_model()->CloseAllTabs();
    297   // Closing all a Browser's tabs will ultimately result in its destruction,
    298   // thought it may not have been destroyed yet.
    299   incognito_browser_ = NULL;
    300 }
    301 
    302 void NetInternalsTest::MessageHandler::EnableHttpPipelining(
    303     const ListValue* list_value) {
    304   bool enable;
    305   ASSERT_TRUE(list_value->GetBoolean(0, &enable));
    306   BrowserThread::PostTask(
    307       BrowserThread::IO, FROM_HERE,
    308       base::Bind(&EnableHttpPipeliningOnIOThread,
    309                  make_scoped_refptr(browser()->profile()->GetRequestContext()),
    310                  enable));
    311 }
    312 
    313 void NetInternalsTest::MessageHandler::AddDummyHttpPipelineFeedback(
    314     const ListValue* list_value) {
    315   std::string hostname;
    316   double port;
    317   std::string raw_capability;
    318   net::HttpPipelinedHostCapability capability;
    319   ASSERT_TRUE(list_value->GetString(0, &hostname));
    320   ASSERT_TRUE(list_value->GetDouble(1, &port));
    321   ASSERT_TRUE(list_value->GetString(2, &raw_capability));
    322   if (raw_capability == "capable") {
    323     capability = net::PIPELINE_CAPABLE;
    324   } else if (raw_capability == "incapable") {
    325     capability = net::PIPELINE_INCAPABLE;
    326   } else {
    327     FAIL() << "Unexpected capability string: " << raw_capability;
    328   }
    329   BrowserThread::PostTask(
    330       BrowserThread::IO, FROM_HERE,
    331       base::Bind(&AddDummyHttpPipelineFeedbackOnIOThread,
    332                  make_scoped_refptr(browser()->profile()->GetRequestContext()),
    333                  hostname,
    334                  static_cast<int>(port),
    335                  capability));
    336 }
    337 
    338 void NetInternalsTest::MessageHandler::GetNetLogLoggerLog(
    339     const ListValue* list_value) {
    340   base::ScopedTempDir temp_directory;
    341   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
    342   base::FilePath temp_file;
    343   ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
    344                                                   &temp_file));
    345   FILE* temp_file_handle = file_util::OpenFile(temp_file, "w");
    346   ASSERT_TRUE(temp_file_handle);
    347 
    348   scoped_ptr<base::Value> constants(NetInternalsUI::GetConstants());
    349   scoped_ptr<net::NetLogLogger> net_log_logger(new net::NetLogLogger(
    350       temp_file_handle, *constants));
    351   net_log_logger->StartObserving(g_browser_process->net_log());
    352   g_browser_process->net_log()->AddGlobalEntry(
    353       net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED);
    354   net::BoundNetLog bound_net_log = net::BoundNetLog::Make(
    355       g_browser_process->net_log(),
    356       net::NetLog::SOURCE_URL_REQUEST);
    357   bound_net_log.BeginEvent(net::NetLog::TYPE_REQUEST_ALIVE);
    358   net_log_logger->StopObserving();
    359   net_log_logger.reset();
    360 
    361   std::string log_contents;
    362   ASSERT_TRUE(file_util::ReadFileToString(temp_file, &log_contents));
    363   ASSERT_GT(log_contents.length(), 0u);
    364 
    365   scoped_ptr<Value> log_contents_value(new base::StringValue(log_contents));
    366   RunJavascriptCallback(log_contents_value.get());
    367 }
    368 
    369 ////////////////////////////////////////////////////////////////////////////////
    370 // NetInternalsTest
    371 ////////////////////////////////////////////////////////////////////////////////
    372 
    373 NetInternalsTest::NetInternalsTest()
    374     : test_server_started_(false) {
    375   message_handler_.reset(new MessageHandler(this));
    376 }
    377 
    378 NetInternalsTest::~NetInternalsTest() {
    379 }
    380 
    381 void NetInternalsTest::SetUp() {
    382 #if defined(OS_WIN) && defined(USE_AURA)
    383   // The NetInternalsTest.netInternalsTimelineViewScrollbar test requires real
    384   // GL bindings to pass on Win7 Aura.
    385   UseRealGLBindings();
    386 #endif
    387 
    388   WebUIBrowserTest::SetUp();
    389 }
    390 
    391 void NetInternalsTest::SetUpCommandLine(CommandLine* command_line) {
    392   WebUIBrowserTest::SetUpCommandLine(command_line);
    393   // Needed to test the prerender view.
    394   command_line->AppendSwitchASCII(switches::kPrerenderMode,
    395                                   switches::kPrerenderModeSwitchValueEnabled);
    396 }
    397 
    398 void NetInternalsTest::SetUpOnMainThread() {
    399   WebUIBrowserTest::SetUpOnMainThread();
    400   // Increase the memory allowed in a prerendered page above normal settings,
    401   // as debug builds use more memory and often go over the usual limit.
    402   Profile* profile = browser()->profile();
    403   prerender::PrerenderManager* prerender_manager =
    404       prerender::PrerenderManagerFactory::GetForProfile(profile);
    405   prerender_manager->mutable_config().max_bytes = 1000 * 1024 * 1024;
    406 }
    407 
    408 content::WebUIMessageHandler* NetInternalsTest::GetMockMessageHandler() {
    409   return message_handler_.get();
    410 }
    411 
    412 GURL NetInternalsTest::CreatePrerenderLoaderUrl(
    413     const GURL& prerender_url) {
    414   EXPECT_TRUE(StartTestServer());
    415   std::vector<net::SpawnedTestServer::StringPair> replacement_text;
    416   replacement_text.push_back(
    417       make_pair("REPLACE_WITH_PRERENDER_URL", prerender_url.spec()));
    418   replacement_text.push_back(
    419       make_pair("REPLACE_WITH_DESTINATION_URL", prerender_url.spec()));
    420   std::string replacement_path;
    421   EXPECT_TRUE(net::SpawnedTestServer::GetFilePathWithReplacements(
    422       "files/prerender/prerender_loader.html",
    423       replacement_text,
    424       &replacement_path));
    425   GURL url_loader = test_server()->GetURL(replacement_path);
    426   return url_loader;
    427 }
    428 
    429 bool NetInternalsTest::StartTestServer() {
    430   if (test_server_started_)
    431     return true;
    432   test_server_started_ = test_server()->Start();
    433   return test_server_started_;
    434 }
    435