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.
5 #include "chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.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_view_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_pipelined_host_capability.h"
38 #include "net/http/http_transaction_factory.h"
39 #include "net/url_request/url_request_context.h"
40 #include "net/url_request/url_request_context_getter.h"
41 #include "testing/gtest/include/gtest/gtest.h"
44 using content::BrowserThread
;
45 using content::WebUIMessageHandler
;
49 // Called on IO thread. Adds an entry to the cache for the specified hostname.
50 // Either |net_error| must be net::OK, or |address| must be NULL.
51 void AddCacheEntryOnIOThread(net::URLRequestContextGetter
* context_getter
,
52 const std::string
& hostname
,
53 const std::string
& ip_literal
,
55 int expire_days_from_now
) {
56 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
57 net::URLRequestContext
* context
= context_getter
->GetURLRequestContext();
58 net::HostCache
* cache
= context
->host_resolver()->GetHostCache();
61 net::HostCache::Key
key(hostname
, net::ADDRESS_FAMILY_UNSPECIFIED
, 0);
62 base::TimeDelta ttl
= base::TimeDelta::FromDays(expire_days_from_now
);
64 net::AddressList address_list
;
65 if (net_error
== net::OK
) {
66 // If |net_error| does not indicate an error, convert |ip_literal| to a
67 // net::AddressList, so it can be used with the cache.
68 int rv
= net::ParseAddressList(ip_literal
, hostname
, &address_list
);
69 ASSERT_EQ(net::OK
, rv
);
71 ASSERT_TRUE(ip_literal
.empty());
74 // Add entry to the cache.
75 cache
->Set(net::HostCache::Key(hostname
, net::ADDRESS_FAMILY_UNSPECIFIED
, 0),
76 net::HostCache::Entry(net_error
, address_list
),
77 base::TimeTicks::Now(),
81 // Called on IO thread. Adds an entry to the list of known HTTP pipelining
83 void AddDummyHttpPipelineFeedbackOnIOThread(
84 net::URLRequestContextGetter
* context_getter
,
85 const std::string
& hostname
,
87 net::HttpPipelinedHostCapability capability
) {
88 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
89 net::URLRequestContext
* context
= context_getter
->GetURLRequestContext();
90 net::HttpNetworkSession
* http_network_session
=
91 context
->http_transaction_factory()->GetSession();
92 base::WeakPtr
<net::HttpServerProperties
> http_server_properties
=
93 http_network_session
->http_server_properties();
94 net::HostPortPair
origin(hostname
, port
);
95 http_server_properties
->SetPipelineCapability(origin
, capability
);
98 // Called on IO thread. Adds an entry to the list of known HTTP pipelining
100 void EnableHttpPipeliningOnIOThread(
101 net::URLRequestContextGetter
* context_getter
, bool enable
) {
102 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
103 net::URLRequestContext
* context
= context_getter
->GetURLRequestContext();
104 net::HttpNetworkSession
* http_network_session
=
105 context
->http_transaction_factory()->GetSession();
106 http_network_session
->set_http_pipelining_enabled(enable
);
111 ////////////////////////////////////////////////////////////////////////////////
112 // NetInternalsTest::MessageHandler
113 ////////////////////////////////////////////////////////////////////////////////
115 // Class to handle messages from the renderer needed by certain tests.
116 class NetInternalsTest::MessageHandler
: public content::WebUIMessageHandler
{
118 explicit MessageHandler(NetInternalsTest
* net_internals_test
);
121 virtual void RegisterMessages() OVERRIDE
;
123 // Runs NetInternalsTest.callback with the given value.
124 void RunJavascriptCallback(base::Value
* value
);
126 // Takes a string and provides the corresponding URL from the test server,
127 // which must already have been started.
128 void GetTestServerURL(const base::ListValue
* list_value
);
130 // Called on UI thread. Adds an entry to the cache for the specified
131 // hostname by posting a task to the IO thread. Takes the host name,
132 // ip address, net error code, and expiration time in days from now
133 // as parameters. If the error code indicates failure, the ip address
134 // must be an empty string.
135 void AddCacheEntry(const base::ListValue
* list_value
);
137 // Opens the given URL in a new tab.
138 void LoadPage(const base::ListValue
* list_value
);
140 // Opens a page in a new tab that prerenders the given URL.
141 void PrerenderPage(const base::ListValue
* list_value
);
143 // Navigates to the prerender in the background tab. This assumes that
144 // there is a "Click()" function in the background tab which will navigate
145 // there, and that the background tab exists at slot 1.
146 void NavigateToPrerender(const base::ListValue
* list_value
);
148 // Creates an incognito browser. Once creation is complete, passes a
149 // message to the Javascript test harness.
150 void CreateIncognitoBrowser(const base::ListValue
* list_value
);
152 // Closes an incognito browser created with CreateIncognitoBrowser.
153 void CloseIncognitoBrowser(const base::ListValue
* list_value
);
155 // Takes in a boolean and enables/disabled HTTP pipelining accordingly.
156 void EnableHttpPipelining(const base::ListValue
* list_value
);
158 // Called on UI thread. Adds an entry to the list of known HTTP pipelining
160 void AddDummyHttpPipelineFeedback(const base::ListValue
* list_value
);
162 // Creates a simple log with a NetLogLogger, and returns it to the
163 // Javascript callback.
164 void GetNetLogLoggerLog(const base::ListValue
* list_value
);
166 Browser
* browser() { return net_internals_test_
->browser(); }
168 NetInternalsTest
* net_internals_test_
;
169 Browser
* incognito_browser_
;
171 DISALLOW_COPY_AND_ASSIGN(MessageHandler
);
174 NetInternalsTest::MessageHandler::MessageHandler(
175 NetInternalsTest
* net_internals_test
)
176 : net_internals_test_(net_internals_test
),
177 incognito_browser_(NULL
) {
180 void NetInternalsTest::MessageHandler::RegisterMessages() {
181 web_ui()->RegisterMessageCallback("getTestServerURL",
182 base::Bind(&NetInternalsTest::MessageHandler::GetTestServerURL
,
183 base::Unretained(this)));
184 web_ui()->RegisterMessageCallback("addCacheEntry",
185 base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry
,
186 base::Unretained(this)));
187 web_ui()->RegisterMessageCallback("loadPage",
188 base::Bind(&NetInternalsTest::MessageHandler::LoadPage
,
189 base::Unretained(this)));
190 web_ui()->RegisterMessageCallback("prerenderPage",
191 base::Bind(&NetInternalsTest::MessageHandler::PrerenderPage
,
192 base::Unretained(this)));
193 web_ui()->RegisterMessageCallback("navigateToPrerender",
194 base::Bind(&NetInternalsTest::MessageHandler::NavigateToPrerender
,
195 base::Unretained(this)));
196 web_ui()->RegisterMessageCallback("createIncognitoBrowser",
197 base::Bind(&NetInternalsTest::MessageHandler::CreateIncognitoBrowser
,
198 base::Unretained(this)));
199 web_ui()->RegisterMessageCallback("closeIncognitoBrowser",
200 base::Bind(&NetInternalsTest::MessageHandler::CloseIncognitoBrowser
,
201 base::Unretained(this)));
202 web_ui()->RegisterMessageCallback("enableHttpPipelining",
203 base::Bind(&NetInternalsTest::MessageHandler::EnableHttpPipelining
,
204 base::Unretained(this)));
205 web_ui()->RegisterMessageCallback("addDummyHttpPipelineFeedback",
207 &NetInternalsTest::MessageHandler::AddDummyHttpPipelineFeedback
,
208 base::Unretained(this)));
209 web_ui()->RegisterMessageCallback("getNetLogLoggerLog",
211 &NetInternalsTest::MessageHandler::GetNetLogLoggerLog
,
212 base::Unretained(this)));
215 void NetInternalsTest::MessageHandler::RunJavascriptCallback(
216 base::Value
* value
) {
217 web_ui()->CallJavascriptFunction("NetInternalsTest.callback", *value
);
220 void NetInternalsTest::MessageHandler::GetTestServerURL(
221 const base::ListValue
* list_value
) {
222 ASSERT_TRUE(net_internals_test_
->StartTestServer());
224 ASSERT_TRUE(list_value
->GetString(0, &path
));
225 GURL url
= net_internals_test_
->test_server()->GetURL(path
);
226 scoped_ptr
<base::Value
> url_value(base::Value::CreateStringValue(url
.spec()));
227 RunJavascriptCallback(url_value
.get());
230 void NetInternalsTest::MessageHandler::AddCacheEntry(
231 const base::ListValue
* list_value
) {
232 std::string hostname
;
233 std::string ip_literal
;
235 double expire_days_from_now
;
236 ASSERT_TRUE(list_value
->GetString(0, &hostname
));
237 ASSERT_TRUE(list_value
->GetString(1, &ip_literal
));
238 ASSERT_TRUE(list_value
->GetDouble(2, &net_error
));
239 ASSERT_TRUE(list_value
->GetDouble(3, &expire_days_from_now
));
240 ASSERT_TRUE(browser());
242 BrowserThread::PostTask(
243 BrowserThread::IO
, FROM_HERE
,
244 base::Bind(&AddCacheEntryOnIOThread
,
245 make_scoped_refptr(browser()->profile()->GetRequestContext()),
248 static_cast<int>(net_error
),
249 static_cast<int>(expire_days_from_now
)));
252 void NetInternalsTest::MessageHandler::LoadPage(
253 const base::ListValue
* list_value
) {
255 ASSERT_TRUE(list_value
->GetString(0, &url
));
256 LOG(WARNING
) << "url: [" << url
<< "]";
257 ui_test_utils::NavigateToURLWithDisposition(
261 ui_test_utils::BROWSER_TEST_NONE
);
264 void NetInternalsTest::MessageHandler::PrerenderPage(
265 const base::ListValue
* list_value
) {
266 std::string prerender_url
;
267 ASSERT_TRUE(list_value
->GetString(0, &prerender_url
));
269 net_internals_test_
->CreatePrerenderLoaderUrl(GURL(prerender_url
));
270 ui_test_utils::NavigateToURLWithDisposition(
274 ui_test_utils::BROWSER_TEST_NONE
);
277 void NetInternalsTest::MessageHandler::NavigateToPrerender(
278 const base::ListValue
* list_value
) {
280 ASSERT_TRUE(list_value
->GetString(0, &url
));
281 content::RenderViewHost
* host
=
282 browser()->tab_strip_model()->GetWebContentsAt(1)->GetRenderViewHost();
283 host
->ExecuteJavascriptInWebFrame(
285 base::ASCIIToUTF16(base::StringPrintf("Click('%s')", url
.c_str())));
288 void NetInternalsTest::MessageHandler::CreateIncognitoBrowser(
289 const base::ListValue
* list_value
) {
290 ASSERT_FALSE(incognito_browser_
);
291 incognito_browser_
= net_internals_test_
->CreateIncognitoBrowser();
293 // Tell the test harness that creation is complete.
294 base::StringValue
command_value("onIncognitoBrowserCreatedForTest");
295 web_ui()->CallJavascriptFunction("g_browser.receive", command_value
);
298 void NetInternalsTest::MessageHandler::CloseIncognitoBrowser(
299 const base::ListValue
* list_value
) {
300 ASSERT_TRUE(incognito_browser_
);
301 incognito_browser_
->tab_strip_model()->CloseAllTabs();
302 // Closing all a Browser's tabs will ultimately result in its destruction,
303 // thought it may not have been destroyed yet.
304 incognito_browser_
= NULL
;
307 void NetInternalsTest::MessageHandler::EnableHttpPipelining(
308 const base::ListValue
* list_value
) {
310 ASSERT_TRUE(list_value
->GetBoolean(0, &enable
));
311 BrowserThread::PostTask(
312 BrowserThread::IO
, FROM_HERE
,
313 base::Bind(&EnableHttpPipeliningOnIOThread
,
314 make_scoped_refptr(browser()->profile()->GetRequestContext()),
318 void NetInternalsTest::MessageHandler::AddDummyHttpPipelineFeedback(
319 const base::ListValue
* list_value
) {
320 std::string hostname
;
322 std::string raw_capability
;
323 net::HttpPipelinedHostCapability capability
;
324 ASSERT_TRUE(list_value
->GetString(0, &hostname
));
325 ASSERT_TRUE(list_value
->GetDouble(1, &port
));
326 ASSERT_TRUE(list_value
->GetString(2, &raw_capability
));
327 if (raw_capability
== "capable") {
328 capability
= net::PIPELINE_CAPABLE
;
329 } else if (raw_capability
== "incapable") {
330 capability
= net::PIPELINE_INCAPABLE
;
332 FAIL() << "Unexpected capability string: " << raw_capability
;
334 BrowserThread::PostTask(
335 BrowserThread::IO
, FROM_HERE
,
336 base::Bind(&AddDummyHttpPipelineFeedbackOnIOThread
,
337 make_scoped_refptr(browser()->profile()->GetRequestContext()),
339 static_cast<int>(port
),
343 void NetInternalsTest::MessageHandler::GetNetLogLoggerLog(
344 const base::ListValue
* list_value
) {
345 base::ScopedTempDir temp_directory
;
346 ASSERT_TRUE(temp_directory
.CreateUniqueTempDir());
347 base::FilePath temp_file
;
348 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_directory
.path(),
350 FILE* temp_file_handle
= base::OpenFile(temp_file
, "w");
351 ASSERT_TRUE(temp_file_handle
);
353 scoped_ptr
<base::Value
> constants(NetInternalsUI::GetConstants());
354 scoped_ptr
<net::NetLogLogger
> net_log_logger(new net::NetLogLogger(
355 temp_file_handle
, *constants
));
356 net_log_logger
->StartObserving(g_browser_process
->net_log());
357 g_browser_process
->net_log()->AddGlobalEntry(
358 net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED
);
359 net::BoundNetLog bound_net_log
= net::BoundNetLog::Make(
360 g_browser_process
->net_log(),
361 net::NetLog::SOURCE_URL_REQUEST
);
362 bound_net_log
.BeginEvent(net::NetLog::TYPE_REQUEST_ALIVE
);
363 net_log_logger
->StopObserving();
364 net_log_logger
.reset();
366 std::string log_contents
;
367 ASSERT_TRUE(base::ReadFileToString(temp_file
, &log_contents
));
368 ASSERT_GT(log_contents
.length(), 0u);
370 scoped_ptr
<base::Value
> log_contents_value(
371 new base::StringValue(log_contents
));
372 RunJavascriptCallback(log_contents_value
.get());
375 ////////////////////////////////////////////////////////////////////////////////
377 ////////////////////////////////////////////////////////////////////////////////
379 NetInternalsTest::NetInternalsTest()
380 : test_server_started_(false) {
381 message_handler_
.reset(new MessageHandler(this));
384 NetInternalsTest::~NetInternalsTest() {
387 void NetInternalsTest::SetUpCommandLine(CommandLine
* command_line
) {
388 WebUIBrowserTest::SetUpCommandLine(command_line
);
389 // Needed to test the prerender view.
390 command_line
->AppendSwitchASCII(switches::kPrerenderMode
,
391 switches::kPrerenderModeSwitchValueEnabled
);
394 void NetInternalsTest::SetUpOnMainThread() {
395 WebUIBrowserTest::SetUpOnMainThread();
396 // Increase the memory allowed in a prerendered page above normal settings,
397 // as debug builds use more memory and often go over the usual limit.
398 Profile
* profile
= browser()->profile();
399 prerender::PrerenderManager
* prerender_manager
=
400 prerender::PrerenderManagerFactory::GetForProfile(profile
);
401 prerender_manager
->mutable_config().max_bytes
= 1000 * 1024 * 1024;
404 content::WebUIMessageHandler
* NetInternalsTest::GetMockMessageHandler() {
405 return message_handler_
.get();
408 GURL
NetInternalsTest::CreatePrerenderLoaderUrl(
409 const GURL
& prerender_url
) {
410 EXPECT_TRUE(StartTestServer());
411 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
412 replacement_text
.push_back(
413 make_pair("REPLACE_WITH_PRERENDER_URL", prerender_url
.spec()));
414 std::string replacement_path
;
415 EXPECT_TRUE(net::SpawnedTestServer::GetFilePathWithReplacements(
416 "files/prerender/prerender_loader.html",
419 GURL url_loader
= test_server()->GetURL(replacement_path
);
423 bool NetInternalsTest::StartTestServer() {
424 if (test_server_started_
)
426 test_server_started_
= test_server()->Start();
427 return test_server_started_
;