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
3 // found in the LICENSE file.
4 
5 #include <memory>
6 #include <string>
7 
8 #include "base/strings/string16.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "build/build_config.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
13 #include "chrome/browser/extensions/extension_browsertest.h"
14 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/test/base/in_process_browser_test.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "components/permissions/permission_request_manager.h"
20 #include "components/permissions/test/mock_permission_prompt_factory.h"
21 #include "content/public/browser/navigation_controller.h"
22 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "net/test/embedded_test_server/embedded_test_server.h"
26 #include "third_party/blink/public/common/context_menu_data/media_type.h"
27 
28 #if defined(OS_MACOSX)
29 #include "chrome/test/base/launchservices_utils_mac.h"
30 #endif
31 
32 using content::WebContents;
33 
34 class RegisterProtocolHandlerBrowserTest : public InProcessBrowserTest {
35  public:
RegisterProtocolHandlerBrowserTest()36   RegisterProtocolHandlerBrowserTest() { }
37 
SetUpOnMainThread()38   void SetUpOnMainThread() override {
39 #if defined(OS_MACOSX)
40     ASSERT_TRUE(test::RegisterAppWithLaunchServices());
41 #endif
42   }
43 
CreateContextMenu(GURL url)44   TestRenderViewContextMenu* CreateContextMenu(GURL url) {
45     content::ContextMenuParams params;
46     params.media_type = blink::ContextMenuDataMediaType::kNone;
47     params.link_url = url;
48     params.unfiltered_link_url = url;
49     WebContents* web_contents =
50         browser()->tab_strip_model()->GetActiveWebContents();
51     params.page_url =
52         web_contents->GetController().GetLastCommittedEntry()->GetURL();
53 #if defined(OS_MACOSX)
54     params.writing_direction_default = 0;
55     params.writing_direction_left_to_right = 0;
56     params.writing_direction_right_to_left = 0;
57 #endif  // OS_MACOSX
58     TestRenderViewContextMenu* menu = new TestRenderViewContextMenu(
59         browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
60         params);
61     menu->Init();
62     return menu;
63   }
64 
AddProtocolHandler(const std::string & protocol,const GURL & url)65   void AddProtocolHandler(const std::string& protocol, const GURL& url) {
66     ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(protocol,
67                                                                      url);
68     ProtocolHandlerRegistry* registry =
69         ProtocolHandlerRegistryFactory::GetForBrowserContext(
70             browser()->profile());
71     // Fake that this registration is happening on profile startup. Otherwise
72     // it'll try to register with the OS, which causes DCHECKs on Windows when
73     // running as admin on Windows 7.
74     registry->is_loading_ = true;
75     registry->OnAcceptRegisterProtocolHandler(handler);
76     registry->is_loading_ = false;
77     ASSERT_TRUE(registry->IsHandledProtocol(protocol));
78   }
RemoveProtocolHandler(const std::string & protocol,const GURL & url)79   void RemoveProtocolHandler(const std::string& protocol,
80                              const GURL& url) {
81     ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(protocol,
82                                                                      url);
83     ProtocolHandlerRegistry* registry =
84         ProtocolHandlerRegistryFactory::GetForBrowserContext(
85             browser()->profile());
86     registry->RemoveHandler(handler);
87     ASSERT_FALSE(registry->IsHandledProtocol(protocol));
88   }
89 };
90 
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest,ContextMenuEntryAppearsForHandledUrls)91 IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest,
92     ContextMenuEntryAppearsForHandledUrls) {
93   std::unique_ptr<TestRenderViewContextMenu> menu(
94       CreateContextMenu(GURL("http://www.google.com/")));
95   ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKWITH));
96 
97   AddProtocolHandler(std::string("web+search"),
98                      GURL("http://www.google.com/%s"));
99   GURL url("web+search:testing");
100   ProtocolHandlerRegistry* registry =
101       ProtocolHandlerRegistryFactory::GetForBrowserContext(
102           browser()->profile());
103   ASSERT_EQ(1u, registry->GetHandlersFor(url.scheme()).size());
104   menu.reset(CreateContextMenu(url));
105   ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKWITH));
106 }
107 
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest,UnregisterProtocolHandler)108 IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest,
109     UnregisterProtocolHandler) {
110   std::unique_ptr<TestRenderViewContextMenu> menu(
111       CreateContextMenu(GURL("http://www.google.com/")));
112   ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKWITH));
113 
114   AddProtocolHandler(std::string("web+search"),
115                      GURL("http://www.google.com/%s"));
116   GURL url("web+search:testing");
117   ProtocolHandlerRegistry* registry =
118       ProtocolHandlerRegistryFactory::GetForBrowserContext(
119           browser()->profile());
120   ASSERT_EQ(1u, registry->GetHandlersFor(url.scheme()).size());
121   menu.reset(CreateContextMenu(url));
122   ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKWITH));
123   RemoveProtocolHandler(std::string("web+search"),
124                         GURL("http://www.google.com/%s"));
125   ASSERT_EQ(0u, registry->GetHandlersFor(url.scheme()).size());
126   menu.reset(CreateContextMenu(url));
127   ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKWITH));
128 }
129 
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest,CustomHandler)130 IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest, CustomHandler) {
131   ASSERT_TRUE(embedded_test_server()->Start());
132   GURL handler_url = embedded_test_server()->GetURL("/custom_handler.html");
133   AddProtocolHandler("news", handler_url);
134 
135   ui_test_utils::NavigateToURL(browser(), GURL("news:test"));
136 
137   ASSERT_EQ(handler_url,
138             browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
139 
140   // Also check redirects.
141   GURL redirect_url =
142       embedded_test_server()->GetURL("/server-redirect?news:test");
143   ui_test_utils::NavigateToURL(browser(), redirect_url);
144 
145   ASSERT_EQ(handler_url,
146             browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
147 }
148 
149 using RegisterProtocolHandlerExtensionBrowserTest =
150     extensions::ExtensionBrowserTest;
151 
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerExtensionBrowserTest,Basic)152 IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerExtensionBrowserTest, Basic) {
153   permissions::PermissionRequestManager* manager =
154       permissions::PermissionRequestManager::FromWebContents(
155           browser()->tab_strip_model()->GetActiveWebContents());
156   auto prompt_factory =
157       std::make_unique<permissions::MockPermissionPromptFactory>(manager);
158   prompt_factory->set_response_type(
159       permissions::PermissionRequestManager::ACCEPT_ALL);
160 
161   const extensions::Extension* extension =
162       LoadExtension(test_data_dir_.AppendASCII("protocol_handler"));
163   ASSERT_NE(nullptr, extension);
164 
165   std::string handler_url =
166       "chrome-extension://" + extension->id() + "/test.html";
167 
168   // Register the handler.
169   ui_test_utils::NavigateToURL(browser(), GURL(handler_url));
170   ASSERT_TRUE(content::ExecuteScript(
171       browser()->tab_strip_model()->GetActiveWebContents(),
172       "navigator.registerProtocolHandler('geo', 'test.html?%s', 'test');"));
173 
174   // Wait until the prompt is "displayed" and "accepted".
175   base::RunLoop().RunUntilIdle();
176 
177   // Test the handler.
178   ui_test_utils::NavigateToURL(browser(), GURL("geo:test"));
179   ASSERT_EQ(GURL(handler_url + "?geo%3Atest"),
180             browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
181 }
182