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/stringprintf.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/values.h" 15#include "chrome/browser/browser_process.h" 16#include "chrome/browser/io_thread.h" 17#include "chrome/browser/net/chrome_net_log.h" 18#include "chrome/browser/prerender/prerender_manager.h" 19#include "chrome/browser/prerender/prerender_manager_factory.h" 20#include "chrome/browser/profiles/profile.h" 21#include "chrome/browser/ui/browser.h" 22#include "chrome/browser/ui/tabs/tab_strip_model.h" 23#include "chrome/browser/ui/webui/net_internals/net_internals_ui.h" 24#include "chrome/common/chrome_switches.h" 25#include "chrome/test/base/ui_test_utils.h" 26#include "content/public/browser/render_frame_host.h" 27#include "content/public/browser/web_contents.h" 28#include "content/public/browser/web_ui_message_handler.h" 29#include "net/base/address_list.h" 30#include "net/base/net_errors.h" 31#include "net/base/net_log.h" 32#include "net/base/net_log_logger.h" 33#include "net/dns/host_cache.h" 34#include "net/dns/host_resolver.h" 35#include "net/dns/mock_host_resolver.h" 36#include "net/http/http_network_session.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 43using content::BrowserThread; 44using content::WebUIMessageHandler; 45 46namespace { 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. 50void 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} // namespace 81 82//////////////////////////////////////////////////////////////////////////////// 83// NetInternalsTest::MessageHandler 84//////////////////////////////////////////////////////////////////////////////// 85 86// Class to handle messages from the renderer needed by certain tests. 87class NetInternalsTest::MessageHandler : public content::WebUIMessageHandler { 88 public: 89 explicit MessageHandler(NetInternalsTest* net_internals_test); 90 91 private: 92 virtual void RegisterMessages() OVERRIDE; 93 94 // Runs NetInternalsTest.callback with the given value. 95 void RunJavascriptCallback(base::Value* value); 96 97 // Takes a string and provides the corresponding URL from the test server, 98 // which must already have been started. 99 void GetTestServerURL(const base::ListValue* list_value); 100 101 // Called on UI thread. Adds an entry to the cache for the specified 102 // hostname by posting a task to the IO thread. Takes the host name, 103 // ip address, net error code, and expiration time in days from now 104 // as parameters. If the error code indicates failure, the ip address 105 // must be an empty string. 106 void AddCacheEntry(const base::ListValue* list_value); 107 108 // Opens the given URL in a new tab. 109 void LoadPage(const base::ListValue* list_value); 110 111 // Opens a page in a new tab that prerenders the given URL. 112 void PrerenderPage(const base::ListValue* list_value); 113 114 // Navigates to the prerender in the background tab. This assumes that 115 // there is a "Click()" function in the background tab which will navigate 116 // there, and that the background tab exists at slot 1. 117 void NavigateToPrerender(const base::ListValue* list_value); 118 119 // Creates an incognito browser. Once creation is complete, passes a 120 // message to the Javascript test harness. 121 void CreateIncognitoBrowser(const base::ListValue* list_value); 122 123 // Closes an incognito browser created with CreateIncognitoBrowser. 124 void CloseIncognitoBrowser(const base::ListValue* list_value); 125 126 // Creates a simple log with a NetLogLogger, and returns it to the 127 // Javascript callback. 128 void GetNetLogLoggerLog(const base::ListValue* list_value); 129 130 Browser* browser() { return net_internals_test_->browser(); } 131 132 NetInternalsTest* net_internals_test_; 133 Browser* incognito_browser_; 134 135 DISALLOW_COPY_AND_ASSIGN(MessageHandler); 136}; 137 138NetInternalsTest::MessageHandler::MessageHandler( 139 NetInternalsTest* net_internals_test) 140 : net_internals_test_(net_internals_test), 141 incognito_browser_(NULL) { 142} 143 144void NetInternalsTest::MessageHandler::RegisterMessages() { 145 web_ui()->RegisterMessageCallback("getTestServerURL", 146 base::Bind(&NetInternalsTest::MessageHandler::GetTestServerURL, 147 base::Unretained(this))); 148 web_ui()->RegisterMessageCallback("addCacheEntry", 149 base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry, 150 base::Unretained(this))); 151 web_ui()->RegisterMessageCallback("loadPage", 152 base::Bind(&NetInternalsTest::MessageHandler::LoadPage, 153 base::Unretained(this))); 154 web_ui()->RegisterMessageCallback("prerenderPage", 155 base::Bind(&NetInternalsTest::MessageHandler::PrerenderPage, 156 base::Unretained(this))); 157 web_ui()->RegisterMessageCallback("navigateToPrerender", 158 base::Bind(&NetInternalsTest::MessageHandler::NavigateToPrerender, 159 base::Unretained(this))); 160 web_ui()->RegisterMessageCallback("createIncognitoBrowser", 161 base::Bind(&NetInternalsTest::MessageHandler::CreateIncognitoBrowser, 162 base::Unretained(this))); 163 web_ui()->RegisterMessageCallback("closeIncognitoBrowser", 164 base::Bind(&NetInternalsTest::MessageHandler::CloseIncognitoBrowser, 165 base::Unretained(this))); 166 web_ui()->RegisterMessageCallback("getNetLogLoggerLog", 167 base::Bind( 168 &NetInternalsTest::MessageHandler::GetNetLogLoggerLog, 169 base::Unretained(this))); 170} 171 172void NetInternalsTest::MessageHandler::RunJavascriptCallback( 173 base::Value* value) { 174 web_ui()->CallJavascriptFunction("NetInternalsTest.callback", *value); 175} 176 177void NetInternalsTest::MessageHandler::GetTestServerURL( 178 const base::ListValue* list_value) { 179 ASSERT_TRUE(net_internals_test_->StartTestServer()); 180 std::string path; 181 ASSERT_TRUE(list_value->GetString(0, &path)); 182 GURL url = net_internals_test_->test_server()->GetURL(path); 183 scoped_ptr<base::Value> url_value(base::Value::CreateStringValue(url.spec())); 184 RunJavascriptCallback(url_value.get()); 185} 186 187void NetInternalsTest::MessageHandler::AddCacheEntry( 188 const base::ListValue* list_value) { 189 std::string hostname; 190 std::string ip_literal; 191 double net_error; 192 double expire_days_from_now; 193 ASSERT_TRUE(list_value->GetString(0, &hostname)); 194 ASSERT_TRUE(list_value->GetString(1, &ip_literal)); 195 ASSERT_TRUE(list_value->GetDouble(2, &net_error)); 196 ASSERT_TRUE(list_value->GetDouble(3, &expire_days_from_now)); 197 ASSERT_TRUE(browser()); 198 199 BrowserThread::PostTask( 200 BrowserThread::IO, FROM_HERE, 201 base::Bind(&AddCacheEntryOnIOThread, 202 make_scoped_refptr(browser()->profile()->GetRequestContext()), 203 hostname, 204 ip_literal, 205 static_cast<int>(net_error), 206 static_cast<int>(expire_days_from_now))); 207} 208 209void NetInternalsTest::MessageHandler::LoadPage( 210 const base::ListValue* list_value) { 211 std::string url; 212 ASSERT_TRUE(list_value->GetString(0, &url)); 213 LOG(WARNING) << "url: [" << url << "]"; 214 ui_test_utils::NavigateToURLWithDisposition( 215 browser(), 216 GURL(url), 217 NEW_BACKGROUND_TAB, 218 ui_test_utils::BROWSER_TEST_NONE); 219} 220 221void NetInternalsTest::MessageHandler::PrerenderPage( 222 const base::ListValue* list_value) { 223 std::string prerender_url; 224 ASSERT_TRUE(list_value->GetString(0, &prerender_url)); 225 GURL loader_url = 226 net_internals_test_->CreatePrerenderLoaderUrl(GURL(prerender_url)); 227 ui_test_utils::NavigateToURLWithDisposition( 228 browser(), 229 GURL(loader_url), 230 NEW_BACKGROUND_TAB, 231 ui_test_utils::BROWSER_TEST_NONE); 232} 233 234void NetInternalsTest::MessageHandler::NavigateToPrerender( 235 const base::ListValue* list_value) { 236 std::string url; 237 ASSERT_TRUE(list_value->GetString(0, &url)); 238 content::RenderFrameHost* frame = 239 browser()->tab_strip_model()->GetWebContentsAt(1)->GetMainFrame(); 240 frame->ExecuteJavaScript( 241 base::ASCIIToUTF16(base::StringPrintf("Click('%s')", url.c_str()))); 242} 243 244void NetInternalsTest::MessageHandler::CreateIncognitoBrowser( 245 const base::ListValue* list_value) { 246 ASSERT_FALSE(incognito_browser_); 247 incognito_browser_ = net_internals_test_->CreateIncognitoBrowser(); 248 249 // Tell the test harness that creation is complete. 250 base::StringValue command_value("onIncognitoBrowserCreatedForTest"); 251 web_ui()->CallJavascriptFunction("g_browser.receive", command_value); 252} 253 254void NetInternalsTest::MessageHandler::CloseIncognitoBrowser( 255 const base::ListValue* list_value) { 256 ASSERT_TRUE(incognito_browser_); 257 incognito_browser_->tab_strip_model()->CloseAllTabs(); 258 // Closing all a Browser's tabs will ultimately result in its destruction, 259 // thought it may not have been destroyed yet. 260 incognito_browser_ = NULL; 261} 262 263void NetInternalsTest::MessageHandler::GetNetLogLoggerLog( 264 const base::ListValue* list_value) { 265 base::ScopedTempDir temp_directory; 266 ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); 267 base::FilePath temp_file; 268 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_directory.path(), 269 &temp_file)); 270 FILE* temp_file_handle = base::OpenFile(temp_file, "w"); 271 ASSERT_TRUE(temp_file_handle); 272 273 scoped_ptr<base::Value> constants(NetInternalsUI::GetConstants()); 274 scoped_ptr<net::NetLogLogger> net_log_logger(new net::NetLogLogger( 275 temp_file_handle, *constants)); 276 net_log_logger->StartObserving(g_browser_process->net_log()); 277 g_browser_process->net_log()->AddGlobalEntry( 278 net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED); 279 net::BoundNetLog bound_net_log = net::BoundNetLog::Make( 280 g_browser_process->net_log(), 281 net::NetLog::SOURCE_URL_REQUEST); 282 bound_net_log.BeginEvent(net::NetLog::TYPE_REQUEST_ALIVE); 283 net_log_logger->StopObserving(); 284 net_log_logger.reset(); 285 286 std::string log_contents; 287 ASSERT_TRUE(base::ReadFileToString(temp_file, &log_contents)); 288 ASSERT_GT(log_contents.length(), 0u); 289 290 scoped_ptr<base::Value> log_contents_value( 291 new base::StringValue(log_contents)); 292 RunJavascriptCallback(log_contents_value.get()); 293} 294 295//////////////////////////////////////////////////////////////////////////////// 296// NetInternalsTest 297//////////////////////////////////////////////////////////////////////////////// 298 299NetInternalsTest::NetInternalsTest() 300 : test_server_started_(false) { 301 message_handler_.reset(new MessageHandler(this)); 302} 303 304NetInternalsTest::~NetInternalsTest() { 305} 306 307void NetInternalsTest::SetUpCommandLine(CommandLine* command_line) { 308 WebUIBrowserTest::SetUpCommandLine(command_line); 309 // Needed to test the prerender view. 310 command_line->AppendSwitchASCII(switches::kPrerenderMode, 311 switches::kPrerenderModeSwitchValueEnabled); 312} 313 314void NetInternalsTest::SetUpOnMainThread() { 315 WebUIBrowserTest::SetUpOnMainThread(); 316 // Increase the memory allowed in a prerendered page above normal settings, 317 // as debug builds use more memory and often go over the usual limit. 318 Profile* profile = browser()->profile(); 319 prerender::PrerenderManager* prerender_manager = 320 prerender::PrerenderManagerFactory::GetForProfile(profile); 321 prerender_manager->mutable_config().max_bytes = 1000 * 1024 * 1024; 322 if (!prerender_manager->cookie_store_loaded()) { 323 base::RunLoop loop; 324 prerender_manager->set_on_cookie_store_loaded_cb_for_testing( 325 loop.QuitClosure()); 326 loop.Run(); 327 } 328} 329 330content::WebUIMessageHandler* NetInternalsTest::GetMockMessageHandler() { 331 return message_handler_.get(); 332} 333 334GURL NetInternalsTest::CreatePrerenderLoaderUrl( 335 const GURL& prerender_url) { 336 EXPECT_TRUE(StartTestServer()); 337 std::vector<net::SpawnedTestServer::StringPair> replacement_text; 338 replacement_text.push_back( 339 make_pair("REPLACE_WITH_PRERENDER_URL", prerender_url.spec())); 340 std::string replacement_path; 341 EXPECT_TRUE(net::SpawnedTestServer::GetFilePathWithReplacements( 342 "files/prerender/prerender_loader.html", 343 replacement_text, 344 &replacement_path)); 345 GURL url_loader = test_server()->GetURL(replacement_path); 346 return url_loader; 347} 348 349bool NetInternalsTest::StartTestServer() { 350 if (test_server_started_) 351 return true; 352 test_server_started_ = test_server()->Start(); 353 return test_server_started_; 354} 355