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

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: Added a comment to ExtensionViewHost::ShouldTransferNavigation. 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 void VerifyNavigationResult(WebContents* popup,
829 GURL old_popup_url,
830 GURL target_url,
831 bool expecting_navigation_success) {
832 if (!popup) {
833 // If navigation ends up in a tab, then the tab will be focused and
834 // therefore the popup will be closed, destroying associated WebContents -
835 // don't do any verification in this case.
836 ADD_FAILURE() << "Navigation should not close extension pop-up";
837 } else {
838 // If the extension popup is still opened, then wait until there is no
839 // load in progress, and verify whether the navigation succeeded or not.
840 LOG(INFO) << "Waiting until popup navigation stops...";
Charlie Reis 2016/09/26 17:27:50 Did you mean to leave these LOG(INFO) statements i
Łukasz Anforowicz 2016/09/26 18:30:23 When I was working on the tests, I had them hang (
841 WaitForLoadStop(popup);
842 if (expecting_navigation_success) {
843 EXPECT_EQ(target_url, popup->GetLastCommittedURL())
844 << "Navigation to " << target_url.spec()
845 << " should succeed in an extension pop-up";
846 } else {
847 EXPECT_NE(target_url, popup->GetLastCommittedURL())
848 << "Navigation to " << target_url.spec()
849 << " should fail in an extension pop-up";
850 EXPECT_THAT(
851 popup->GetLastCommittedURL(),
852 ::testing::AnyOf(::testing::Eq(old_popup_url),
853 ::testing::Eq(GURL("chrome-extension://invalid")),
854 ::testing::Eq(GURL("about:blank"))));
855 }
856 }
857
858 // Make sure that the web navigation did not succeed somewhere outside of
859 // the extension popup (as it might if ExtensionViewHost::OpenURLFromTab
860 // forwards the navigation to Browser::OpenURL [which doesn't specify a
861 // source WebContents]).
862 LOG(INFO) << "Verifying contents of tabs...";
863 TabStripModel* tabs = browser()->tab_strip_model();
864 for (int i = 0; i < tabs->count(); i++) {
865 WebContents* tab_contents = tabs->GetWebContentsAt(i);
866 WaitForLoadStop(tab_contents);
867 EXPECT_NE(target_url, tab_contents->GetLastCommittedURL())
868 << "Navigating an extension pop-up should not affect tabs.";
869 }
870 }
871
872 void TestPopupNavigationViaGet(GURL target_url,
873 bool expecting_navigation_success) {
874 // Were there any failures so far (e.g. in SetUpOnMainThread)?
875 ASSERT_FALSE(HasFailure());
876
877 // Simulate a click on the browser action to open the popup.
878 LOG(INFO) << "Opening an extension popup";
879 WebContents* popup = OpenPopup(0);
880 ASSERT_TRUE(popup);
881 GURL popup_url = popup_extension().GetResourceURL("popup.html");
882 EXPECT_EQ(popup_url, popup->GetLastCommittedURL());
883
884 // Note that the |setTimeout| call below is needed to make sure
885 // ExecuteScriptAndExtractBool returns *after* a scheduled navigation has
886 // already started.
887 std::string navigation_starting_script =
888 "window.location = '" + target_url.spec() + "';"
889 "setTimeout("
890 " function(){ window.domAutomationController.send(true); },"
891 " 0);";
892
893 // Try to navigate the pop-up.
894 bool ignored;
895 content::WebContentsDestroyedWatcher popup_destruction_watcher(popup);
896 LOG(INFO) << "Navigating the popup to " << target_url;
897 EXPECT_TRUE(ExecuteScriptAndExtractBool(popup, navigation_starting_script,
898 &ignored));
899
900 // Verify whether navigation succeeded or failed.
901 VerifyNavigationResult(popup_destruction_watcher.web_contents(), popup_url,
902 target_url, expecting_navigation_success);
903
904 // Close the pop-up.
905 BrowserActionTestUtil* actions_bar = GetBrowserActionsBar();
906 EXPECT_TRUE(actions_bar->HidePopup());
907 }
908
909 void TestPopupNavigationViaPost(GURL target_url,
910 bool expecting_navigation_success) {
911 // Were there any failures so far (e.g. in SetUpOnMainThread)?
912 ASSERT_FALSE(HasFailure());
913
914 // Simulate a click on the browser action to open the popup.
915 LOG(INFO) << "Opening an extension popup...";
916 WebContents* popup = OpenPopup(0);
917 ASSERT_TRUE(popup);
918 GURL popup_url = popup_extension().GetResourceURL("popup.html");
919 EXPECT_EQ(popup_url, popup->GetLastCommittedURL());
920
921 // Note that the |setTimeout| call below is needed to make sure
922 // ExecuteScriptAndExtractBool returns *after* a scheduled navigation has
923 // already started.
924 std::string navigation_starting_script =
925 "var form = document.getElementById('form');"
926 "form.action = '" + target_url.spec() + "';"
927 "form.submit();"
Charlie Reis 2016/09/26 17:27:50 This function looks the same as TestPopupNavigatio
Łukasz Anforowicz 2016/09/26 18:30:23 Done.
928 "setTimeout("
929 " function(){ window.domAutomationController.send(true); },"
930 " 0);";
931
932 // Try to navigate the pop-up.
933 bool ignored;
934 content::WebContentsDestroyedWatcher popup_destruction_watcher(popup);
935 LOG(INFO) << "Navigating the popup to " << target_url;
936 EXPECT_TRUE(ExecuteScriptAndExtractBool(popup, navigation_starting_script,
937 &ignored));
938
939 // Verify whether navigation succeeded or failed.
940 VerifyNavigationResult(popup_destruction_watcher.web_contents(), popup_url,
941 target_url, expecting_navigation_success);
942
943 // Close the pop-up.
944 BrowserActionTestUtil* actions_bar = GetBrowserActionsBar();
945 EXPECT_TRUE(actions_bar->HidePopup());
946 }
947
948 private:
949 const Extension* popup_extension_;
950 const Extension* other_extension_;
951 };
952
953 // Test verifies if an extension pop-up can be navigated to a web page.
954 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, WebpageViaGet) {
955 GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
956 TestPopupNavigationViaGet(web_url,
957 false /* == expecting_navigation_success */);
Charlie Reis 2016/09/26 17:27:50 nit: No need for the ==
Łukasz Anforowicz 2016/09/26 18:30:23 Done.
958 }
959
960 // Test verifies if an extension pop-up can be navigated to a web page.
961 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, WebpageViaPost) {
962 GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
963 TestPopupNavigationViaPost(web_url,
964 false /* == expecting_navigation_success */);
965 }
966
967 // Test verifies if an extension pop-up can be navigated to another page
968 // in the same extension.
969 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
970 PageInSameExtensionViaGet) {
971 GURL other_page_in_same_extension =
972 popup_extension().GetResourceURL("other_page.html");
973 TestPopupNavigationViaGet(other_page_in_same_extension,
974 true /* == expecting_navigation_success */);
975 }
976
977 // Test verifies if an extension pop-up can be navigated to another page
978 // in the same extension.
979 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
980 PageInSameExtensionViaPost) {
981 GURL other_page_in_same_extension =
982 popup_extension().GetResourceURL("other_page.html");
983 TestPopupNavigationViaPost(other_page_in_same_extension,
984 true /* == expecting_navigation_success */);
985 }
986
987 // Test verifies if an extension pop-up can be navigated to a page
988 // in another extension.
989 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
990 PageInOtherExtensionViaGet) {
991 GURL other_extension_url = other_extension().GetResourceURL("other.html");
992 TestPopupNavigationViaGet(other_extension_url,
993 false /* == expecting_navigation_success */);
994 }
995
996 // Test verifies if an extension pop-up can be navigated to a page
997 // in another extension.
998 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
999 PageInOtherExtensionViaPost) {
1000 GURL other_extension_url = other_extension().GetResourceURL("other.html");
1001 TestPopupNavigationViaPost(other_extension_url,
1002 false /* == expecting_navigation_success */);
1003 }
1004
1005 // Test verifies if navigating an extension pop-up to a http URI that returns
1006 // Content-Disposition: attachment; filename=...
1007 // works: No navigation, but download shelf visible + download goes through.
1008 //
1009 // Note - there is no "...ViaGet" flavour of this test, because we don't care
1010 // (yet) if GET succeeds with the download or not (it probably should succeed
1011 // for consistency with POST, but it always failed in M54 and before). After
1012 // abandoing ShouldFork/OpenURL for all methods (not just for POST) [see comment
1013 // about https://crbug.com/646261 in ChromeContentRendererClient::ShouldFork]
1014 // GET should automagically start working for downloads.
1015 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, DownloadViaPost) {
1016 content::DownloadTestObserverTerminal downloads_observer(
1017 content::BrowserContext::GetDownloadManager(browser()->profile()),
1018 1, // == wait_count (only waiting for "download-test3.gif").
1019 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
1020
1021 // Navigate to a URL that replies with
1022 // Content-Disposition: attachment; filename=...
1023 // header.
1024 GURL download_url(
1025 embedded_test_server()->GetURL("foo.com", "/download-test3.gif"));
1026 TestPopupNavigationViaPost(download_url,
1027 false /* == expecting_navigation_success */);
1028
1029 // Verify that "download-test3.gif got downloaded.
1030 LOG(INFO) << "Waiting for downloads to finish...";
1031 downloads_observer.WaitForFinished();
1032 EXPECT_EQ(0u, downloads_observer.NumDangerousDownloadsSeen());
1033 EXPECT_EQ(1u, downloads_observer.NumDownloadsSeenInState(
1034 content::DownloadItem::COMPLETE));
1035 #if !defined(OS_CHROMEOS)
Charlie Reis 2016/09/26 17:27:50 nit: Add a comment explaining why this is skipped
Łukasz Anforowicz 2016/09/26 18:30:23 Done. I've also felt that maybe !defined(OS_CHROM
Charlie Reis 2016/09/26 19:00:48 Cool, I like it.
Łukasz Anforowicz 2016/09/26 22:05:10 Actually, this didn't work... I've built CrOS bro
1036 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
1037 #endif
1038 }
1039
797 } // namespace 1040 } // namespace
798 } // namespace extensions 1041 } // 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