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

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: Addressed CR feedback from creis@. 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
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,
Devlin 2016/09/26 20:57:05 Could this be private?
Łukasz Anforowicz 2016/09/26 22:05:11 Actually, after addressing Charlie's feedback ther
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...";
Devlin 2016/09/26 20:57:05 nit: remove debugging logs
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
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()
Devlin 2016/09/26 20:57:05 I think you can avoid the .spec() calls here - log
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
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,
Devlin 2016/09/26 20:57:05 const GURL&s
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
873 bool expecting_navigation_success) {
874 std::string navigation_starting_script =
875 "window.location = '" + target_url.spec() + "';";
876 TestPopupNavigation(target_url, expecting_navigation_success,
877 navigation_starting_script);
878 }
879
880 void TestPopupNavigationViaPost(GURL target_url,
881 bool expecting_navigation_success) {
882 std::string navigation_starting_script =
883 "var form = document.getElementById('form');"
884 "form.action = '" + target_url.spec() + "';"
885 "form.submit();";
886 TestPopupNavigation(target_url, expecting_navigation_success,
887 navigation_starting_script);
888 }
889
890 private:
891 void TestPopupNavigation(
892 GURL target_url,
893 bool expecting_navigation_success,
894 std::string navigation_starting_script) {
895 // Were there any failures so far (e.g. in SetUpOnMainThread)?
896 ASSERT_FALSE(HasFailure());
897
898 // Simulate a click on the browser action to open the popup.
899 WebContents* popup = OpenPopup(0);
900 ASSERT_TRUE(popup);
901 GURL popup_url = popup_extension().GetResourceURL("popup.html");
902 EXPECT_EQ(popup_url, popup->GetLastCommittedURL());
903
904 // Note that the |setTimeout| call below is needed to make sure
905 // ExecuteScriptAndExtractBool returns *after* a scheduled navigation has
906 // already started.
907 std::string script_to_execute =
908 navigation_starting_script +
909 "setTimeout("
Devlin 2016/09/26 20:57:05 \n
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
910 " function(){ window.domAutomationController.send(true); },"
Devlin 2016/09/26 20:57:05 space after function() \n
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
911 " 0);";
Devlin 2016/09/26 20:57:05 no indentation
Łukasz Anforowicz 2016/09/26 22:05:11 I don't understand. The arguments of setTimeout s
Devlin 2016/09/27 15:57:28 Whoops, misread this for some reason. The 0 shoul
Łukasz Anforowicz 2016/09/27 17:00:50 Got it - done.
912
913 // Try to navigate the pop-up.
914 bool ignored;
Devlin 2016/09/26 20:57:05 init ignored
Łukasz Anforowicz 2016/09/26 22:05:11 Done (+ renamed the variable to be more descriptiv
915 content::WebContentsDestroyedWatcher popup_destruction_watcher(popup);
916 LOG(INFO) << "Navigating extension popup to " << target_url;
917 EXPECT_TRUE(ExecuteScriptAndExtractBool(popup, script_to_execute,
918 &ignored));
919
920 // Verify whether navigation succeeded or failed.
921 VerifyNavigationResult(popup_destruction_watcher.web_contents(), popup_url,
922 target_url, expecting_navigation_success);
923
924 // Close the pop-up.
925 BrowserActionTestUtil* actions_bar = GetBrowserActionsBar();
926 EXPECT_TRUE(actions_bar->HidePopup());
927 }
928
929 const Extension* popup_extension_;
930 const Extension* other_extension_;
931 };
932
933 // Test verifies if an extension pop-up can be navigated to a web page.
Devlin 2016/09/26 20:57:05 s/Test verifies if/Tests that (and add the expecte
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
934 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, WebpageViaGet) {
935 GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
936 TestPopupNavigationViaGet(web_url,
937 false /* expecting_navigation_success */);
Devlin 2016/09/26 20:57:05 with how frequent this bool is used, maybe make an
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
938 }
939
940 // Test verifies if an extension pop-up can be navigated to a web page.
941 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, WebpageViaPost) {
Devlin 2016/09/26 20:57:05 Browsertests are expensive. Can we combine the Vi
Łukasz Anforowicz 2016/09/26 22:05:11 Done.
942 GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
943 TestPopupNavigationViaPost(web_url,
944 false /* expecting_navigation_success */);
945 }
946
947 // Test verifies if an extension pop-up can be navigated to another page
948 // in the same extension.
949 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
950 PageInSameExtensionViaGet) {
951 GURL other_page_in_same_extension =
952 popup_extension().GetResourceURL("other_page.html");
953 TestPopupNavigationViaGet(other_page_in_same_extension,
954 true /* expecting_navigation_success */);
955 }
956
957 // Test verifies if an extension pop-up can be navigated to another page
958 // in the same extension.
959 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
960 PageInSameExtensionViaPost) {
961 GURL other_page_in_same_extension =
962 popup_extension().GetResourceURL("other_page.html");
963 TestPopupNavigationViaPost(other_page_in_same_extension,
964 true /* expecting_navigation_success */);
965 }
966
967 // Test verifies if an extension pop-up can be navigated to a page
968 // in another extension.
969 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
970 PageInOtherExtensionViaGet) {
971 GURL other_extension_url = other_extension().GetResourceURL("other.html");
972 TestPopupNavigationViaGet(other_extension_url,
973 false /* expecting_navigation_success */);
974 }
975
976 // Test verifies if an extension pop-up can be navigated to a page
977 // in another extension.
978 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
979 PageInOtherExtensionViaPost) {
980 GURL other_extension_url = other_extension().GetResourceURL("other.html");
981 TestPopupNavigationViaPost(other_extension_url,
982 false /* expecting_navigation_success */);
983 }
984
985 // Test verifies if navigating an extension pop-up to a http URI that returns
986 // Content-Disposition: attachment; filename=...
987 // works: No navigation, but download shelf visible + download goes through.
988 //
989 // Note - there is no "...ViaGet" flavour of this test, because we don't care
990 // (yet) if GET succeeds with the download or not (it probably should succeed
991 // for consistency with POST, but it always failed in M54 and before). After
992 // abandoing ShouldFork/OpenURL for all methods (not just for POST) [see comment
993 // about https://crbug.com/646261 in ChromeContentRendererClient::ShouldFork]
994 // GET should automagically start working for downloads.
995 IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, DownloadViaPost) {
996 content::DownloadTestObserverTerminal downloads_observer(
997 content::BrowserContext::GetDownloadManager(browser()->profile()),
998 1, // == wait_count (only waiting for "download-test3.gif").
999 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
1000
1001 // Navigate to a URL that replies with
1002 // Content-Disposition: attachment; filename=...
1003 // header.
1004 GURL download_url(
1005 embedded_test_server()->GetURL("foo.com", "/download-test3.gif"));
1006 TestPopupNavigationViaPost(download_url,
1007 false /* expecting_navigation_success */);
1008
1009 // Verify that "download-test3.gif got downloaded.
1010 LOG(INFO) << "Waiting for downloads to finish...";
1011 downloads_observer.WaitForFinished();
1012 EXPECT_EQ(0u, downloads_observer.NumDangerousDownloadsSeen());
1013 EXPECT_EQ(1u, downloads_observer.NumDownloadsSeenInState(
1014 content::DownloadItem::COMPLETE));
1015
1016 // The test verification below is applicable only to scenarios where the
1017 // download shelf is supported (e.g. there is no download shelf on Chrome OS).
1018 if (browser()->SupportsWindowFeature(Browser::FEATURE_DOWNLOADSHELF))
1019 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
1020 }
1021
797 } // namespace 1022 } // namespace
798 } // namespace extensions 1023 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698