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/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