• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/test/thread_test_helper.h"
12 #include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
13 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
14 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h"
15 #include "chrome/browser/extensions/extension_apitest.h"
16 #include "chrome/browser/extensions/extension_test_message_listener.h"
17 #include "chrome/browser/extensions/test_extension_dir.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/common/extension.h"
25 
26 using content::BrowserThread;
27 using extensions::Extension;
28 using extensions::ExtensionPrefs;
29 using extensions::RulesRegistry;
30 using extensions::RulesRegistryService;
31 using extensions::TestExtensionDir;
32 using extensions::WebRequestRulesRegistry;
33 
34 namespace {
35 
36 const char kArbitraryUrl[] = "http://www.example.com";  // Must be http://.
37 
38 // The extension in "declarative/redirect_to_data" redirects every navigation to
39 // a page with title |kTestTitle|.
40 #define TEST_TITLE_STRING ":TEST:"
41 const char kTestTitle[] = TEST_TITLE_STRING;
42 
43 // All methods and constands below containing "RedirectToData" in their names
44 // are parts of a test extension "Redirect to 'data:'".
GetRedirectToDataManifestWithVersion(unsigned version)45 std::string GetRedirectToDataManifestWithVersion(unsigned version) {
46   return base::StringPrintf(
47       "{\n"
48       "  \"name\": \"Redirect to 'data:' (declarative apitest)\",\n"
49       "  \"version\": \"%d\",\n"
50       "  \"manifest_version\": 2,\n"
51       "  \"description\": \"Redirects all requests to a fixed data: URI.\",\n"
52       "  \"background\": {\n"
53       "    \"scripts\": [\"background.js\"]\n"
54       "  },\n"
55       "  \"permissions\": [\n"
56       "    \"declarativeWebRequest\", \"<all_urls>\"\n"
57       "  ]\n"
58       "}\n",
59       version);
60 }
61 
62 const char kRedirectToDataConstants[] =
63     "var redirectDataURI =\n"
64     "    'data:text/html;charset=utf-8,<html><head><title>' +\n"
65     "    '" TEST_TITLE_STRING "' +\n"
66     "    '<%2Ftitle><%2Fhtml>';\n";
67 #undef TEST_TITLE_STRING
68 
69 const char kRedirectToDataRules[] =
70     "var rules = [{\n"
71     "  conditions: [\n"
72     "    new chrome.declarativeWebRequest.RequestMatcher({\n"
73     "        url: {schemes: ['http']}})\n"
74     "  ],\n"
75     "  actions: [\n"
76     "    new chrome.declarativeWebRequest.RedirectRequest({\n"
77     "      redirectUrl: redirectDataURI\n"
78     "    })\n"
79     "  ]\n"
80     "}];\n";
81 
82 const char kRedirectToDataInstallRules[] =
83     "function report(details) {\n"
84     "  if (chrome.extension.lastError) {\n"
85     "    chrome.test.log(chrome.extension.lastError.message);\n"
86     "  } else {\n"
87     "    chrome.test.sendMessage(\"ready\", function(reply) {})\n"
88     "  }\n"
89     "}\n"
90     "\n"
91     "chrome.runtime.onInstalled.addListener(function(details) {\n"
92     "  if (details.reason == 'install')\n"
93     "    chrome.declarativeWebRequest.onRequest.addRules(rules, report);\n"
94     "});\n";
95 
96 const char kRedirectToDataNoRules[] =
97     "chrome.runtime.onInstalled.addListener(function(details) {\n"
98     "  chrome.test.sendMessage(\"ready\", function(reply) {})\n"
99     "});\n";
100 
101 }  // namespace
102 
103 class DeclarativeApiTest : public ExtensionApiTest {
104  public:
GetTitle()105   std::string GetTitle() {
106     base::string16 title(
107         browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
108     return base::UTF16ToUTF8(title);
109   }
110 
111   // Reports the number of rules registered for the |extension_id| with the
112   // non-webview rules registry.
NumberOfRegisteredRules(const std::string & extension_id)113   size_t NumberOfRegisteredRules(const std::string& extension_id) {
114     RulesRegistryService* rules_registry_service =
115         extensions::RulesRegistryService::Get(browser()->profile());
116     scoped_refptr<RulesRegistry> rules_registry =
117         rules_registry_service->GetRulesRegistry(
118             RulesRegistry::WebViewKey(0, 0),
119             extensions::declarative_webrequest_constants::kOnRequest);
120     std::vector<linked_ptr<RulesRegistry::Rule> > rules;
121     BrowserThread::PostTask(
122         BrowserThread::IO,
123         FROM_HERE,
124         base::Bind(
125             &RulesRegistry::GetAllRules, rules_registry, extension_id, &rules));
126     scoped_refptr<base::ThreadTestHelper> io_helper(new base::ThreadTestHelper(
127         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get()));
128     EXPECT_TRUE(io_helper->Run());
129     return rules.size();
130   }
131 };
132 
IN_PROC_BROWSER_TEST_F(DeclarativeApiTest,DeclarativeApi)133 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, DeclarativeApi) {
134   ASSERT_TRUE(RunExtensionTest("declarative/api")) << message_;
135 
136   // Check that uninstalling the extension has removed all rules.
137   std::string extension_id = GetSingleLoadedExtension()->id();
138   UninstallExtension(extension_id);
139 
140   // UnloadExtension posts a task to the owner thread of the extension
141   // to process this unloading. The next task to retrive all rules
142   // is therefore processed after the UnloadExtension task has been executed.
143   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
144 }
145 
146 // PersistRules test first installs an extension, which registers some rules.
147 // Then after browser restart, it checks that the rules are still in effect.
IN_PROC_BROWSER_TEST_F(DeclarativeApiTest,PRE_PersistRules)148 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, PRE_PersistRules) {
149   // Note that we cannot use an extension generated by *GetRedirectToData*
150   // helpers in a TestExtensionDir, because we need the extension to persist
151   // until the PersistRules test is run.
152   ASSERT_TRUE(RunExtensionTest("declarative/redirect_to_data")) << message_;
153 }
154 
IN_PROC_BROWSER_TEST_F(DeclarativeApiTest,PersistRules)155 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, PersistRules) {
156   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
157   EXPECT_EQ(kTestTitle, GetTitle());
158 }
159 
160 // Test that the rules are correctly persisted and (de)activated during
161 // changing the "installed" and "enabled" status of an extension.
IN_PROC_BROWSER_TEST_F(DeclarativeApiTest,ExtensionLifetimeRulesHandling)162 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, ExtensionLifetimeRulesHandling) {
163   TestExtensionDir ext_dir;
164 
165   // 1. Install the extension. Rules should become active.
166   ext_dir.WriteManifest(GetRedirectToDataManifestWithVersion(1));
167   ext_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
168                     base::StringPrintf("%s%s%s",
169                                        kRedirectToDataConstants,
170                                        kRedirectToDataRules,
171                                        kRedirectToDataInstallRules));
172   ExtensionTestMessageListener ready("ready", /*will_reply=*/false);
173   const Extension* extension = InstallExtensionWithUIAutoConfirm(
174       ext_dir.Pack(), 1 /*+1 installed extension*/, browser());
175   ASSERT_TRUE(extension);
176   std::string extension_id(extension->id());
177   ASSERT_TRUE(ready.WaitUntilSatisfied());
178   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
179   EXPECT_EQ(kTestTitle, GetTitle());
180   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
181 
182   // 2. Disable the extension. Rules are no longer active, but are still
183   // registered.
184   DisableExtension(extension_id);
185   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
186   EXPECT_NE(kTestTitle, GetTitle());
187   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
188 
189   // 3. Enable the extension again. Rules are active again.
190   EnableExtension(extension_id);
191   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
192   EXPECT_EQ(kTestTitle, GetTitle());
193   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
194 
195   // 4. Bump the version and update, without the code to add the rules. Rules
196   // are still active, because the registry does not drop them unless the
197   // extension gets uninstalled.
198   ext_dir.WriteManifest(GetRedirectToDataManifestWithVersion(2));
199   ext_dir.WriteFile(
200       FILE_PATH_LITERAL("background.js"),
201       base::StringPrintf(
202           "%s%s", kRedirectToDataConstants, kRedirectToDataNoRules));
203   ExtensionTestMessageListener ready_after_update("ready",
204                                                   /*will_reply=*/false);
205   EXPECT_TRUE(UpdateExtension(
206       extension_id, ext_dir.Pack(), 0 /*no new installed extension*/));
207   ASSERT_TRUE(ready_after_update.WaitUntilSatisfied());
208   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
209   EXPECT_EQ(kTestTitle, GetTitle());
210   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
211 
212   // 5. Reload the extension. Rules remain active.
213   ReloadExtension(extension_id);
214   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
215   EXPECT_EQ(kTestTitle, GetTitle());
216   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
217 
218   // 6. Uninstall the extension. Rules are gone.
219   UninstallExtension(extension_id);
220   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
221   EXPECT_NE(kTestTitle, GetTitle());
222   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
223 }
224 
225 // When an extenion is uninstalled, the state store deletes all preferences
226 // stored for that extension. We need to make sure we don't store anything after
227 // that deletion occurs.
IN_PROC_BROWSER_TEST_F(DeclarativeApiTest,NoTracesAfterUninstalling)228 IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, NoTracesAfterUninstalling) {
229   TestExtensionDir ext_dir;
230 
231   // 1. Install the extension. Verify that rules become active and some prefs
232   // are stored.
233   ext_dir.WriteManifest(GetRedirectToDataManifestWithVersion(1));
234   ext_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
235                     base::StringPrintf("%s%s%s",
236                                        kRedirectToDataConstants,
237                                        kRedirectToDataRules,
238                                        kRedirectToDataInstallRules));
239   ExtensionTestMessageListener ready("ready", /*will_reply=*/false);
240   const Extension* extension = InstallExtensionWithUIAutoConfirm(
241       ext_dir.Pack(), 1 /*+1 installed extension*/, browser());
242   ASSERT_TRUE(extension);
243   std::string extension_id(extension->id());
244   ASSERT_TRUE(ready.WaitUntilSatisfied());
245   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
246   EXPECT_EQ(kTestTitle, GetTitle());
247   EXPECT_EQ(1u, NumberOfRegisteredRules(extension_id));
248   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser()->profile());
249   EXPECT_TRUE(extension_prefs->HasPrefForExtension(extension_id));
250 
251   // 2. Uninstall the extension. Rules are gone and preferences should be empty.
252   UninstallExtension(extension_id);
253   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
254   EXPECT_NE(kTestTitle, GetTitle());
255   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
256   EXPECT_FALSE(extension_prefs->HasPrefForExtension(extension_id));
257 }
258