| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <string> | 5 #include <string> |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/strings/stringprintf.h" |
| 9 #include "base/test/scoped_feature_list.h" | 10 #include "base/test/scoped_feature_list.h" |
| 10 #include "chrome/browser/extensions/extension_browsertest.h" | 11 #include "chrome/browser/extensions/extension_browsertest.h" |
| 11 #include "chrome/browser/extensions/extension_service.h" | 12 #include "chrome/browser/extensions/extension_service.h" |
| 12 #include "chrome/browser/extensions/extension_util.h" | 13 #include "chrome/browser/extensions/extension_util.h" |
| 14 #include "chrome/browser/extensions/test_extension_dir.h" |
| 13 #include "chrome/browser/ui/browser_list.h" | 15 #include "chrome/browser/ui/browser_list.h" |
| 14 #include "chrome/browser/ui/extensions/app_launch_params.h" | 16 #include "chrome/browser/ui/extensions/app_launch_params.h" |
| 15 #include "chrome/browser/ui/extensions/application_launch.h" | 17 #include "chrome/browser/ui/extensions/application_launch.h" |
| 16 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h" | 18 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h" |
| 17 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 18 #include "chrome/browser/web_applications/web_app.h" | 20 #include "chrome/browser/web_applications/web_app.h" |
| 19 #include "chrome/test/base/ui_test_utils.h" | 21 #include "chrome/test/base/ui_test_utils.h" |
| 22 #include "content/public/browser/render_frame_host.h" |
| 20 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 24 #include "content/public/common/content_switches.h" |
| 25 #include "content/public/test/browser_test_utils.h" |
| 26 #include "content/public/test/test_utils.h" |
| 21 #include "extensions/browser/extension_registry.h" | 27 #include "extensions/browser/extension_registry.h" |
| 22 #include "extensions/common/constants.h" | 28 #include "extensions/common/constants.h" |
| 23 #include "extensions/common/extension.h" | 29 #include "extensions/common/extension.h" |
| 24 #include "extensions/common/extension_set.h" | 30 #include "extensions/common/extension_set.h" |
| 31 #include "net/dns/mock_host_resolver.h" |
| 32 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 25 | 33 |
| 26 #if defined(OS_MACOSX) | 34 #if defined(OS_MACOSX) |
| 27 #include "chrome/common/chrome_features.h" | 35 #include "chrome/common/chrome_features.h" |
| 28 #endif | 36 #endif |
| 29 | 37 |
| 30 using content::WebContents; | 38 using content::WebContents; |
| 31 using extensions::Extension; | 39 using extensions::Extension; |
| 32 | 40 |
| 33 namespace { | 41 namespace { |
| 34 | 42 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 53 // testing::Test: | 61 // testing::Test: |
| 54 void SetUp() override { | 62 void SetUp() override { |
| 55 ExtensionBrowserTest::SetUp(); | 63 ExtensionBrowserTest::SetUp(); |
| 56 #if defined(OS_MACOSX) | 64 #if defined(OS_MACOSX) |
| 57 scoped_feature_list_.InitAndEnableFeature(features::kBookmarkApps); | 65 scoped_feature_list_.InitAndEnableFeature(features::kBookmarkApps); |
| 58 #endif | 66 #endif |
| 59 } | 67 } |
| 60 | 68 |
| 61 protected: | 69 protected: |
| 62 void SetupApp(const std::string& app_folder, bool is_bookmark_app) { | 70 void SetupApp(const std::string& app_folder, bool is_bookmark_app) { |
| 71 SetupApp(test_data_dir_.AppendASCII(app_folder), is_bookmark_app); |
| 72 } |
| 73 |
| 74 void SetupApp(const base::FilePath& app_folder, bool is_bookmark_app) { |
| 63 const Extension* app = InstallExtensionWithSourceAndFlags( | 75 const Extension* app = InstallExtensionWithSourceAndFlags( |
| 64 test_data_dir_.AppendASCII(app_folder), 1, | 76 app_folder, 1, extensions::Manifest::INTERNAL, |
| 65 extensions::Manifest::INTERNAL, | |
| 66 is_bookmark_app ? extensions::Extension::FROM_BOOKMARK | 77 is_bookmark_app ? extensions::Extension::FROM_BOOKMARK |
| 67 : extensions::Extension::NO_FLAGS); | 78 : extensions::Extension::NO_FLAGS); |
| 68 ASSERT_TRUE(app); | 79 ASSERT_TRUE(app); |
| 69 | 80 |
| 70 // Launch it in a window. | 81 // Launch it in a window. |
| 71 ASSERT_TRUE(OpenApplication(AppLaunchParams( | 82 ASSERT_TRUE(OpenApplication(AppLaunchParams( |
| 72 browser()->profile(), app, extensions::LAUNCH_CONTAINER_WINDOW, | 83 browser()->profile(), app, extensions::LAUNCH_CONTAINER_WINDOW, |
| 73 WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST))); | 84 WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST))); |
| 74 | 85 |
| 75 for (auto* b : *BrowserList::GetInstance()) { | 86 for (auto* b : *BrowserList::GetInstance()) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 | 190 |
| 180 // Navigate to the app's launch page with the 'www.' prefis; the location bar | 191 // Navigate to the app's launch page with the 'www.' prefis; the location bar |
| 181 // should be hidden. | 192 // should be hidden. |
| 182 NavigateAndCheckForLocationBar( | 193 NavigateAndCheckForLocationBar( |
| 183 app_browser_, "http://www.example.com/empty.html", false); | 194 app_browser_, "http://www.example.com/empty.html", false); |
| 184 | 195 |
| 185 // Navigate to different origin; the location bar should now be visible. | 196 // Navigate to different origin; the location bar should now be visible. |
| 186 NavigateAndCheckForLocationBar( | 197 NavigateAndCheckForLocationBar( |
| 187 app_browser_, "http://www.foo.com/blah", true); | 198 app_browser_, "http://www.foo.com/blah", true); |
| 188 } | 199 } |
| 200 |
| 201 class HostedAppVsTdiTest : public HostedAppTest { |
| 202 public: |
| 203 HostedAppVsTdiTest() {} |
| 204 ~HostedAppVsTdiTest() override {} |
| 205 |
| 206 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 207 HostedAppTest::SetUpCommandLine(command_line); |
| 208 command_line->AppendSwitch(switches::kTopDocumentIsolation); |
| 209 } |
| 210 |
| 211 void SetUpOnMainThread() override { |
| 212 HostedAppTest::SetUpOnMainThread(); |
| 213 host_resolver()->AddRule("*", "127.0.0.1"); |
| 214 ASSERT_TRUE(embedded_test_server()->Start()); |
| 215 } |
| 216 }; |
| 217 |
| 218 // Tests that even with --top-document-isolation, app.site.com (covered by app's |
| 219 // web extent) main frame and foo.site.com (not covered by app's web extent) |
| 220 // share the same renderer process. See also https://crbug.com/679011. |
| 221 // |
| 222 // Relevant frames in the test: |
| 223 // - |app| - app.site.com/frame_tree/cross_origin_but_same_site_frames.html |
| 224 // Main frame, launch URL of the hosted app (i.e. app.launch.web_url). |
| 225 // - |same_dir| - app.site.com/frame_tree/simple.htm |
| 226 // Another URL, but still covered by hosted app's web extent |
| 227 // (i.e. by app.urls). |
| 228 // - |diff_dir| - app.site.com/save_page/a.htm |
| 229 // Same origin as |same_dir| and |app|, but not covered by app's |
| 230 // extent. |
| 231 // - |same_site| - other.site.com/title1.htm |
| 232 // Different origin, but same site as |app|, |same_dir|, |
| 233 // |diff_dir|. |
| 234 // - |cross_site| - cross.domain.com/title1.htm |
| 235 // Cross-site from all the other frames. |
| 236 // |
| 237 // Verifications of |*_site| (e.g. EXPECT_EQ(same_dir_site, app_site) are |
| 238 // sanity checks of the test setup. |
| 239 // |
| 240 // First real verification in the test is whether |same_dir| and |diff_dir| can |
| 241 // script each other (despite their effective URLs being cross-site, because |
| 242 // |same_dir| is mapped to a chrome-extension URL). This was a functionality |
| 243 // problem caused by https://crbug.com/679011. |
| 244 // |
| 245 // The test also verifies that all same-site frames (i.e. |app|, |same_dir|, |
| 246 // |diff_dir|, |same_site|) share the same renderer process. This was a small |
| 247 // performance problem caused by https://crbug.com/679011. |
| 248 IN_PROC_BROWSER_TEST_F(HostedAppVsTdiTest, ProcessAllocation) { |
| 249 // Setup and launch the hosted app. |
| 250 GURL url = embedded_test_server()->GetURL( |
| 251 "app.site.com", "/frame_tree/cross_origin_but_same_site_frames.html"); |
| 252 |
| 253 extensions::TestExtensionDir test_app_dir; |
| 254 test_app_dir.WriteManifest(base::StringPrintf( |
| 255 R"( { "name": "Hosted App vs TDI Test", |
| 256 "version": "1", |
| 257 "manifest_version": 2, |
| 258 "app": { |
| 259 "launch": { |
| 260 "web_url": "%s" |
| 261 }, |
| 262 "urls": ["*://app.site.com/frame_tree"] |
| 263 } |
| 264 } )", |
| 265 url.spec().c_str())); |
| 266 SetupApp(test_app_dir.UnpackedPath(), false); |
| 267 |
| 268 content::WebContents* web_contents = |
| 269 app_browser_->tab_strip_model()->GetActiveWebContents(); |
| 270 content::WaitForLoadStop(web_contents); |
| 271 |
| 272 auto find_frame = [web_contents](const std::string& name) { |
| 273 return content::FrameMatchingPredicate( |
| 274 web_contents, base::Bind(&content::FrameMatchesName, name)); |
| 275 }; |
| 276 content::RenderFrameHost* app = web_contents->GetMainFrame(); |
| 277 content::RenderFrameHost* same_dir = find_frame("SameOrigin-SamePath"); |
| 278 content::RenderFrameHost* diff_dir = find_frame("SameOrigin-DifferentPath"); |
| 279 content::RenderFrameHost* same_site = find_frame("OtherSubdomain-SameSite"); |
| 280 content::RenderFrameHost* cross_site = find_frame("CrossSite"); |
| 281 |
| 282 // Sanity-check sites of all relevant frames to verify test setup. |
| 283 GURL app_site = content::SiteInstance::GetSiteForURL( |
| 284 app_browser_->profile(), app->GetLastCommittedURL()); |
| 285 EXPECT_EQ(extensions::kExtensionScheme, app_site.scheme()); |
| 286 |
| 287 GURL same_dir_site = content::SiteInstance::GetSiteForURL( |
| 288 app_browser_->profile(), same_dir->GetLastCommittedURL()); |
| 289 EXPECT_EQ(extensions::kExtensionScheme, same_dir_site.scheme()); |
| 290 EXPECT_EQ(same_dir_site, app_site); |
| 291 |
| 292 GURL diff_dir_site = content::SiteInstance::GetSiteForURL( |
| 293 app_browser_->profile(), diff_dir->GetLastCommittedURL()); |
| 294 EXPECT_NE(extensions::kExtensionScheme, diff_dir_site.scheme()); |
| 295 EXPECT_NE(diff_dir_site, app_site); |
| 296 |
| 297 GURL same_site_site = content::SiteInstance::GetSiteForURL( |
| 298 app_browser_->profile(), same_site->GetLastCommittedURL()); |
| 299 EXPECT_NE(extensions::kExtensionScheme, same_site_site.scheme()); |
| 300 EXPECT_NE(same_site_site, app_site); |
| 301 EXPECT_EQ(same_site_site, diff_dir_site); |
| 302 |
| 303 GURL cross_site_site = content::SiteInstance::GetSiteForURL( |
| 304 app_browser_->profile(), cross_site->GetLastCommittedURL()); |
| 305 EXPECT_NE(cross_site_site, app_site); |
| 306 EXPECT_NE(cross_site_site, same_site_site); |
| 307 |
| 308 // Verify that |same_dir| and |diff_dir| have the same origin according to |
| 309 // |window.origin| (even though they have different |same_dir_site| and |
| 310 // |diff_dir_site|). |
| 311 std::string same_dir_origin; |
| 312 EXPECT_TRUE(content::ExecuteScriptAndExtractString( |
| 313 same_dir, "domAutomationController.send(window.origin)", |
| 314 &same_dir_origin)); |
| 315 |
| 316 std::string diff_dir_origin; |
| 317 EXPECT_TRUE(content::ExecuteScriptAndExtractString( |
| 318 diff_dir, "domAutomationController.send(window.origin)", |
| 319 &diff_dir_origin)); |
| 320 |
| 321 EXPECT_EQ(diff_dir_origin, same_dir_origin); |
| 322 |
| 323 // Verify scriptability and process placement. |
| 324 EXPECT_EQ(same_dir->GetProcess(), app->GetProcess()); |
| 325 if (!content::AreAllSitesIsolatedForTesting()) { |
| 326 // Verify that |same_dir| and |diff_dir| can script each other. |
| 327 // (they should - they have the same origin). |
| 328 std::string inner_text_from_other_frame; |
| 329 ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| 330 diff_dir, |
| 331 R"( var w = window.open('', 'SameOrigin-SamePath'); |
| 332 domAutomationController.send(w.document.body.innerText); )", |
| 333 &inner_text_from_other_frame)); |
| 334 EXPECT_EQ("Simple test page.", inner_text_from_other_frame); |
| 335 |
| 336 // Verify there are no additional processes for same-site frames. |
| 337 EXPECT_EQ(diff_dir->GetProcess(), app->GetProcess()); |
| 338 EXPECT_EQ(same_site->GetProcess(), app->GetProcess()); |
| 339 // TODO(lukasza): https://crbug.com/718516: For now it is okay for |
| 340 // |cross_site| to be in any process, but we should probably revisit |
| 341 // before launching --top-document-isolation more broadly. |
| 342 } else { |
| 343 // TODO(lukasza): https://crbug.com/718516: Process policy is not |
| 344 // well-defined / settled wrt relationship between 1) hosted apps and 2) |
| 345 // same-site web content outside of hosted app's extent. When this test was |
| 346 // authored --site-per-process would put |app| in a separate renderer |
| 347 // process from |diff_dir| and |same_site|, even though such process |
| 348 // placement can be problematic (if |app| tries to synchronously script |
| 349 // |diff_dir| and/or |same_site|). |
| 350 } |
| 351 } |
| OLD | NEW |