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(base::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(base::CreateTemporaryFileInDir(temp_directory.path(), 344 &temp_file)); 345 FILE* temp_file_handle = base::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(base::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