Home | History | Annotate | Download | only in web_contents
      1 // Copyright 2014 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/command_line.h"
      6 #include "base/strings/stringprintf.h"
      7 #include "content/public/browser/web_contents.h"
      8 #include "content/public/browser/web_contents_delegate.h"
      9 #include "content/public/common/content_switches.h"
     10 #include "content/public/test/browser_test_utils.h"
     11 #include "content/public/test/content_browser_test.h"
     12 #include "content/public/test/content_browser_test_utils.h"
     13 #include "content/public/test/test_navigation_observer.h"
     14 #include "content/shell/browser/shell.h"
     15 #include "net/dns/mock_host_resolver.h"
     16 #include "url/gurl.h"
     17 
     18 namespace content {
     19 
     20 namespace {
     21 
     22 // A dummy WebContentsDelegate which tracks whether CloseContents() has been
     23 // called. It refuses the actual close but keeps track of whether the renderer
     24 // requested it.
     25 class CloseTrackingDelegate : public WebContentsDelegate {
     26  public:
     27   CloseTrackingDelegate() : close_contents_called_(false) {}
     28 
     29   bool close_contents_called() const { return close_contents_called_; }
     30 
     31   virtual void CloseContents(WebContents* source) OVERRIDE {
     32     close_contents_called_ = true;
     33   }
     34 
     35  private:
     36   bool close_contents_called_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(CloseTrackingDelegate);
     39 };
     40 
     41 }  // namespace
     42 
     43 class OpenedByDOMTest : public ContentBrowserTest {
     44  protected:
     45   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     46     // Use --site-per-process to force process swaps on cross-site navigations.
     47     command_line->AppendSwitch(switches::kSitePerProcess);
     48   }
     49 
     50   bool AttemptCloseFromJavaScript(WebContents* web_contents) {
     51     CloseTrackingDelegate close_tracking_delegate;
     52     WebContentsDelegate* old_delegate = web_contents->GetDelegate();
     53     web_contents->SetDelegate(&close_tracking_delegate);
     54 
     55     const char kCloseWindowScript[] =
     56         // Close the window.
     57         "window.close();"
     58         // Report back after an event loop iteration; the close IPC isn't sent
     59         // immediately.
     60         "setTimeout(function() {"
     61         "window.domAutomationController.send(0);"
     62         "});";
     63     int dummy;
     64     CHECK(ExecuteScriptAndExtractInt(web_contents, kCloseWindowScript, &dummy));
     65 
     66     web_contents->SetDelegate(old_delegate);
     67     return close_tracking_delegate.close_contents_called();
     68   }
     69 
     70   Shell* OpenWindowFromJavaScript(Shell* shell, const GURL& url) {
     71     // Wait for the popup to be created and for it to have navigated.
     72     ShellAddedObserver new_shell_observer;
     73     TestNavigationObserver nav_observer(NULL);
     74     nav_observer.StartWatchingNewWebContents();
     75     CHECK(ExecuteScript(
     76         shell->web_contents(),
     77         base::StringPrintf("window.open('%s')", url.spec().c_str())));
     78     nav_observer.Wait();
     79     return new_shell_observer.GetShell();
     80   }
     81 };
     82 
     83 // Tests that window.close() does not work on a normal window that has navigated
     84 // a few times.
     85 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, NormalWindow) {
     86   ASSERT_TRUE(test_server()->Start());
     87 
     88   // window.close is allowed if the window was opened by DOM OR the back/forward
     89   // list has only one element. Navigate a bit so the second condition is false.
     90   GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
     91   GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
     92   NavigateToURL(shell(), url1);
     93   NavigateToURL(shell(), url2);
     94 
     95   // This window was not opened by DOM, so close does not reach the browser
     96   // process.
     97   EXPECT_FALSE(AttemptCloseFromJavaScript(shell()->web_contents()));
     98 }
     99 
    100 // Tests that window.close() works in a popup window that has navigated a few
    101 // times.
    102 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, Popup) {
    103   ASSERT_TRUE(test_server()->Start());
    104 
    105   GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
    106   GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
    107   GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
    108   NavigateToURL(shell(), url1);
    109 
    110   Shell* popup = OpenWindowFromJavaScript(shell(), url2);
    111   NavigateToURL(popup, url3);
    112   EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
    113 }
    114 
    115 // Tests that window.close() works in a popup window that has navigated a few
    116 // times and swapped processes.
    117 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, CrossProcessPopup) {
    118   host_resolver()->AddRule("*", "127.0.0.1");
    119   ASSERT_TRUE(test_server()->Start());
    120 
    121   GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
    122 
    123   GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
    124   GURL::Replacements replace_host;
    125   std::string foo_com("foo.com");
    126   replace_host.SetHostStr(foo_com);
    127   url2 = url2.ReplaceComponents(replace_host);
    128 
    129   GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
    130   url3 = url3.ReplaceComponents(replace_host);
    131 
    132   NavigateToURL(shell(), url1);
    133 
    134   Shell* popup = OpenWindowFromJavaScript(shell(), url2);
    135   NavigateToURL(popup, url3);
    136   EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
    137 }
    138 
    139 }  // namespace content
    140