OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 "content/browser/child_process_security_policy_impl.h" |
| 7 #include "content/browser/web_contents/web_contents_impl.h" |
| 8 #include "content/public/browser/render_process_host.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_frame_navigation_observer.h" |
| 14 #include "content/public/test/test_navigation_observer.h" |
| 15 #include "content/public/test/test_utils.h" |
| 16 #include "content/shell/browser/shell.h" |
| 17 #include "content/test/content_browser_test_utils_internal.h" |
| 18 #include "net/dns/mock_host_resolver.h" |
| 19 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 20 #include "url/gurl.h" |
| 21 |
| 22 namespace content { |
| 23 |
| 24 class IsolatedOriginTest : public ContentBrowserTest { |
| 25 public: |
| 26 IsolatedOriginTest() {} |
| 27 ~IsolatedOriginTest() override {} |
| 28 |
| 29 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 30 ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| 31 |
| 32 std::string origin_list = |
| 33 embedded_test_server()->GetURL("isolated.foo.com", "/").spec() + "," + |
| 34 embedded_test_server()->GetURL("isolated.bar.com", "/").spec(); |
| 35 command_line->AppendSwitchASCII(switches::kIsolateOrigins, origin_list); |
| 36 } |
| 37 |
| 38 void SetUpOnMainThread() override { |
| 39 host_resolver()->AddRule("*", "127.0.0.1"); |
| 40 embedded_test_server()->StartAcceptingConnections(); |
| 41 } |
| 42 |
| 43 WebContentsImpl* web_contents() const { |
| 44 return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| 45 } |
| 46 }; |
| 47 |
| 48 // Check that navigating a main frame from an non-isolated origin to an |
| 49 // isolated origin and vice versa swaps processes and uses a new SiteInstance, |
| 50 // both for browser-initiated and renderer-initiated navigations. |
| 51 IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, MainFrameNavigation) { |
| 52 GURL unisolated_url( |
| 53 embedded_test_server()->GetURL("www.foo.com", "/title1.html")); |
| 54 GURL isolated_url( |
| 55 embedded_test_server()->GetURL("isolated.foo.com", "/title2.html")); |
| 56 |
| 57 EXPECT_TRUE(NavigateToURL(shell(), unisolated_url)); |
| 58 |
| 59 // Open a same-site popup to keep the www.foo.com process alive. |
| 60 Shell* popup = OpenPopup(shell(), GURL(url::kAboutBlankURL), "foo"); |
| 61 SiteInstance* unisolated_instance = |
| 62 popup->web_contents()->GetMainFrame()->GetSiteInstance(); |
| 63 RenderProcessHost* unisolated_process = |
| 64 popup->web_contents()->GetMainFrame()->GetProcess(); |
| 65 |
| 66 // Perform a browser-initiated navigation to an isolated origin and ensure |
| 67 // that this ends up in a new process and SiteInstance for isolated.foo.com. |
| 68 EXPECT_TRUE(NavigateToURL(shell(), isolated_url)); |
| 69 |
| 70 scoped_refptr<SiteInstance> isolated_instance = |
| 71 web_contents()->GetSiteInstance(); |
| 72 EXPECT_NE(isolated_instance, unisolated_instance); |
| 73 EXPECT_NE(web_contents()->GetMainFrame()->GetProcess(), unisolated_process); |
| 74 |
| 75 // The site URL for isolated.foo.com should be the full origin rather than |
| 76 // scheme and eTLD+1. |
| 77 EXPECT_EQ(isolated_url.GetOrigin(), isolated_instance->GetSiteURL()); |
| 78 |
| 79 // Now perform a renderer-initiated navigation to an unisolated origin, |
| 80 // www.foo.com. This should end up in the |popup|'s process. |
| 81 { |
| 82 TestNavigationObserver observer(web_contents()); |
| 83 EXPECT_TRUE(ExecuteScript( |
| 84 web_contents(), "location.href = '" + unisolated_url.spec() + "'")); |
| 85 observer.Wait(); |
| 86 } |
| 87 |
| 88 EXPECT_EQ(unisolated_instance, web_contents()->GetSiteInstance()); |
| 89 EXPECT_EQ(unisolated_process, web_contents()->GetMainFrame()->GetProcess()); |
| 90 |
| 91 // Go to isolated.foo.com again, this time with a renderer-initiated |
| 92 // navigation from the unisolated www.foo.com. |
| 93 { |
| 94 TestNavigationObserver observer(web_contents()); |
| 95 EXPECT_TRUE(ExecuteScript(web_contents(), |
| 96 "location.href = '" + isolated_url.spec() + "'")); |
| 97 observer.Wait(); |
| 98 } |
| 99 |
| 100 EXPECT_EQ(isolated_instance, web_contents()->GetSiteInstance()); |
| 101 EXPECT_NE(unisolated_process, web_contents()->GetMainFrame()->GetProcess()); |
| 102 |
| 103 // Go back to www.foo.com: this should end up in the unisolated process. |
| 104 { |
| 105 TestNavigationObserver back_observer(web_contents()); |
| 106 web_contents()->GetController().GoBack(); |
| 107 back_observer.Wait(); |
| 108 } |
| 109 |
| 110 EXPECT_EQ(unisolated_instance, web_contents()->GetSiteInstance()); |
| 111 EXPECT_EQ(unisolated_process, web_contents()->GetMainFrame()->GetProcess()); |
| 112 |
| 113 // Go back again. This should go to isolated.foo.com in an isolated process. |
| 114 { |
| 115 TestNavigationObserver back_observer(web_contents()); |
| 116 web_contents()->GetController().GoBack(); |
| 117 back_observer.Wait(); |
| 118 } |
| 119 |
| 120 EXPECT_EQ(isolated_instance, web_contents()->GetSiteInstance()); |
| 121 EXPECT_NE(unisolated_process, web_contents()->GetMainFrame()->GetProcess()); |
| 122 |
| 123 // Do a renderer-initiated navigation from isolated.foo.com to another |
| 124 // isolated origin and ensure there is a different isolated process. |
| 125 GURL second_isolated_url( |
| 126 embedded_test_server()->GetURL("isolated.bar.com", "/title3.html")); |
| 127 { |
| 128 TestNavigationObserver observer(web_contents()); |
| 129 EXPECT_TRUE( |
| 130 ExecuteScript(web_contents(), |
| 131 "location.href = '" + second_isolated_url.spec() + "'")); |
| 132 observer.Wait(); |
| 133 } |
| 134 |
| 135 EXPECT_EQ(second_isolated_url.GetOrigin(), |
| 136 web_contents()->GetSiteInstance()->GetSiteURL()); |
| 137 EXPECT_NE(isolated_instance, web_contents()->GetSiteInstance()); |
| 138 EXPECT_NE(unisolated_instance, web_contents()->GetSiteInstance()); |
| 139 } |
| 140 |
| 141 // Check that opening a popup for an isolated origin puts it into a new process |
| 142 // and its own SiteInstance. |
| 143 IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, Popup) { |
| 144 GURL unisolated_url( |
| 145 embedded_test_server()->GetURL("foo.com", "/title1.html")); |
| 146 GURL isolated_url( |
| 147 embedded_test_server()->GetURL("isolated.foo.com", "/title2.html")); |
| 148 |
| 149 EXPECT_TRUE(NavigateToURL(shell(), unisolated_url)); |
| 150 |
| 151 // Open a popup to a URL with an isolated origin and ensure that there was a |
| 152 // process swap. |
| 153 Shell* popup = OpenPopup(shell(), isolated_url, "foo"); |
| 154 |
| 155 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 156 popup->web_contents()->GetSiteInstance()); |
| 157 |
| 158 // The popup's site URL should match the full isolated origin. |
| 159 EXPECT_EQ(isolated_url.GetOrigin(), |
| 160 popup->web_contents()->GetSiteInstance()->GetSiteURL()); |
| 161 |
| 162 // Now open a second popup from an isolated origin to a URL with an |
| 163 // unisolated origin and ensure that there was another process swap. |
| 164 Shell* popup2 = OpenPopup(popup, unisolated_url, "bar"); |
| 165 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| 166 popup2->web_contents()->GetSiteInstance()); |
| 167 EXPECT_NE(popup->web_contents()->GetSiteInstance(), |
| 168 popup2->web_contents()->GetSiteInstance()); |
| 169 } |
| 170 |
| 171 // Check that navigating a subframe to an isolated origin puts the subframe |
| 172 // into an OOPIF and its own SiteInstance. Also check that the isolated |
| 173 // frame's subframes also end up in correct SiteInstance. |
| 174 IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, Subframe) { |
| 175 GURL top_url( |
| 176 embedded_test_server()->GetURL("www.foo.com", "/page_with_iframe.html")); |
| 177 EXPECT_TRUE(NavigateToURL(shell(), top_url)); |
| 178 |
| 179 GURL isolated_url(embedded_test_server()->GetURL("isolated.foo.com", |
| 180 "/page_with_iframe.html")); |
| 181 |
| 182 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 183 FrameTreeNode* child = root->child_at(0); |
| 184 |
| 185 NavigateIframeToURL(web_contents(), "test_iframe", isolated_url); |
| 186 EXPECT_EQ(child->current_url(), isolated_url); |
| 187 |
| 188 // Verify that the child frame is an OOPIF with a different SiteInstance. |
| 189 EXPECT_NE(web_contents()->GetSiteInstance(), |
| 190 child->current_frame_host()->GetSiteInstance()); |
| 191 EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe()); |
| 192 EXPECT_EQ(isolated_url.GetOrigin(), |
| 193 child->current_frame_host()->GetSiteInstance()->GetSiteURL()); |
| 194 |
| 195 // Verify that the isolated frame's subframe (which starts out at a relative |
| 196 // path) is kept in the isolated parent's SiteInstance. |
| 197 FrameTreeNode* grandchild = child->child_at(0); |
| 198 EXPECT_EQ(child->current_frame_host()->GetSiteInstance(), |
| 199 grandchild->current_frame_host()->GetSiteInstance()); |
| 200 |
| 201 // Navigating the grandchild to www.foo.com should put it into the top |
| 202 // frame's SiteInstance. |
| 203 GURL non_isolated_url( |
| 204 embedded_test_server()->GetURL("www.foo.com", "/title3.html")); |
| 205 TestFrameNavigationObserver observer(grandchild); |
| 206 EXPECT_TRUE(ExecuteScript( |
| 207 grandchild, "location.href = '" + non_isolated_url.spec() + "';")); |
| 208 observer.Wait(); |
| 209 EXPECT_EQ(non_isolated_url, grandchild->current_url()); |
| 210 |
| 211 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(), |
| 212 grandchild->current_frame_host()->GetSiteInstance()); |
| 213 EXPECT_NE(child->current_frame_host()->GetSiteInstance(), |
| 214 grandchild->current_frame_host()->GetSiteInstance()); |
| 215 } |
| 216 |
| 217 // Check that when an non-isolated origin foo.com embeds a subframe from an |
| 218 // isolated origin, which then navigates to a non-isolated origin bar.com, |
| 219 // bar.com goes back to the main frame's SiteInstance. See |
| 220 // https://crbug.com/711006. |
| 221 IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, |
| 222 NoOOPIFWhenIsolatedOriginNavigatesToNonIsolatedOrigin) { |
| 223 if (AreAllSitesIsolatedForTesting()) |
| 224 return; |
| 225 |
| 226 GURL top_url( |
| 227 embedded_test_server()->GetURL("www.foo.com", "/page_with_iframe.html")); |
| 228 EXPECT_TRUE(NavigateToURL(shell(), top_url)); |
| 229 |
| 230 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 231 FrameTreeNode* child = root->child_at(0); |
| 232 |
| 233 GURL isolated_url(embedded_test_server()->GetURL("isolated.foo.com", |
| 234 "/page_with_iframe.html")); |
| 235 |
| 236 NavigateIframeToURL(web_contents(), "test_iframe", isolated_url); |
| 237 EXPECT_EQ(isolated_url, child->current_url()); |
| 238 |
| 239 // Verify that the child frame is an OOPIF with a different SiteInstance. |
| 240 EXPECT_NE(web_contents()->GetSiteInstance(), |
| 241 child->current_frame_host()->GetSiteInstance()); |
| 242 EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe()); |
| 243 EXPECT_EQ(isolated_url.GetOrigin(), |
| 244 child->current_frame_host()->GetSiteInstance()->GetSiteURL()); |
| 245 |
| 246 // Navigate the child frame cross-site, but to a non-isolated origin. When |
| 247 // not in --site-per-process, this should bring the subframe back into the |
| 248 // main frame's SiteInstance. |
| 249 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html")); |
| 250 auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); |
| 251 EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin(bar_url))); |
| 252 NavigateIframeToURL(web_contents(), "test_iframe", bar_url); |
| 253 EXPECT_EQ(web_contents()->GetSiteInstance(), |
| 254 child->current_frame_host()->GetSiteInstance()); |
| 255 EXPECT_FALSE(child->current_frame_host()->IsCrossProcessSubframe()); |
| 256 } |
| 257 |
| 258 // Check that isolated origins can access cookies. This requires cookie checks |
| 259 // on the IO thread to be aware of isolated origins. |
| 260 IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, Cookies) { |
| 261 GURL isolated_url( |
| 262 embedded_test_server()->GetURL("isolated.foo.com", "/title2.html")); |
| 263 EXPECT_TRUE(NavigateToURL(shell(), isolated_url)); |
| 264 |
| 265 EXPECT_TRUE(ExecuteScript(web_contents(), "document.cookie = 'foo=bar';")); |
| 266 |
| 267 std::string cookie; |
| 268 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 269 web_contents(), "window.domAutomationController.send(document.cookie);", |
| 270 &cookie)); |
| 271 EXPECT_EQ("foo=bar", cookie); |
| 272 } |
| 273 |
| 274 } // namespace content |
OLD | NEW |