| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 13 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
| 14 #include "base/test/histogram_tester.h" |
| 14 #include "chrome/browser/extensions/browser_action_test_util.h" | 15 #include "chrome/browser/extensions/browser_action_test_util.h" |
| 15 #include "chrome/browser/extensions/extension_browsertest.h" | 16 #include "chrome/browser/extensions/extension_browsertest.h" |
| 16 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
| 17 #include "chrome/browser/extensions/test_extension_dir.h" | 18 #include "chrome/browser/extensions/test_extension_dir.h" |
| 18 #include "chrome/browser/ui/browser_commands.h" | 19 #include "chrome/browser/ui/browser_commands.h" |
| 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 20 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 20 #include "chrome/common/chrome_paths.h" | 21 #include "chrome/common/chrome_paths.h" |
| 21 #include "chrome/common/extensions/extension_process_policy.h" | 22 #include "chrome/common/extensions/extension_process_policy.h" |
| 22 #include "chrome/common/pref_names.h" | 23 #include "chrome/common/pref_names.h" |
| 23 #include "chrome/test/base/in_process_browser_test.h" | 24 #include "chrome/test/base/in_process_browser_test.h" |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 IsIsolateExtensionsEnabled() | 243 IsIsolateExtensionsEnabled() |
| 243 ? if_enabled | 244 ? if_enabled |
| 244 : if_disabled; | 245 : if_disabled; |
| 245 } | 246 } |
| 246 | 247 |
| 247 content::WebContents* OpenPopup(content::RenderFrameHost* opener, | 248 content::WebContents* OpenPopup(content::RenderFrameHost* opener, |
| 248 const GURL& url) { | 249 const GURL& url) { |
| 249 content::WindowedNotificationObserver popup_observer( | 250 content::WindowedNotificationObserver popup_observer( |
| 250 chrome::NOTIFICATION_TAB_ADDED, | 251 chrome::NOTIFICATION_TAB_ADDED, |
| 251 content::NotificationService::AllSources()); | 252 content::NotificationService::AllSources()); |
| 252 EXPECT_TRUE(ExecuteScript(opener, "window.open('" + url.spec() + "')")); | 253 EXPECT_TRUE(ExecuteScript( |
| 254 opener, "window.popup = window.open('" + url.spec() + "')")); |
| 253 popup_observer.Wait(); | 255 popup_observer.Wait(); |
| 254 content::WebContents* popup = | 256 content::WebContents* popup = |
| 255 browser()->tab_strip_model()->GetActiveWebContents(); | 257 browser()->tab_strip_model()->GetActiveWebContents(); |
| 256 WaitForLoadStop(popup); | 258 WaitForLoadStop(popup); |
| 257 EXPECT_EQ(url, popup->GetMainFrame()->GetLastCommittedURL()); | 259 EXPECT_EQ(url, popup->GetMainFrame()->GetLastCommittedURL()); |
| 258 return popup; | 260 return popup; |
| 259 } | 261 } |
| 260 | 262 |
| 261 private: | 263 private: |
| 262 std::vector<std::unique_ptr<TestExtensionDir>> temp_dirs_; | 264 std::vector<std::unique_ptr<TestExtensionDir>> temp_dirs_; |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 EXPECT_TRUE(policy->CanRequestURL( | 724 EXPECT_TRUE(policy->CanRequestURL( |
| 723 main_frame->GetProcess()->GetID(), | 725 main_frame->GetProcess()->GetID(), |
| 724 GURL("filesystem:chrome-extension://some-extension-id/some-path"))); | 726 GURL("filesystem:chrome-extension://some-extension-id/some-path"))); |
| 725 EXPECT_TRUE(policy->CanRequestURL( | 727 EXPECT_TRUE(policy->CanRequestURL( |
| 726 extension_frame->GetProcess()->GetID(), | 728 extension_frame->GetProcess()->GetID(), |
| 727 GURL("chrome-extension://some-extension-id/resource.html"))); | 729 GURL("chrome-extension://some-extension-id/resource.html"))); |
| 728 EXPECT_TRUE(policy->CanRequestURL( | 730 EXPECT_TRUE(policy->CanRequestURL( |
| 729 main_frame->GetProcess()->GetID(), | 731 main_frame->GetProcess()->GetID(), |
| 730 GURL("chrome-extension://some-extension-id/resource.html"))); | 732 GURL("chrome-extension://some-extension-id/resource.html"))); |
| 731 | 733 |
| 732 EXPECT_TRUE(policy->CanCommitURL( | 734 if (IsIsolateExtensionsEnabled()) { |
| 733 extension_frame->GetProcess()->GetID(), | 735 EXPECT_TRUE(policy->CanCommitURL( |
| 734 GURL("blob:chrome-extension://some-extension-id/some-guid"))); | 736 extension_frame->GetProcess()->GetID(), |
| 735 EXPECT_FALSE(policy->CanCommitURL( | 737 GURL("blob:chrome-extension://some-extension-id/some-guid"))); |
| 736 main_frame->GetProcess()->GetID(), | 738 EXPECT_FALSE(policy->CanCommitURL( |
| 737 GURL("blob:chrome-extension://some-extension-id/some-guid"))); | 739 main_frame->GetProcess()->GetID(), |
| 738 EXPECT_TRUE(policy->CanCommitURL( | 740 GURL("blob:chrome-extension://some-extension-id/some-guid"))); |
| 739 extension_frame->GetProcess()->GetID(), | 741 EXPECT_TRUE(policy->CanCommitURL( |
| 740 GURL("chrome-extension://some-extension-id/resource.html"))); | 742 extension_frame->GetProcess()->GetID(), |
| 741 EXPECT_FALSE(policy->CanCommitURL( | 743 GURL("chrome-extension://some-extension-id/resource.html"))); |
| 742 main_frame->GetProcess()->GetID(), | 744 EXPECT_FALSE(policy->CanCommitURL( |
| 743 GURL("chrome-extension://some-extension-id/resource.html"))); | 745 main_frame->GetProcess()->GetID(), |
| 744 EXPECT_TRUE(policy->CanCommitURL( | 746 GURL("chrome-extension://some-extension-id/resource.html"))); |
| 745 extension_frame->GetProcess()->GetID(), | 747 EXPECT_TRUE(policy->CanCommitURL( |
| 746 GURL("filesystem:chrome-extension://some-extension-id/some-path"))); | 748 extension_frame->GetProcess()->GetID(), |
| 747 EXPECT_FALSE(policy->CanCommitURL( | 749 GURL("filesystem:chrome-extension://some-extension-id/some-path"))); |
| 748 main_frame->GetProcess()->GetID(), | 750 EXPECT_FALSE(policy->CanCommitURL( |
| 749 GURL("filesystem:chrome-extension://some-extension-id/some-path"))); | 751 main_frame->GetProcess()->GetID(), |
| 752 GURL("filesystem:chrome-extension://some-extension-id/some-path"))); |
| 753 } |
| 750 | 754 |
| 751 // Open a new about:blank popup from main frame. This should stay in the web | 755 // Open a new about:blank popup from main frame. This should stay in the web |
| 752 // process. | 756 // process. |
| 753 content::WebContents* popup = | 757 content::WebContents* popup = |
| 754 OpenPopup(main_frame, GURL(url::kAboutBlankURL)); | 758 OpenPopup(main_frame, GURL(url::kAboutBlankURL)); |
| 755 EXPECT_NE(popup, tab); | 759 EXPECT_NE(popup, tab); |
| 756 ASSERT_EQ(2, browser()->tab_strip_model()->count()); | 760 ASSERT_EQ(2, browser()->tab_strip_model()->count()); |
| 757 EXPECT_EQ(IfExtensionsIsolated(1, 0), | 761 EXPECT_EQ(IfExtensionsIsolated(1, 0), |
| 758 pm->GetRenderFrameHostsForExtension(extension->id()).size()); | 762 pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 759 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); | 763 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 780 EXPECT_FALSE(extension_origin.IsSameOriginWith( | 784 EXPECT_FALSE(extension_origin.IsSameOriginWith( |
| 781 popup->GetMainFrame()->GetLastCommittedOrigin())); | 785 popup->GetMainFrame()->GetLastCommittedOrigin())); |
| 782 EXPECT_NE("foo", GetTextContent(popup->GetMainFrame())); | 786 EXPECT_NE("foo", GetTextContent(popup->GetMainFrame())); |
| 783 | 787 |
| 784 EXPECT_EQ(IfExtensionsIsolated(1, 0), | 788 EXPECT_EQ(IfExtensionsIsolated(1, 0), |
| 785 pm->GetRenderFrameHostsForExtension(extension->id()).size()); | 789 pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 786 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); | 790 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); |
| 787 } | 791 } |
| 788 | 792 |
| 789 // Navigate second subframe to each nested URL from the main frame (i.e., | 793 // Navigate second subframe to each nested URL from the main frame (i.e., |
| 790 // from non-extension process). | 794 // from non-extension process). This should be blocked in |
| 795 // --isolate-extensions, but allowed without --isolate-extensions due to |
| 796 // unblessed extension frames. |
| 791 // | 797 // |
| 792 // TODO(alexmos): Currently, this is still allowed due to unblessed extension | 798 // TODO(alexmos): This is also temporarily allowed under PlzNavigate, because |
| 793 // contexts, but in the future such subframe navigations from non-extension | 799 // currently this particular blocking happens in |
| 794 // processes should be blocked when unblessed contexts go away with | 800 // ChromeContentBrowserClientExtensionsPart::ShouldAllowOpenURL, which isn't |
| 795 // --isolate-extensions. | 801 // triggered below under PlzNavigate (since there'll be no transfer). Once |
| 802 // the blob/filesystem URL checks in ExtensionNavigationThrottle are updated |
| 803 // to apply to all frames and not just main frames, the PlzNavigate exception |
| 804 // below can be removed. See https://crbug.com/661324. |
| 796 for (size_t i = 0; i < arraysize(nested_urls); i++) { | 805 for (size_t i = 0; i < arraysize(nested_urls); i++) { |
| 797 EXPECT_TRUE(content::NavigateIframeToURL(tab, "frame2", nested_urls[i])); | 806 EXPECT_TRUE(content::NavigateIframeToURL(tab, "frame2", nested_urls[i])); |
| 798 content::RenderFrameHost* second_frame = ChildFrameAt(main_frame, 1); | 807 content::RenderFrameHost* second_frame = ChildFrameAt(main_frame, 1); |
| 799 EXPECT_EQ(nested_urls[i], second_frame->GetLastCommittedURL()); | 808 if (IsIsolateExtensionsEnabled() && |
| 800 EXPECT_EQ(extension_origin, second_frame->GetLastCommittedOrigin()); | 809 !content::IsBrowserSideNavigationEnabled()) { |
| 801 EXPECT_EQ("foo", GetTextContent(second_frame)); | 810 EXPECT_NE(nested_urls[i], second_frame->GetLastCommittedURL()); |
| 802 EXPECT_EQ(IfExtensionsIsolated(2, 0), | 811 EXPECT_FALSE(extension_origin.IsSameOriginWith( |
| 803 pm->GetRenderFrameHostsForExtension(extension->id()).size()); | 812 second_frame->GetLastCommittedOrigin())); |
| 804 EXPECT_EQ(IfExtensionsIsolated(2, 0), pm->GetAllFrames().size()); | 813 EXPECT_NE("foo", GetTextContent(second_frame)); |
| 814 EXPECT_EQ(IfExtensionsIsolated(1, 0), |
| 815 pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 816 EXPECT_EQ(IfExtensionsIsolated(1, 0), pm->GetAllFrames().size()); |
| 817 } else { |
| 818 EXPECT_EQ(nested_urls[i], second_frame->GetLastCommittedURL()); |
| 819 EXPECT_EQ(extension_origin, second_frame->GetLastCommittedOrigin()); |
| 820 EXPECT_EQ("foo", GetTextContent(second_frame)); |
| 821 EXPECT_EQ(IfExtensionsIsolated(2, 0), |
| 822 pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 823 EXPECT_EQ(IfExtensionsIsolated(2, 0), pm->GetAllFrames().size()); |
| 824 } |
| 825 EXPECT_TRUE( |
| 826 content::NavigateIframeToURL(tab, "frame2", GURL(url::kAboutBlankURL))); |
| 805 } | 827 } |
| 806 } | 828 } |
| 807 | 829 |
| 808 // Test that navigations to blob: and filesystem: URLs with extension origins | 830 // Test that navigations to blob: and filesystem: URLs with extension origins |
| 809 // are allowed when initiated from extension processes. See | 831 // are allowed when initiated from extension processes. See |
| 810 // https://crbug.com/645028 and https://crbug.com/644426. | 832 // https://crbug.com/645028 and https://crbug.com/644426. |
| 811 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, | 833 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, |
| 812 NestedURLNavigationsToExtensionAllowed) { | 834 NestedURLNavigationsToExtensionAllowed) { |
| 813 // Create a simple extension without a background page. | 835 // Create a simple extension without a background page. |
| 814 const Extension* extension = CreateExtension("Extension", false); | 836 const Extension* extension = CreateExtension("Extension", false); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 EXPECT_FALSE(app_origin.IsSameOriginWith( | 984 EXPECT_FALSE(app_origin.IsSameOriginWith( |
| 963 web_tab->GetMainFrame()->GetLastCommittedOrigin())); | 985 web_tab->GetMainFrame()->GetLastCommittedOrigin())); |
| 964 EXPECT_NE("foo", GetTextContent(web_tab->GetMainFrame())); | 986 EXPECT_NE("foo", GetTextContent(web_tab->GetMainFrame())); |
| 965 EXPECT_NE(web_tab->GetMainFrame()->GetProcess(), app_rfh->GetProcess()); | 987 EXPECT_NE(web_tab->GetMainFrame()->GetProcess(), app_rfh->GetProcess()); |
| 966 | 988 |
| 967 EXPECT_EQ(2u, pm->GetAllFrames().size()); | 989 EXPECT_EQ(2u, pm->GetAllFrames().size()); |
| 968 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(app->id()).size()); | 990 EXPECT_EQ(2u, pm->GetRenderFrameHostsForExtension(app->id()).size()); |
| 969 } | 991 } |
| 970 } | 992 } |
| 971 | 993 |
| 994 // Test that a web frame can't navigate a proxy for an extension frame to a |
| 995 // blob/filesystem extension URL. See https://crbug.com/656752. |
| 996 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, |
| 997 NestedURLNavigationsViaProxyBlocked) { |
| 998 base::HistogramTester uma; |
| 999 // Create a simple extension without a background page. |
| 1000 const Extension* extension = CreateExtension("Extension", false); |
| 1001 embedded_test_server()->ServeFilesFromDirectory(extension->path()); |
| 1002 ASSERT_TRUE(embedded_test_server()->Start()); |
| 1003 |
| 1004 // Navigate main tab to an empty web page. There should be no extension |
| 1005 // frames yet. |
| 1006 NavigateToURL(embedded_test_server()->GetURL("/empty.html")); |
| 1007 ProcessManager* pm = ProcessManager::Get(profile()); |
| 1008 EXPECT_EQ(0u, pm->GetAllFrames().size()); |
| 1009 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 1010 |
| 1011 content::WebContents* tab = |
| 1012 browser()->tab_strip_model()->GetActiveWebContents(); |
| 1013 content::RenderFrameHost* main_frame = tab->GetMainFrame(); |
| 1014 |
| 1015 // Open a new about:blank popup from main frame. This should stay in the web |
| 1016 // process. |
| 1017 content::WebContents* popup = |
| 1018 OpenPopup(main_frame, GURL(url::kAboutBlankURL)); |
| 1019 EXPECT_NE(popup, tab); |
| 1020 ASSERT_EQ(2, browser()->tab_strip_model()->count()); |
| 1021 EXPECT_EQ(0u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 1022 EXPECT_EQ(0u, pm->GetAllFrames().size()); |
| 1023 |
| 1024 // Navigate popup to an extension page. |
| 1025 const GURL extension_url(extension->url().Resolve("empty.html")); |
| 1026 content::TestNavigationObserver observer(popup); |
| 1027 EXPECT_TRUE( |
| 1028 ExecuteScript(popup, "location.href = '" + extension_url.spec() + "';")); |
| 1029 observer.Wait(); |
| 1030 EXPECT_EQ(1u, pm->GetAllFrames().size()); |
| 1031 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 1032 content::RenderFrameHost* extension_frame = popup->GetMainFrame(); |
| 1033 |
| 1034 // Create valid blob and filesystem URLs in the extension's origin. |
| 1035 url::Origin extension_origin(extension_frame->GetLastCommittedOrigin()); |
| 1036 GURL blob_url(CreateBlobURL(extension_frame, "foo")); |
| 1037 EXPECT_EQ(extension_origin, url::Origin(blob_url)); |
| 1038 GURL filesystem_url(CreateFileSystemURL(extension_frame, "foo")); |
| 1039 EXPECT_EQ(extension_origin, url::Origin(filesystem_url)); |
| 1040 |
| 1041 // Have the web page navigate the popup to each nested URL with extension |
| 1042 // origin via the window reference it obtained earlier from window.open. |
| 1043 GURL nested_urls[] = {blob_url, filesystem_url}; |
| 1044 for (size_t i = 0; i < arraysize(nested_urls); i++) { |
| 1045 EXPECT_TRUE(ExecuteScript( |
| 1046 tab, "window.popup.location.href = '" + nested_urls[i].spec() + "';")); |
| 1047 WaitForLoadStop(popup); |
| 1048 |
| 1049 // This is a top-level navigation that should be blocked since it |
| 1050 // originates from a non-extension process. Ensure that the popup stays at |
| 1051 // the original page and doesn't navigate to the nested URL. |
| 1052 EXPECT_NE(nested_urls[i], popup->GetLastCommittedURL()); |
| 1053 EXPECT_NE("foo", GetTextContent(popup->GetMainFrame())); |
| 1054 |
| 1055 EXPECT_EQ(1u, pm->GetRenderFrameHostsForExtension(extension->id()).size()); |
| 1056 EXPECT_EQ(1u, pm->GetAllFrames().size()); |
| 1057 } |
| 1058 |
| 1059 // Verify that the blocking was recorded correctly in UMA. |
| 1060 uma.ExpectTotalCount("Extensions.ShouldAllowOpenURL.Failure", 2); |
| 1061 uma.ExpectBucketCount("Extensions.ShouldAllowOpenURL.Failure", |
| 1062 0 /* FAILURE_FILE_SYSTEM_URL */, 1); |
| 1063 uma.ExpectBucketCount("Extensions.ShouldAllowOpenURL.Failure", |
| 1064 1 /* FAILURE_BLOB_URL */, 1); |
| 1065 } |
| 1066 |
| 972 // Verify that a web popup created via window.open from an extension page can | 1067 // Verify that a web popup created via window.open from an extension page can |
| 973 // communicate with the extension page via window.opener. See | 1068 // communicate with the extension page via window.opener. See |
| 974 // https://crbug.com/590068. | 1069 // https://crbug.com/590068. |
| 975 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, | 1070 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, |
| 976 WebPopupFromExtensionMainFrameHasValidOpener) { | 1071 WebPopupFromExtensionMainFrameHasValidOpener) { |
| 977 // Create a simple extension without a background page. | 1072 // Create a simple extension without a background page. |
| 978 const Extension* extension = CreateExtension("Extension", false); | 1073 const Extension* extension = CreateExtension("Extension", false); |
| 979 embedded_test_server()->ServeFilesFromDirectory(extension->path()); | 1074 embedded_test_server()->ServeFilesFromDirectory(extension->path()); |
| 980 ASSERT_TRUE(embedded_test_server()->Start()); | 1075 ASSERT_TRUE(embedded_test_server()->Start()); |
| 981 | 1076 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1060 EXPECT_TRUE(ExecuteScriptAndExtractBool( | 1155 EXPECT_TRUE(ExecuteScriptAndExtractBool( |
| 1061 popup, "window.domAutomationController.send(!!window.opener)", | 1156 popup, "window.domAutomationController.send(!!window.opener)", |
| 1062 &is_opener_defined)); | 1157 &is_opener_defined)); |
| 1063 EXPECT_TRUE(is_opener_defined); | 1158 EXPECT_TRUE(is_opener_defined); |
| 1064 | 1159 |
| 1065 // Verify that postMessage to window.opener works. | 1160 // Verify that postMessage to window.opener works. |
| 1066 VerifyPostMessageToOpener(popup->GetMainFrame(), extension_frame); | 1161 VerifyPostMessageToOpener(popup->GetMainFrame(), extension_frame); |
| 1067 } | 1162 } |
| 1068 | 1163 |
| 1069 } // namespace extensions | 1164 } // namespace extensions |
| OLD | NEW |