Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Side by Side Diff: chrome/browser/extensions/api/extension_action/browser_action_apitest.cc

Issue 2352083003: Allow top-level navigation in extension pop-ups if it only triggers a download. (Closed)
Patch Set: Changed bug reference (in a TODO comment) to a fresh bug. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/browser/extensions/extension_view_host.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 <stdint.h> 5 #include <stdint.h>
6 6
7 #include "base/macros.h" 7 #include "base/macros.h"
8 #include "build/build_config.h" 8 #include "build/build_config.h"
9 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 9 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
10 #include "chrome/browser/extensions/browser_action_test_util.h" 10 #include "chrome/browser/extensions/browser_action_test_util.h"
11 #include "chrome/browser/extensions/extension_action.h" 11 #include "chrome/browser/extensions/extension_action.h"
12 #include "chrome/browser/extensions/extension_action_icon_factory.h" 12 #include "chrome/browser/extensions/extension_action_icon_factory.h"
13 #include "chrome/browser/extensions/extension_action_manager.h" 13 #include "chrome/browser/extensions/extension_action_manager.h"
14 #include "chrome/browser/extensions/extension_action_runner.h" 14 #include "chrome/browser/extensions/extension_action_runner.h"
15 #include "chrome/browser/extensions/extension_apitest.h" 15 #include "chrome/browser/extensions/extension_apitest.h"
16 #include "chrome/browser/extensions/extension_tab_util.h" 16 #include "chrome/browser/extensions/extension_tab_util.h"
17 #include "chrome/browser/extensions/extension_util.h" 17 #include "chrome/browser/extensions/extension_util.h"
18 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_commands.h" 20 #include "chrome/browser/ui/browser_commands.h"
21 #include "chrome/browser/ui/browser_finder.h" 21 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/browser/ui/browser_navigator_params.h" 22 #include "chrome/browser/ui/browser_navigator_params.h"
23 #include "chrome/browser/ui/browser_window.h" 23 #include "chrome/browser/ui/browser_window.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h" 24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/common/url_constants.h" 25 #include "chrome/common/url_constants.h"
26 #include "chrome/test/base/ui_test_utils.h" 26 #include "chrome/test/base/ui_test_utils.h"
27 #include "content/public/browser/browser_context.h"
27 #include "content/public/browser/notification_service.h" 28 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/render_frame_host.h" 29 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/web_contents.h" 30 #include "content/public/browser/web_contents.h"
30 #include "content/public/test/browser_test_utils.h" 31 #include "content/public/test/browser_test_utils.h"
32 #include "content/public/test/content_browser_test_utils.h"
33 #include "content/public/test/download_test_observer.h"
34 #include "content/public/test/test_utils.h"
31 #include "extensions/browser/extension_registry.h" 35 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_system.h" 36 #include "extensions/browser/extension_system.h"
33 #include "extensions/browser/notification_types.h" 37 #include "extensions/browser/notification_types.h"
34 #include "extensions/browser/process_manager.h" 38 #include "extensions/browser/process_manager.h"
35 #include "extensions/browser/test_extension_registry_observer.h" 39 #include "extensions/browser/test_extension_registry_observer.h"
36 #include "extensions/common/feature_switch.h" 40 #include "extensions/common/feature_switch.h"
37 #include "extensions/test/extension_test_message_listener.h" 41 #include "extensions/test/extension_test_message_listener.h"
38 #include "extensions/test/result_catcher.h" 42 #include "extensions/test/result_catcher.h"
39 #include "net/dns/mock_host_resolver.h" 43 #include "net/dns/mock_host_resolver.h"
40 #include "net/test/embedded_test_server/embedded_test_server.h" 44 #include "net/test/embedded_test_server/embedded_test_server.h"
45 #include "testing/gmock/include/gmock/gmock.h"
41 #include "ui/base/resource/resource_bundle.h" 46 #include "ui/base/resource/resource_bundle.h"
42 #include "ui/gfx/geometry/rect.h" 47 #include "ui/gfx/geometry/rect.h"
43 #include "ui/gfx/geometry/size.h" 48 #include "ui/gfx/geometry/size.h"
44 #include "ui/gfx/image/canvas_image_source.h" 49 #include "ui/gfx/image/canvas_image_source.h"
45 #include "ui/gfx/image/image_skia.h" 50 #include "ui/gfx/image/image_skia.h"
46 #include "ui/gfx/image/image_skia_operations.h" 51 #include "ui/gfx/image/image_skia_operations.h"
47 #include "ui/gfx/image/image_unittest_util.h" 52 #include "ui/gfx/image/image_unittest_util.h"
48 #include "ui/gfx/skia_util.h" 53 #include "ui/gfx/skia_util.h"
49 54
50 using content::WebContents; 55 using content::WebContents;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 BrowserActionApiTest() {} 103 BrowserActionApiTest() {}
99 ~BrowserActionApiTest() override {} 104 ~BrowserActionApiTest() override {}
100 105
101 protected: 106 protected:
102 BrowserActionTestUtil* GetBrowserActionsBar() { 107 BrowserActionTestUtil* GetBrowserActionsBar() {
103 if (!browser_action_test_util_) 108 if (!browser_action_test_util_)
104 browser_action_test_util_.reset(new BrowserActionTestUtil(browser())); 109 browser_action_test_util_.reset(new BrowserActionTestUtil(browser()));
105 return browser_action_test_util_.get(); 110 return browser_action_test_util_.get();
106 } 111 }
107 112
108 bool OpenPopup(int index) { 113 WebContents* OpenPopup(int index) {
109 ResultCatcher catcher; 114 ResultCatcher catcher;
110 content::WindowedNotificationObserver popup_observer( 115 content::WindowedNotificationObserver popup_observer(
111 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 116 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
112 content::NotificationService::AllSources()); 117 content::NotificationService::AllSources());
113 GetBrowserActionsBar()->Press(index); 118 GetBrowserActionsBar()->Press(index);
114 popup_observer.Wait(); 119 popup_observer.Wait();
115 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 120 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
116 return GetBrowserActionsBar()->HasPopup(); 121
122 if (!GetBrowserActionsBar()->HasPopup())
123 return nullptr;
124
125 const auto& source = static_cast<const content::Source<WebContents>&>(
126 popup_observer.source());
127 return source.ptr();
117 } 128 }
118 129
119 ExtensionAction* GetBrowserAction(const Extension& extension) { 130 ExtensionAction* GetBrowserAction(const Extension& extension) {
120 return ExtensionActionManager::Get(browser()->profile())-> 131 return ExtensionActionManager::Get(browser()->profile())->
121 GetBrowserAction(extension); 132 GetBrowserAction(extension);
122 } 133 }
123 134
124 private: 135 private:
125 std::unique_ptr<BrowserActionTestUtil> browser_action_test_util_; 136 std::unique_ptr<BrowserActionTestUtil> browser_action_test_util_;
126 137
(...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 ExtensionTestMessageListener listener("ready", true); 798 ExtensionTestMessageListener listener("ready", true);
788 EXPECT_TRUE(LoadExtension( 799 EXPECT_TRUE(LoadExtension(
789 test_data_dir_.AppendASCII("browser_action/open_popup_on_reply"))); 800 test_data_dir_.AppendASCII("browser_action/open_popup_on_reply")));
790 EXPECT_TRUE(listener.WaitUntilSatisfied()); 801 EXPECT_TRUE(listener.WaitUntilSatisfied());
791 802
792 ResultCatcher catcher; 803 ResultCatcher catcher;
793 listener.Reply(std::string()); 804 listener.Reply(std::string());
794 EXPECT_TRUE(catcher.GetNextResult()) << message_; 805 EXPECT_TRUE(catcher.GetNextResult()) << message_;
795 } 806 }
796 807
808 class NavigatingExtensionPopupBrowserTest : public BrowserActionApiTest {
809 public:
810 const Extension& popup_extension() { return *popup_extension_; }
811 const Extension& other_extension() { return *other_extension_; }
812
813 void SetUpOnMainThread() override {
814 BrowserActionApiTest::SetUpOnMainThread();
815
816 host_resolver()->AddRule("*", "127.0.0.1");
817 ASSERT_TRUE(embedded_test_server()->Start());
818
819 // Load an extension with a pop-up.
820 ASSERT_TRUE(popup_extension_ = LoadExtension(test_data_dir_.AppendASCII(
821 "browser_action/popup_with_form")));
822
823 // Load another extension (that we can try navigating to).
824 ASSERT_TRUE(other_extension_ = LoadExtension(test_data_dir_.AppendASCII(
825 "browser_action/popup_with_iframe")));
826 }
827
828 enum ExpectedNavigationStatus {
829 EXPECTING_NAVIGATION_SUCCESS,
830 EXPECTING_NAVIGATION_FAILURE,
831 };
832
833 void TestPopupNavigationViaGet(
834 const GURL& target_url,
835 ExpectedNavigationStatus expected_navigation_status) {
836 std::string navigation_starting_script =
837 "window.location = '" + target_url.spec() + "';\n";
838 TestPopupNavigation(target_url, expected_navigation_status,
839 navigation_starting_script);
840 }
841
842 void TestPopupNavigationViaPost(
843 const GURL& target_url,
844 ExpectedNavigationStatus expected_navigation_status) {
845 std::string navigation_starting_script =
846 "var form = document.getElementById('form');\n"
847 "form.action = '" + target_url.spec() + "';\n"
848 "form.submit();\n";
849 TestPopupNavigation(target_url, expected_navigation_status,
850 navigation_starting_script);
851 }
852
853 private:
854 void TestPopupNavigation(const GURL& target_url,
855 ExpectedNavigationStatus expected_navigation_status,
856 std::string navigation_starting_script) {
857 // Were there any failures so far (e.g. in SetUpOnMainThread)?
858 ASSERT_FALSE(HasFailure());
859
860 // Simulate a click on the browser action to open the popup.
861 WebContents* popup = OpenPopup(0);
862 ASSERT_TRUE(popup);
863 GURL popup_url = popup_extension().GetResourceURL("popup.html");
864 EXPECT_EQ(popup_url, popup->GetLastCommittedURL());
865
866 // Note that the |setTimeout| call below is needed to make sure
867 // ExecuteScriptAndExtractBool returns *after* a scheduled navigation has
868 // already started.
869 std::string script_to_execute =
870 navigation_starting_script +
871 "setTimeout(\n"
872 " function() { window.domAutomationController.send(true); },\n"
873 " 0);\n";
874
875 // Try to navigate the pop-up.
876 bool ignored_script_result = false;
877 content::WebContentsDestroyedWatcher popup_destruction_watcher(popup);
878 EXPECT_TRUE(ExecuteScriptAndExtractBool(popup, script_to_execute,
879 &ignored_script_result));
880 popup = popup_destruction_watcher.web_contents();
881
882 // Verify if the popup navigation succeeded or failed as expected.
883 if (!popup) {
884 // If navigation ends up in a tab, then the tab will be focused and
885 // therefore the popup will be closed, destroying associated WebContents -
886 // don't do any verification in this case.
887 ADD_FAILURE() << "Navigation should not close extension pop-up";
888 } else {
889 // If the extension popup is still opened, then wait until there is no
890 // load in progress, and verify whether the navigation succeeded or not.
891 WaitForLoadStop(popup);
892 if (expected_navigation_status == EXPECTING_NAVIGATION_SUCCESS) {
893 EXPECT_EQ(target_url, popup->GetLastCommittedURL())
894 << "Navigation to " << target_url
895 << " should succeed in an extension pop-up";
896 } else {
897 EXPECT_NE(target_url, popup->GetLastCommittedURL())
898 << "Navigation to " << target_url
899 << " should fail in an extension pop-up";
900 EXPECT_THAT(
901 popup->GetLastCommittedURL(),
902 ::testing::AnyOf(::testing::Eq(popup_url),
903 ::testing::Eq(GURL("chrome-extension://invalid")),
904 ::testing::Eq(GURL("about:blank"))));
905 }
906 }
907
908 // Make sure that the web navigation did not succeed somewhere outside of
909 // the extension popup (as it might if ExtensionViewHost::OpenURLFromTab
910 // forwards the navigation to Browser::OpenURL [which doesn't specify a
911 // source WebContents]).
912 TabStripModel* tabs = browser()->tab_strip_model();
913 for (int i = 0; i < tabs->count(); i++) {
914 WebContents* tab_contents = tabs->GetWebContentsAt(i);
915 WaitForLoadStop(tab_contents);
916 EXPECT_NE(target_url, tab_contents->GetLastCommittedURL())
917 << "Navigating an extension pop-up should not affect tabs.";
918 }
919
920 // Close the pop-up.
921 EXPECT_TRUE(GetBrowserActionsBar()->HidePopup());
922 }
923
924 const Extension* popup_extension_;
925 const Extension* other_extension_;
926 };
927
928 // Tests that an extension pop-up cannot be navigated to a web page.
929 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, Webpage) {
930 GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
931 TestPopupNavigationViaGet(web_url, EXPECTING_NAVIGATION_FAILURE);
932 TestPopupNavigationViaPost(web_url, EXPECTING_NAVIGATION_FAILURE);
933 }
934
935 // Tests that an extension pop-up can be navigated to another page
936 // in the same extension.
937 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
938 PageInSameExtension) {
939 GURL other_page_in_same_extension =
940 popup_extension().GetResourceURL("other_page.html");
941 TestPopupNavigationViaGet(other_page_in_same_extension,
942 EXPECTING_NAVIGATION_SUCCESS);
943 TestPopupNavigationViaPost(other_page_in_same_extension,
944 EXPECTING_NAVIGATION_SUCCESS);
945 }
946
947 // Tests that an extension pop-up cannot be navigated to a page
948 // in another extension.
949 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
950 PageInOtherExtension) {
951 GURL other_extension_url = other_extension().GetResourceURL("other.html");
952 TestPopupNavigationViaGet(other_extension_url, EXPECTING_NAVIGATION_FAILURE);
953 TestPopupNavigationViaPost(other_extension_url, EXPECTING_NAVIGATION_FAILURE);
954 }
955
956 // Tests that navigating an extension pop-up to a http URI that returns
957 // Content-Disposition: attachment; filename=...
958 // works: No navigation, but download shelf visible + download goes through.
959 //
960 // Note - there is no "...ViaGet" flavour of this test, because we don't care
961 // (yet) if GET succeeds with the download or not (it probably should succeed
962 // for consistency with POST, but it always failed in M54 and before). After
963 // abandoing ShouldFork/OpenURL for all methods (not just for POST) [see comment
964 // about https://crbug.com/646261 in ChromeContentRendererClient::ShouldFork]
965 // GET should automagically start working for downloads.
966 // TODO(lukasza): https://crbug.com/650694: Add a "Get" flavour of the test once
967 // the download works both for GET and POST requests.
968 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, DownloadViaPost) {
969 content::DownloadTestObserverTerminal downloads_observer(
970 content::BrowserContext::GetDownloadManager(browser()->profile()),
971 1, // == wait_count (only waiting for "download-test3.gif").
972 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
973
974 // Navigate to a URL that replies with
975 // Content-Disposition: attachment; filename=...
976 // header.
977 GURL download_url(
978 embedded_test_server()->GetURL("foo.com", "/download-test3.gif"));
979 TestPopupNavigationViaPost(download_url, EXPECTING_NAVIGATION_FAILURE);
980
981 // Verify that "download-test3.gif got downloaded.
982 downloads_observer.WaitForFinished();
983 EXPECT_EQ(0u, downloads_observer.NumDangerousDownloadsSeen());
984 EXPECT_EQ(1u, downloads_observer.NumDownloadsSeenInState(
985 content::DownloadItem::COMPLETE));
986
987 // The test verification below is applicable only to scenarios where the
988 // download shelf is supported - on ChromeOS, instead of the download shelf,
989 // there is a download notification in the right-bottom corner of the screen.
990 #if !defined(OS_CHROMEOS)
991 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
992 #endif
993 }
994
797 } // namespace 995 } // namespace
798 } // namespace extensions 996 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/extensions/extension_view_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698