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