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 "base/strings/string_util.h" 6 #include "base/strings/stringprintf.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "content/browser/download/download_manager_impl.h" 9 #include "content/browser/web_contents/web_contents_impl.h" 10 #include "content/public/browser/browser_context.h" 11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/notification_service.h" 13 #include "content/public/browser/notification_types.h" 14 #include "content/public/browser/web_contents.h" 15 #include "content/public/common/url_constants.h" 16 #include "content/public/test/browser_test_utils.h" 17 #include "content/public/test/test_utils.h" 18 #include "content/shell/shell.h" 19 #include "content/shell/shell_content_browser_client.h" 20 #include "content/shell/shell_network_delegate.h" 21 #include "content/test/content_browser_test.h" 22 #include "content/test/content_browser_test_utils.h" 23 #include "content/test/net/url_request_failed_job.h" 24 #include "content/test/net/url_request_mock_http_job.h" 25 #include "net/base/net_errors.h" 26 #include "net/test/embedded_test_server/embedded_test_server.h" 27 #include "net/test/embedded_test_server/http_request.h" 28 #include "net/test/embedded_test_server/http_response.h" 29 30 namespace content { 31 32 class ResourceDispatcherHostBrowserTest : public ContentBrowserTest, 33 public DownloadManager::Observer { 34 public: 35 ResourceDispatcherHostBrowserTest() : got_downloads_(false) {} 36 37 protected: 38 virtual void SetUpOnMainThread() OVERRIDE { 39 base::FilePath path = GetTestFilePath("", ""); 40 BrowserThread::PostTask( 41 BrowserThread::IO, FROM_HERE, 42 base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, path)); 43 BrowserThread::PostTask( 44 BrowserThread::IO, FROM_HERE, 45 base::Bind(&URLRequestFailedJob::AddUrlHandler)); 46 } 47 48 virtual void OnDownloadCreated( 49 DownloadManager* manager, 50 DownloadItem* item) OVERRIDE { 51 if (!got_downloads_) 52 got_downloads_ = !!manager->InProgressCount(); 53 } 54 55 GURL GetMockURL(const std::string& file) { 56 return URLRequestMockHTTPJob::GetMockUrl( 57 base::FilePath().AppendASCII(file)); 58 } 59 60 void CheckTitleTest(const GURL& url, 61 const std::string& expected_title) { 62 string16 expected_title16(ASCIIToUTF16(expected_title)); 63 TitleWatcher title_watcher(shell()->web_contents(), expected_title16); 64 NavigateToURL(shell(), url); 65 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle()); 66 } 67 68 bool GetPopupTitle(const GURL& url, string16* title) { 69 NavigateToURL(shell(), url); 70 71 ShellAddedObserver new_shell_observer; 72 73 // Create dynamic popup. 74 if (!ExecuteScript(shell()->web_contents(), "OpenPopup();")) 75 return false; 76 77 Shell* new_shell = new_shell_observer.GetShell(); 78 *title = new_shell->web_contents()->GetTitle(); 79 return true; 80 } 81 82 std::string GetCookies(const GURL& url) { 83 return content::GetCookies( 84 shell()->web_contents()->GetBrowserContext(), url); 85 } 86 87 bool got_downloads() const { return got_downloads_; } 88 89 private: 90 bool got_downloads_; 91 }; 92 93 // Test title for content created by javascript window.open(). 94 // See http://crbug.com/5988 95 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, DynamicTitle1) { 96 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 97 98 GURL url(embedded_test_server()->GetURL("/dynamic1.html")); 99 string16 title; 100 ASSERT_TRUE(GetPopupTitle(url, &title)); 101 EXPECT_TRUE(StartsWith(title, ASCIIToUTF16("My Popup Title"), true)) 102 << "Actual title: " << title; 103 } 104 105 // Test title for content created by javascript window.open(). 106 // See http://crbug.com/5988 107 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, DynamicTitle2) { 108 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 109 110 GURL url(embedded_test_server()->GetURL("/dynamic2.html")); 111 string16 title; 112 ASSERT_TRUE(GetPopupTitle(url, &title)); 113 EXPECT_TRUE(StartsWith(title, ASCIIToUTF16("My Dynamic Title"), true)) 114 << "Actual title: " << title; 115 } 116 117 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 118 SniffHTMLWithNoContentType) { 119 CheckTitleTest(GetMockURL("content-sniffer-test0.html"), 120 "Content Sniffer Test 0"); 121 } 122 123 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 124 RespectNoSniffDirective) { 125 CheckTitleTest(GetMockURL("nosniff-test.html"), 126 "mock.http/nosniff-test.html"); 127 } 128 129 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 130 DoNotSniffHTMLFromTextPlain) { 131 CheckTitleTest(GetMockURL("content-sniffer-test1.html"), 132 "mock.http/content-sniffer-test1.html"); 133 } 134 135 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 136 DoNotSniffHTMLFromImageGIF) { 137 CheckTitleTest(GetMockURL("content-sniffer-test2.html"), 138 "mock.http/content-sniffer-test2.html"); 139 } 140 141 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 142 SniffNoContentTypeNoData) { 143 // Make sure no downloads start. 144 BrowserContext::GetDownloadManager( 145 shell()->web_contents()->GetBrowserContext())->AddObserver(this); 146 CheckTitleTest(GetMockURL("content-sniffer-test3.html"), 147 "Content Sniffer Test 3"); 148 EXPECT_EQ(1u, Shell::windows().size()); 149 ASSERT_FALSE(got_downloads()); 150 } 151 152 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 153 ContentDispositionEmpty) { 154 CheckTitleTest(GetMockURL("content-disposition-empty.html"), "success"); 155 } 156 157 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 158 ContentDispositionInline) { 159 CheckTitleTest(GetMockURL("content-disposition-inline.html"), "success"); 160 } 161 162 // Test for bug #1091358. 163 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, SyncXMLHttpRequest) { 164 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 165 NavigateToURL( 166 shell(), embedded_test_server()->GetURL("/sync_xmlhttprequest.html")); 167 168 // Let's check the XMLHttpRequest ran successfully. 169 bool success = false; 170 EXPECT_TRUE(ExecuteScriptAndExtractBool( 171 shell()->web_contents(), 172 "window.domAutomationController.send(DidSyncRequestSucceed());", 173 &success)); 174 EXPECT_TRUE(success); 175 } 176 177 // If this flakes, use http://crbug.com/62776. 178 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 179 SyncXMLHttpRequest_Disallowed) { 180 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 181 NavigateToURL( 182 shell(), 183 embedded_test_server()->GetURL("/sync_xmlhttprequest_disallowed.html")); 184 185 // Let's check the XMLHttpRequest ran successfully. 186 bool success = false; 187 EXPECT_TRUE(ExecuteScriptAndExtractBool( 188 shell()->web_contents(), 189 "window.domAutomationController.send(DidSucceed());", 190 &success)); 191 EXPECT_TRUE(success); 192 } 193 194 // Test for bug #1159553 -- A synchronous xhr (whose content-type is 195 // downloadable) would trigger download and hang the renderer process, 196 // if executed while navigating to a new page. 197 // Disabled on Mac: see http://crbug.com/56264 198 #if defined(OS_MACOSX) 199 #define MAYBE_SyncXMLHttpRequest_DuringUnload \ 200 DISABLED_SyncXMLHttpRequest_DuringUnload 201 #else 202 #define MAYBE_SyncXMLHttpRequest_DuringUnload SyncXMLHttpRequest_DuringUnload 203 #endif 204 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 205 MAYBE_SyncXMLHttpRequest_DuringUnload) { 206 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 207 BrowserContext::GetDownloadManager( 208 shell()->web_contents()->GetBrowserContext())->AddObserver(this); 209 210 CheckTitleTest( 211 embedded_test_server()->GetURL("/sync_xmlhttprequest_during_unload.html"), 212 "sync xhr on unload"); 213 214 // Navigate to a new page, to dispatch unload event and trigger xhr. 215 // (the bug would make this step hang the renderer). 216 CheckTitleTest( 217 embedded_test_server()->GetURL("/title2.html"), "Title Of Awesomeness"); 218 219 ASSERT_FALSE(got_downloads()); 220 } 221 222 // Tests that onunload is run for cross-site requests. (Bug 1114994) 223 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 224 CrossSiteOnunloadCookie) { 225 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 226 227 GURL url = embedded_test_server()->GetURL("/onunload_cookie.html"); 228 CheckTitleTest(url, "set cookie on unload"); 229 230 // Navigate to a new cross-site page, to dispatch unload event and set the 231 // cookie. 232 CheckTitleTest(GetMockURL("content-sniffer-test0.html"), 233 "Content Sniffer Test 0"); 234 235 // Check that the cookie was set. 236 EXPECT_EQ("onunloadCookie=foo", GetCookies(url)); 237 } 238 239 // If this flakes, use http://crbug.com/130404 240 // Tests that onunload is run for cross-site requests to URLs that complete 241 // without network loads (e.g., about:blank, data URLs). 242 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 243 DISABLED_CrossSiteImmediateLoadOnunloadCookie) { 244 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 245 246 GURL url = embedded_test_server()->GetURL("/onunload_cookie.html"); 247 CheckTitleTest(url, "set cookie on unload"); 248 249 // Navigate to a cross-site page that loads immediately without making a 250 // network request. The unload event should still be run. 251 NavigateToURL(shell(), GURL(kAboutBlankURL)); 252 253 // Check that the cookie was set. 254 EXPECT_EQ("onunloadCookie=foo", GetCookies(url)); 255 } 256 257 namespace { 258 259 // Handles |request| by serving a redirect response. 260 scoped_ptr<net::test_server::HttpResponse> NoContentResponseHandler( 261 const std::string& path, 262 const net::test_server::HttpRequest& request) { 263 if (!StartsWithASCII(path, request.relative_url, true)) 264 return scoped_ptr<net::test_server::HttpResponse>(); 265 266 scoped_ptr<net::test_server::BasicHttpResponse> http_response( 267 new net::test_server::BasicHttpResponse); 268 http_response->set_code(net::HTTP_NO_CONTENT); 269 return http_response.PassAs<net::test_server::HttpResponse>(); 270 } 271 272 } // namespace 273 274 // Tests that the unload handler is not run for 204 responses. 275 // If this flakes use http://crbug.com/80596. 276 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 277 CrossSiteNoUnloadOn204) { 278 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 279 280 // Start with a URL that sets a cookie in its unload handler. 281 GURL url = embedded_test_server()->GetURL("/onunload_cookie.html"); 282 CheckTitleTest(url, "set cookie on unload"); 283 284 // Navigate to a cross-site URL that returns a 204 No Content response. 285 const char kNoContentPath[] = "/nocontent"; 286 embedded_test_server()->RegisterRequestHandler( 287 base::Bind(&NoContentResponseHandler, kNoContentPath)); 288 NavigateToURL(shell(), embedded_test_server()->GetURL(kNoContentPath)); 289 290 // Check that the unload cookie was not set. 291 EXPECT_EQ("", GetCookies(url)); 292 } 293 294 #if !defined(OS_MACOSX) 295 // Tests that the onbeforeunload and onunload logic is short-circuited if the 296 // old renderer is gone. In that case, we don't want to wait for the old 297 // renderer to run the handlers. 298 // We need to disable this on Mac because the crash causes the OS CrashReporter 299 // process to kick in to analyze the poor dead renderer. Unfortunately, if the 300 // app isn't stripped of debug symbols, this takes about five minutes to 301 // complete and isn't conducive to quick turnarounds. As we don't currently 302 // strip the app on the build bots, this is bad times. 303 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, CrossSiteAfterCrash) { 304 // Cause the renderer to crash. 305 WindowedNotificationObserver crash_observer( 306 NOTIFICATION_RENDERER_PROCESS_CLOSED, 307 NotificationService::AllSources()); 308 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 309 // Wait for browser to notice the renderer crash. 310 crash_observer.Wait(); 311 312 // Navigate to a new cross-site page. The browser should not wait around for 313 // the old renderer's on{before}unload handlers to run. 314 CheckTitleTest(GetMockURL("content-sniffer-test0.html"), 315 "Content Sniffer Test 0"); 316 } 317 #endif // !defined(OS_MACOSX) 318 319 // Tests that cross-site navigations work when the new page does not go through 320 // the BufferedEventHandler (e.g., non-http{s} URLs). (Bug 1225872) 321 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 322 CrossSiteNavigationNonBuffered) { 323 // Start with an HTTP page. 324 CheckTitleTest(GetMockURL("content-sniffer-test0.html"), 325 "Content Sniffer Test 0"); 326 327 // Now load a file:// page, which does not use the BufferedEventHandler. 328 // Make sure that the page loads and displays a title, and doesn't get stuck. 329 GURL url = GetTestUrl("", "title2.html"); 330 CheckTitleTest(url, "Title Of Awesomeness"); 331 } 332 333 // Tests that a cross-site navigation to an error page (resulting in the link 334 // doctor page) still runs the onunload handler and can support navigations 335 // away from the link doctor page. (Bug 1235537) 336 // Flaky: http://crbug.com/100823 337 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 338 CrossSiteNavigationErrorPage) { 339 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 340 341 GURL url(embedded_test_server()->GetURL("/onunload_cookie.html")); 342 CheckTitleTest(url, "set cookie on unload"); 343 344 // Navigate to a new cross-site URL that results in an error. 345 // TODO(creis): If this causes crashes or hangs, it might be for the same 346 // reason as ErrorPageTest::DNSError. See bug 1199491 and 347 // http://crbug.com/22877. 348 GURL failed_url = URLRequestFailedJob::GetMockHttpUrl( 349 net::ERR_NAME_NOT_RESOLVED); 350 NavigateToURL(shell(), failed_url); 351 352 EXPECT_NE(ASCIIToUTF16("set cookie on unload"), 353 shell()->web_contents()->GetTitle()); 354 355 // Check that the cookie was set, meaning that the onunload handler ran. 356 EXPECT_EQ("onunloadCookie=foo", GetCookies(url)); 357 358 // Check that renderer-initiated navigations still work. In a previous bug, 359 // the ResourceDispatcherHost would think that such navigations were 360 // cross-site, because we didn't clean up from the previous request. Since 361 // WebContentsImpl was in the NORMAL state, it would ignore the attempt to run 362 // the onunload handler, and the navigation would fail. We can't test by 363 // redirecting to javascript:window.location='someURL', since javascript: 364 // URLs are prohibited by policy from interacting with sensitive chrome 365 // pages of which the error page is one. Instead, use automation to kick 366 // off the navigation, and wait to see that the tab loads. 367 string16 expected_title16(ASCIIToUTF16("Title Of Awesomeness")); 368 TitleWatcher title_watcher(shell()->web_contents(), expected_title16); 369 370 bool success; 371 GURL test_url(embedded_test_server()->GetURL("/title2.html")); 372 std::string redirect_script = "window.location='" + 373 test_url.possibly_invalid_spec() + "';" + 374 "window.domAutomationController.send(true);"; 375 EXPECT_TRUE(ExecuteScriptAndExtractBool( 376 shell()->web_contents(), 377 redirect_script, 378 &success)); 379 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle()); 380 } 381 382 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 383 CrossSiteNavigationErrorPage2) { 384 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 385 386 GURL url(embedded_test_server()->GetURL("/title2.html")); 387 CheckTitleTest(url, "Title Of Awesomeness"); 388 389 // Navigate to a new cross-site URL that results in an error. 390 // TODO(creis): If this causes crashes or hangs, it might be for the same 391 // reason as ErrorPageTest::DNSError. See bug 1199491 and 392 // http://crbug.com/22877. 393 GURL failed_url = URLRequestFailedJob::GetMockHttpUrl( 394 net::ERR_NAME_NOT_RESOLVED); 395 396 NavigateToURL(shell(), failed_url); 397 EXPECT_NE(ASCIIToUTF16("Title Of Awesomeness"), 398 shell()->web_contents()->GetTitle()); 399 400 // Repeat navigation. We are testing that this completes. 401 NavigateToURL(shell(), failed_url); 402 EXPECT_NE(ASCIIToUTF16("Title Of Awesomeness"), 403 shell()->web_contents()->GetTitle()); 404 } 405 406 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 407 CrossOriginRedirectBlocked) { 408 // We expect the following URL requests from this test: 409 // 1- http://mock.http/cross-origin-redirect-blocked.html 410 // 2- http://mock.http/redirect-to-title2.html 411 // 3- http://mock.http/title2.html 412 // 413 // If the redirect in #2 were not blocked, we'd also see a request 414 // for http://mock.http:4000/title2.html, and the title would be different. 415 CheckTitleTest(GetMockURL("cross-origin-redirect-blocked.html"), 416 "Title Of More Awesomeness"); 417 } 418 419 // Tests that ResourceRequestInfoImpl is updated correctly on failed 420 // requests, to prevent calling Read on a request that has already failed. 421 // See bug 40250. 422 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, 423 CrossSiteFailedRequest) { 424 // Visit another URL first to trigger a cross-site navigation. 425 NavigateToURL(shell(), GetTestUrl("", "simple_page.html")); 426 427 // Visit a URL that fails without calling ResourceDispatcherHost::Read. 428 GURL broken_url("chrome://theme"); 429 NavigateToURL(shell(), broken_url); 430 } 431 432 namespace { 433 434 scoped_ptr<net::test_server::HttpResponse> HandleRedirectRequest( 435 const std::string& request_path, 436 const net::test_server::HttpRequest& request) { 437 if (!StartsWithASCII(request.relative_url, request_path, true)) 438 return scoped_ptr<net::test_server::HttpResponse>(); 439 440 scoped_ptr<net::test_server::BasicHttpResponse> http_response( 441 new net::test_server::BasicHttpResponse); 442 http_response->set_code(net::HTTP_FOUND); 443 http_response->AddCustomHeader( 444 "Location", request.relative_url.substr(request_path.length())); 445 return http_response.PassAs<net::test_server::HttpResponse>(); 446 } 447 448 } // namespace 449 450 // Test that we update the cookie policy URLs correctly when transferring 451 // navigations. 452 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, CookiePolicy) { 453 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 454 embedded_test_server()->RegisterRequestHandler( 455 base::Bind(&HandleRedirectRequest, "/redirect?")); 456 457 std::string set_cookie_url(base::StringPrintf( 458 "http://localhost:%d/set_cookie.html", embedded_test_server()->port())); 459 GURL url(embedded_test_server()->GetURL("/redirect?" + set_cookie_url)); 460 461 ShellContentBrowserClient::SetSwapProcessesForRedirect(true); 462 ShellNetworkDelegate::SetAcceptAllCookies(false); 463 464 CheckTitleTest(url, "cookie set"); 465 } 466 467 } // namespace content 468