Home | History | Annotate | Download | only in loader
      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/web_contents.h"
     13 #include "content/public/common/url_constants.h"
     14 #include "content/public/test/browser_test_utils.h"
     15 #include "content/public/test/content_browser_test.h"
     16 #include "content/public/test/content_browser_test_utils.h"
     17 #include "content/public/test/test_utils.h"
     18 #include "content/shell/browser/shell.h"
     19 #include "content/shell/browser/shell_content_browser_client.h"
     20 #include "content/shell/browser/shell_network_delegate.h"
     21 #include "content/test/net/url_request_failed_job.h"
     22 #include "content/test/net/url_request_mock_http_job.h"
     23 #include "net/base/net_errors.h"
     24 #include "net/test/embedded_test_server/embedded_test_server.h"
     25 #include "net/test/embedded_test_server/http_request.h"
     26 #include "net/test/embedded_test_server/http_response.h"
     27 
     28 using base::ASCIIToUTF16;
     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     base::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, base::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   base::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   base::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(url::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   // Make sure we have a live process before trying to kill it.
    305   NavigateToURL(shell(), GURL("about:blank"));
    306 
    307   // Cause the renderer to crash.
    308   RenderProcessHostWatcher crash_observer(
    309       shell()->web_contents(),
    310       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
    311   NavigateToURL(shell(), GURL(kChromeUICrashURL));
    312   // Wait for browser to notice the renderer crash.
    313   crash_observer.Wait();
    314 
    315   // Navigate to a new cross-site page.  The browser should not wait around for
    316   // the old renderer's on{before}unload handlers to run.
    317   CheckTitleTest(GetMockURL("content-sniffer-test0.html"),
    318                  "Content Sniffer Test 0");
    319 }
    320 #endif  // !defined(OS_MACOSX)
    321 
    322 // Tests that cross-site navigations work when the new page does not go through
    323 // the BufferedEventHandler (e.g., non-http{s} URLs).  (Bug 1225872)
    324 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
    325                        CrossSiteNavigationNonBuffered) {
    326   // Start with an HTTP page.
    327   CheckTitleTest(GetMockURL("content-sniffer-test0.html"),
    328                  "Content Sniffer Test 0");
    329 
    330   // Now load a file:// page, which does not use the BufferedEventHandler.
    331   // Make sure that the page loads and displays a title, and doesn't get stuck.
    332   GURL url = GetTestUrl("", "title2.html");
    333   CheckTitleTest(url, "Title Of Awesomeness");
    334 }
    335 
    336 // Tests that a cross-site navigation to an error page (resulting in the link
    337 // doctor page) still runs the onunload handler and can support navigations
    338 // away from the link doctor page.  (Bug 1235537)
    339 // Flaky: http://crbug.com/100823
    340 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
    341                        CrossSiteNavigationErrorPage) {
    342   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    343 
    344   GURL url(embedded_test_server()->GetURL("/onunload_cookie.html"));
    345   CheckTitleTest(url, "set cookie on unload");
    346 
    347   // Navigate to a new cross-site URL that results in an error.
    348   // TODO(creis): If this causes crashes or hangs, it might be for the same
    349   // reason as ErrorPageTest::DNSError.  See bug 1199491 and
    350   // http://crbug.com/22877.
    351   GURL failed_url = URLRequestFailedJob::GetMockHttpUrl(
    352       net::ERR_NAME_NOT_RESOLVED);
    353   NavigateToURL(shell(), failed_url);
    354 
    355   EXPECT_NE(ASCIIToUTF16("set cookie on unload"),
    356             shell()->web_contents()->GetTitle());
    357 
    358   // Check that the cookie was set, meaning that the onunload handler ran.
    359   EXPECT_EQ("onunloadCookie=foo", GetCookies(url));
    360 
    361   // Check that renderer-initiated navigations still work.  In a previous bug,
    362   // the ResourceDispatcherHost would think that such navigations were
    363   // cross-site, because we didn't clean up from the previous request.  Since
    364   // WebContentsImpl was in the NORMAL state, it would ignore the attempt to run
    365   // the onunload handler, and the navigation would fail. We can't test by
    366   // redirecting to javascript:window.location='someURL', since javascript:
    367   // URLs are prohibited by policy from interacting with sensitive chrome
    368   // pages of which the error page is one.  Instead, use automation to kick
    369   // off the navigation, and wait to see that the tab loads.
    370   base::string16 expected_title16(ASCIIToUTF16("Title Of Awesomeness"));
    371   TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
    372 
    373   bool success;
    374   GURL test_url(embedded_test_server()->GetURL("/title2.html"));
    375   std::string redirect_script = "window.location='" +
    376       test_url.possibly_invalid_spec() + "';" +
    377       "window.domAutomationController.send(true);";
    378   EXPECT_TRUE(ExecuteScriptAndExtractBool(
    379       shell()->web_contents(),
    380       redirect_script,
    381       &success));
    382   EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
    383 }
    384 
    385 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
    386                        CrossSiteNavigationErrorPage2) {
    387   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    388 
    389   GURL url(embedded_test_server()->GetURL("/title2.html"));
    390   CheckTitleTest(url, "Title Of Awesomeness");
    391 
    392   // Navigate to a new cross-site URL that results in an error.
    393   // TODO(creis): If this causes crashes or hangs, it might be for the same
    394   // reason as ErrorPageTest::DNSError.  See bug 1199491 and
    395   // http://crbug.com/22877.
    396   GURL failed_url = URLRequestFailedJob::GetMockHttpUrl(
    397       net::ERR_NAME_NOT_RESOLVED);
    398 
    399   NavigateToURL(shell(), failed_url);
    400   EXPECT_NE(ASCIIToUTF16("Title Of Awesomeness"),
    401             shell()->web_contents()->GetTitle());
    402 
    403   // Repeat navigation.  We are testing that this completes.
    404   NavigateToURL(shell(), failed_url);
    405   EXPECT_NE(ASCIIToUTF16("Title Of Awesomeness"),
    406             shell()->web_contents()->GetTitle());
    407 }
    408 
    409 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
    410                        CrossOriginRedirectBlocked) {
    411   // We expect the following URL requests from this test:
    412   // 1-  http://mock.http/cross-origin-redirect-blocked.html
    413   // 2-  http://mock.http/redirect-to-title2.html
    414   // 3-  http://mock.http/title2.html
    415   //
    416   // If the redirect in #2 were not blocked, we'd also see a request
    417   // for http://mock.http:4000/title2.html, and the title would be different.
    418   CheckTitleTest(GetMockURL("cross-origin-redirect-blocked.html"),
    419                  "Title Of More Awesomeness");
    420 }
    421 
    422 // Tests that ResourceRequestInfoImpl is updated correctly on failed
    423 // requests, to prevent calling Read on a request that has already failed.
    424 // See bug 40250.
    425 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
    426                        CrossSiteFailedRequest) {
    427   // Visit another URL first to trigger a cross-site navigation.
    428   NavigateToURL(shell(), GetTestUrl("", "simple_page.html"));
    429 
    430   // Visit a URL that fails without calling ResourceDispatcherHost::Read.
    431   GURL broken_url("chrome://theme");
    432   NavigateToURL(shell(), broken_url);
    433 }
    434 
    435 namespace {
    436 
    437 scoped_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
    438     const std::string& request_path,
    439     const net::test_server::HttpRequest& request) {
    440   if (!StartsWithASCII(request.relative_url, request_path, true))
    441     return scoped_ptr<net::test_server::HttpResponse>();
    442 
    443   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
    444       new net::test_server::BasicHttpResponse);
    445   http_response->set_code(net::HTTP_FOUND);
    446   http_response->AddCustomHeader(
    447       "Location", request.relative_url.substr(request_path.length()));
    448   return http_response.PassAs<net::test_server::HttpResponse>();
    449 }
    450 
    451 }  // namespace
    452 
    453 // Test that we update the cookie policy URLs correctly when transferring
    454 // navigations.
    455 IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, CookiePolicy) {
    456   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    457   embedded_test_server()->RegisterRequestHandler(
    458       base::Bind(&HandleRedirectRequest, "/redirect?"));
    459 
    460   std::string set_cookie_url(base::StringPrintf(
    461       "http://localhost:%d/set_cookie.html", embedded_test_server()->port()));
    462   GURL url(embedded_test_server()->GetURL("/redirect?" + set_cookie_url));
    463 
    464   ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
    465   ShellNetworkDelegate::SetAcceptAllCookies(false);
    466 
    467   CheckTitleTest(url, "cookie set");
    468 }
    469 
    470 }  // namespace content
    471