blob: 713ebf5b21c7c5a000fd36da91fa0713f8776eb6 [file] [log] [blame]
[email protected]a7789f22014-03-12 16:10:381// Copyright 2014 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
dchengc963c7142016-04-08 03:55:225#include "chrome/browser/extensions/extension_web_ui.h"
6
Sylvain Defresne711ff6b2018-10-04 12:33:547#include "base/bind.h"
[email protected]a7789f22014-03-12 16:10:388#include "base/command_line.h"
fdoraycb32419d2016-06-23 15:52:559#include "base/run_loop.h"
avia2f4804a2015-12-24 23:11:1310#include "build/build_config.h"
[email protected]a7789f22014-03-12 16:10:3811#include "chrome/browser/extensions/extension_service.h"
rdevlin.cronin5fafa5a2015-12-30 03:42:0212#include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
[email protected]a7789f22014-03-12 16:10:3813#include "chrome/browser/extensions/test_extension_system.h"
Matt Siembor8db9de02019-05-23 04:26:5814#include "chrome/common/webui_url_constants.h"
[email protected]a7789f22014-03-12 16:10:3815#include "chrome/test/base/testing_profile.h"
Benjamin Ackerman001a7f82018-09-10 14:53:3016#include "components/favicon_base/favicon_callback.h"
17#include "components/favicon_base/favicon_types.h"
Gabriel Charettec7108742019-08-23 03:31:4018#include "content/public/test/browser_task_environment.h"
[email protected]03d25812014-06-22 19:41:5519#include "extensions/browser/extension_system.h"
[email protected]a7789f22014-03-12 16:10:3820#include "extensions/common/extension.h"
21#include "extensions/common/extension_builder.h"
22#include "extensions/common/manifest_constants.h"
23#include "testing/gtest/include/gtest/gtest.h"
Benjamin Ackerman001a7f82018-09-10 14:53:3024#include "third_party/skia/include/core/SkBitmap.h"
25#include "ui/gfx/codec/png_codec.h"
[email protected]a7789f22014-03-12 16:10:3826
27#if defined(OS_CHROMEOS)
[email protected]4d390782014-08-15 09:22:5828#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
A Olsenc63621c2018-08-13 15:32:1729#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
[email protected]a7789f22014-03-12 16:10:3830#endif
31
32namespace extensions {
33
rdevlin.cronin5fafa5a2015-12-30 03:42:0234namespace {
35
dchengc963c7142016-04-08 03:55:2236std::unique_ptr<KeyedService> BuildOverrideRegistrar(
rdevlin.cronin5fafa5a2015-12-30 03:42:0237 content::BrowserContext* context) {
Jinho Bangb5216cec2018-01-17 19:43:1138 return std::make_unique<ExtensionWebUIOverrideRegistrar>(context);
rdevlin.cronin5fafa5a2015-12-30 03:42:0239}
40
41} // namespace
42
[email protected]a7789f22014-03-12 16:10:3843class ExtensionWebUITest : public testing::Test {
44 public:
fdoray2ce6dc222017-04-27 14:39:3945 ExtensionWebUITest() = default;
[email protected]a7789f22014-03-12 16:10:3846
47 protected:
dcheng72191812014-10-28 20:49:5648 void SetUp() override {
[email protected]a7789f22014-03-12 16:10:3849 profile_.reset(new TestingProfile());
50 TestExtensionSystem* system =
51 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_.get()));
52 extension_service_ = system->CreateExtensionService(
avi3ef9ec9e2014-12-22 22:50:1753 base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
rdevlin.cronin5fafa5a2015-12-30 03:42:0254 ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:5455 profile_.get(), base::BindRepeating(&BuildOverrideRegistrar));
rdevlin.cronin5fafa5a2015-12-30 03:42:0256 ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->Get(profile_.get());
[email protected]a7789f22014-03-12 16:10:3857 }
58
dcheng72191812014-10-28 20:49:5659 void TearDown() override {
[email protected]a7789f22014-03-12 16:10:3860 profile_.reset();
fdoraycb32419d2016-06-23 15:52:5561 base::RunLoop().RunUntilIdle();
[email protected]a7789f22014-03-12 16:10:3862 }
63
dchengc963c7142016-04-08 03:55:2264 std::unique_ptr<TestingProfile> profile_;
[email protected]a7789f22014-03-12 16:10:3865 ExtensionService* extension_service_;
Gabriel Charette798fde72019-08-20 22:24:0466 content::BrowserTaskEnvironment task_environment_;
[email protected]a7789f22014-03-12 16:10:3867
68#if defined OS_CHROMEOS
A Olsenc63621c2018-08-13 15:32:1769 chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
[email protected]a7789f22014-03-12 16:10:3870 chromeos::ScopedTestUserManager test_user_manager_;
71#endif
72};
73
74// Test that component extension url overrides have lower priority than
75// non-component extension url overrides.
76TEST_F(ExtensionWebUITest, ExtensionURLOverride) {
rdevlin.cronin2b7cf6a2016-01-27 18:23:5277 const char kOverrideResource[] = "1.html";
[email protected]6584f472014-03-18 17:42:2478 // Register a non-component extension.
[email protected]03d25812014-06-22 19:41:5579 DictionaryBuilder manifest;
[email protected]a7789f22014-03-12 16:10:3880 manifest.Set(manifest_keys::kName, "ext1")
81 .Set(manifest_keys::kVersion, "0.1")
Devlin Cronin1fa235b62018-04-12 14:04:0782 .Set(manifest_keys::kManifestVersion, 2)
[email protected]a7789f22014-03-12 16:10:3883 .Set(std::string(manifest_keys::kChromeURLOverrides),
dcheng794d2bd2016-02-27 03:51:3284 DictionaryBuilder().Set("bookmarks", kOverrideResource).Build());
Devlin Cronin8e5892f2018-10-04 00:13:4385 scoped_refptr<const Extension> ext_unpacked(
[email protected]03d25812014-06-22 19:41:5586 ExtensionBuilder()
dcheng794d2bd2016-02-27 03:51:3287 .SetManifest(manifest.Build())
[email protected]6584f472014-03-18 17:42:2488 .SetLocation(Manifest::UNPACKED)
[email protected]a7789f22014-03-12 16:10:3889 .SetID("abcdefghijabcdefghijabcdefghijaa")
90 .Build());
[email protected]03d25812014-06-22 19:41:5591 extension_service_->AddExtension(ext_unpacked.get());
[email protected]a7789f22014-03-12 16:10:3892
rdevlin.cronin2b7cf6a2016-01-27 18:23:5293 const GURL kExpectedUnpackedOverrideUrl =
94 ext_unpacked->GetResourceURL(kOverrideResource);
Matt Siembor8db9de02019-05-23 04:26:5895 const GURL kBookmarksUrl(chrome::kChromeUIBookmarksURL);
rdevlin.cronin2b7cf6a2016-01-27 18:23:5296 GURL changed_url = kBookmarksUrl;
97 EXPECT_TRUE(
98 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
99 EXPECT_EQ(kExpectedUnpackedOverrideUrl, changed_url);
100 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
101 profile_.get()));
102 EXPECT_EQ(kBookmarksUrl, changed_url);
103
104 GURL url_plus_fragment = kBookmarksUrl.Resolve("#1");
105 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverride(&url_plus_fragment,
106 profile_.get()));
107 EXPECT_EQ(kExpectedUnpackedOverrideUrl.Resolve("#1"),
108 url_plus_fragment);
109 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&url_plus_fragment,
110 profile_.get()));
111 EXPECT_EQ(kBookmarksUrl.Resolve("#1"), url_plus_fragment);
[email protected]6584f472014-03-18 17:42:24112
113 // Register a component extension
rdevlin.cronin2b7cf6a2016-01-27 18:23:52114 const char kOverrideResource2[] = "2.html";
[email protected]03d25812014-06-22 19:41:55115 DictionaryBuilder manifest2;
[email protected]a7789f22014-03-12 16:10:38116 manifest2.Set(manifest_keys::kName, "ext2")
117 .Set(manifest_keys::kVersion, "0.1")
Devlin Cronin1fa235b62018-04-12 14:04:07118 .Set(manifest_keys::kManifestVersion, 2)
[email protected]a7789f22014-03-12 16:10:38119 .Set(std::string(manifest_keys::kChromeURLOverrides),
dcheng794d2bd2016-02-27 03:51:32120 DictionaryBuilder().Set("bookmarks", kOverrideResource2).Build());
Devlin Cronin8e5892f2018-10-04 00:13:43121 scoped_refptr<const Extension> ext_component(
[email protected]03d25812014-06-22 19:41:55122 ExtensionBuilder()
dcheng794d2bd2016-02-27 03:51:32123 .SetManifest(manifest2.Build())
[email protected]6584f472014-03-18 17:42:24124 .SetLocation(Manifest::COMPONENT)
[email protected]a7789f22014-03-12 16:10:38125 .SetID("bbabcdefghijabcdefghijabcdefghij")
126 .Build());
[email protected]03d25812014-06-22 19:41:55127 extension_service_->AddComponentExtension(ext_component.get());
[email protected]a7789f22014-03-12 16:10:38128
[email protected]6584f472014-03-18 17:42:24129 // Despite being registered more recently, the component extension should
[email protected]3b09cec52014-05-15 00:33:41130 // not take precedence over the non-component extension.
rdevlin.cronin2b7cf6a2016-01-27 18:23:52131 changed_url = kBookmarksUrl;
132 EXPECT_TRUE(
133 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
134 EXPECT_EQ(kExpectedUnpackedOverrideUrl, changed_url);
135 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
136 profile_.get()));
137 EXPECT_EQ(kBookmarksUrl, changed_url);
[email protected]a7789f22014-03-12 16:10:38138
rdevlin.cronin2b7cf6a2016-01-27 18:23:52139 GURL kExpectedComponentOverrideUrl =
140 ext_component->GetResourceURL(kOverrideResource2);
[email protected]6584f472014-03-18 17:42:24141
[email protected]a7789f22014-03-12 16:10:38142 // Unregister non-component extension. Only component extension remaining.
143 ExtensionWebUI::UnregisterChromeURLOverrides(
144 profile_.get(), URLOverrides::GetChromeURLOverrides(ext_unpacked.get()));
rdevlin.cronin2b7cf6a2016-01-27 18:23:52145 changed_url = kBookmarksUrl;
146 EXPECT_TRUE(
147 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
148 EXPECT_EQ(kExpectedComponentOverrideUrl, changed_url);
149 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
150 profile_.get()));
151 EXPECT_EQ(kBookmarksUrl, changed_url);
[email protected]a7789f22014-03-12 16:10:38152
[email protected]6584f472014-03-18 17:42:24153 // This time the non-component extension was registered more recently and
154 // should still take precedence.
rdevlin.cronin5fafa5a2015-12-30 03:42:02155 ExtensionWebUI::RegisterOrActivateChromeURLOverrides(
[email protected]a7789f22014-03-12 16:10:38156 profile_.get(), URLOverrides::GetChromeURLOverrides(ext_unpacked.get()));
rdevlin.cronin2b7cf6a2016-01-27 18:23:52157 changed_url = kBookmarksUrl;
158 EXPECT_TRUE(
159 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
160 EXPECT_EQ(kExpectedUnpackedOverrideUrl, changed_url);
161 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
162 profile_.get()));
163 EXPECT_EQ(kBookmarksUrl, changed_url);
[email protected]a7789f22014-03-12 16:10:38164}
165
Devlin Cronin313da2812017-11-10 17:40:40166TEST_F(ExtensionWebUITest, TestRemovingDuplicateEntriesForHosts) {
167 // Test that duplicate entries for a single extension are removed. This could
168 // happen because of https://crbug.com/782959.
Devlin Cronin313da2812017-11-10 17:40:40169 scoped_refptr<const Extension> extension =
170 ExtensionBuilder("extension")
Devlin Cronin98cd6582018-05-08 19:18:12171 .SetManifestPath({"chrome_url_overrides", "newtab"}, "newtab.html")
Devlin Cronin313da2812017-11-10 17:40:40172 .Build();
173
174 const GURL newtab_url = extension->GetResourceURL("newtab.html");
175
176 PrefService* prefs = profile_->GetPrefs();
177 {
178 // Add multiple entries for the same extension.
179 DictionaryPrefUpdate update(prefs, ExtensionWebUI::kExtensionURLOverrides);
180 base::DictionaryValue* all_overrides = update.Get();
181 base::Value newtab_list(base::Value::Type::LIST);
182 {
183 base::Value newtab(base::Value::Type::DICTIONARY);
184 newtab.SetKey("entry", base::Value(newtab_url.spec()));
185 newtab.SetKey("active", base::Value(true));
Jan Wilken Dörrie91e4ef02019-09-11 08:22:12186 newtab_list.Append(std::move(newtab));
Devlin Cronin313da2812017-11-10 17:40:40187 }
188 {
189 base::Value newtab(base::Value::Type::DICTIONARY);
190 newtab.SetKey(
191 "entry",
192 base::Value(extension->GetResourceURL("oldtab.html").spec()));
193 newtab.SetKey("active", base::Value(true));
Jan Wilken Dörrie91e4ef02019-09-11 08:22:12194 newtab_list.Append(std::move(newtab));
Devlin Cronin313da2812017-11-10 17:40:40195 }
196
197 all_overrides->SetKey("newtab", std::move(newtab_list));
198 }
199
200 extension_service_->AddExtension(extension.get());
201 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_.get()))
202 ->SetReady();
203 base::RunLoop().RunUntilIdle();
204
205 // Duplicates should be removed (in response to ExtensionSystem::ready()).
206 // Only a single entry should remain.
207 const base::DictionaryValue* overrides =
208 prefs->GetDictionary(ExtensionWebUI::kExtensionURLOverrides);
209 ASSERT_TRUE(overrides);
210 const base::Value* newtab_overrides =
211 overrides->FindKeyOfType("newtab", base::Value::Type::LIST);
212 ASSERT_TRUE(newtab_overrides);
213 ASSERT_EQ(1u, newtab_overrides->GetList().size());
214 const base::Value& override_dict = newtab_overrides->GetList()[0];
215 EXPECT_EQ(newtab_url.spec(), override_dict.FindKey("entry")->GetString());
216 EXPECT_TRUE(override_dict.FindKey("active")->GetBool());
217}
218
Benjamin Ackerman001a7f82018-09-10 14:53:30219TEST_F(ExtensionWebUITest, TestFaviconAlwaysAvailable) {
220 scoped_refptr<const Extension> extension =
221 ExtensionBuilder("extension").Build();
222 extension_service_->AddExtension(extension.get());
223 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_.get()))
224 ->SetReady();
225
226 const GURL kExtensionManifestURL = extension->GetResourceURL("manifest.json");
227
228 std::vector<favicon_base::FaviconRawBitmapResult> favicon_results;
229 auto set_favicon_results =
230 [](std::vector<favicon_base::FaviconRawBitmapResult>* favicons_out,
231 base::RepeatingClosure quit_closure,
232 const std::vector<favicon_base::FaviconRawBitmapResult>& favicons) {
233 *favicons_out = favicons;
234 std::move(quit_closure).Run();
235 };
236
237 base::RunLoop run_loop;
238 ExtensionWebUI::GetFaviconForURL(
239 profile_.get(), kExtensionManifestURL,
Jan Wilken Dörrie1a7df9482020-04-01 17:34:10240 base::BindOnce(set_favicon_results, &favicon_results,
241 run_loop.QuitClosure()));
Benjamin Ackerman001a7f82018-09-10 14:53:30242
243 run_loop.Run();
244 EXPECT_FALSE(favicon_results.empty());
245
246 // Verify that the favicon bitmaps are not empty and are valid.
247 for (const auto& favicon : favicon_results) {
248 EXPECT_TRUE(favicon.is_valid());
249
250 SkBitmap bitmap;
251 bool result =
252 gfx::PNGCodec::Decode(favicon.bitmap_data.get()->front(),
253 favicon.bitmap_data.get()->size(), &bitmap);
254 EXPECT_TRUE(result);
255 EXPECT_FALSE(bitmap.isNull());
256 EXPECT_FALSE(bitmap.drawsNothing());
257 }
258}
259
[email protected]a7789f22014-03-12 16:10:38260} // namespace extensions