blob: 8612fdde0ed4d03d492838a9d219beaa901424ce [file] [log] [blame]
[email protected]1791e6c92014-04-11 08:29:011// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]5e212ed2012-03-21 23:29:152// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avia2f4804a2015-12-24 23:11:135#include <stddef.h>
6
dchengc963c7142016-04-08 03:55:227#include <memory>
[email protected]5e212ed2012-03-21 23:29:158#include <string>
vabr9984ea62017-04-10 11:33:499#include <utility>
[email protected]5e212ed2012-03-21 23:29:1510
lazyboyd6dbb262017-03-30 00:57:3011#include "base/command_line.h"
Lei Zhang1f46798c2021-05-26 01:35:1812#include "base/cxx17_backports.h"
thestigc9e38a22014-09-13 01:02:1113#include "base/files/file_util.h"
Clark DuVallc7e3b4692019-06-13 22:07:1114#include "base/path_service.h"
fdoraycb32419d2016-06-23 15:52:5515#include "base/run_loop.h"
[email protected]774cebd2013-09-26 04:55:0116#include "base/strings/string_number_conversions.h"
[email protected]00e7bef2013-06-10 20:35:1717#include "base/strings/string_util.h"
Etienne Bergeron09479972021-04-13 13:23:4518#include "base/test/power_monitor_test.h"
lazyboyd6dbb262017-03-30 00:57:3019#include "base/test/test_file_util.h"
Devlin Croninc3f88072018-01-30 02:10:1120#include "base/test/values_test_util.h"
[email protected]06492ed2013-03-24 22:13:1421#include "base/values.h"
Kevin Marshall4cab5af2019-01-14 20:27:1422#include "build/build_config.h"
lazyboyd6dbb262017-03-30 00:57:3023#include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
Ryan Keane4a17bdf2020-06-23 22:15:5724#include "chrome/browser/extensions/chrome_extensions_browser_client.h"
[email protected]93ac047a2012-12-13 02:53:4925#include "chrome/common/chrome_paths.h"
lazyboyd6dbb262017-03-30 00:57:3026#include "chrome/common/chrome_switches.h"
27#include "chrome/test/base/testing_profile.h"
28#include "components/crx_file/id_util.h"
Matt Falkenhagenae65b292018-04-25 16:03:2729#include "content/public/browser/render_process_host.h"
Gabriel Charettec7108742019-08-23 03:31:4030#include "content/public/test/browser_task_environment.h"
Chris Mumford8f812662018-02-22 00:27:5731#include "content/public/test/test_renderer_host.h"
lazyboyd6dbb262017-03-30 00:57:3032#include "content/public/test/test_utils.h"
Chris Mumford8f812662018-02-22 00:27:5733#include "content/public/test/web_contents_tester.h"
lazyboyd6dbb262017-03-30 00:57:3034#include "extensions/browser/content_verifier.h"
Istiaque Ahmed72816eaa2018-01-30 22:37:0635#include "extensions/browser/content_verifier/test_utils.h"
Chris Mumford8f812662018-02-22 00:27:5736#include "extensions/browser/extension_prefs.h"
[email protected]1791e6c92014-04-11 08:29:0137#include "extensions/browser/extension_protocols.h"
Chris Mumford8f812662018-02-22 00:27:5738#include "extensions/browser/extension_registry.h"
John Abd-El-Malekea006302018-05-10 05:50:4639#include "extensions/browser/extension_system.h"
[email protected]38427a12013-11-09 17:34:2040#include "extensions/browser/info_map.h"
Devlin Croninc9c4efe2020-01-07 21:04:0541#include "extensions/browser/unloaded_extension_reason.h"
[email protected]e4452d32013-11-15 23:07:4142#include "extensions/common/extension.h"
lazyboyd6dbb262017-03-30 00:57:3043#include "extensions/common/extension_builder.h"
Istiaque Ahmed72816eaa2018-01-30 22:37:0644#include "extensions/common/extension_paths.h"
asargenta093ec32016-02-13 01:36:4345#include "extensions/common/file_util.h"
Maks Orlovich5408ddfc2020-07-28 23:07:3546#include "extensions/common/identifiability_metrics.h"
Devlin Cronin1fa235b62018-04-12 14:04:0747#include "extensions/common/value_builder.h"
Devlin Croninc3f88072018-01-30 02:10:1148#include "extensions/test/test_extension_dir.h"
Julie Jeongeun Kim917c197902019-11-26 03:36:1449#include "mojo/public/cpp/bindings/pending_remote.h"
rhalavati04b93382017-04-07 19:00:5450#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
Yue Ru Sun03a6990a2020-10-24 18:04:3151#include "services/metrics/public/cpp/ukm_source_id.h"
Julie Jeongeun Kimab3f20d2020-12-08 05:01:1552#include "services/network/public/mojom/fetch_api.mojom.h"
Chris Mumford8f812662018-02-22 00:27:5753#include "services/network/test/test_url_loader_client.h"
Ryan Keane4a17bdf2020-06-23 22:15:5754#include "testing/gmock/include/gmock/gmock.h"
[email protected]5e212ed2012-03-21 23:29:1555#include "testing/gtest/include/gtest/gtest.h"
Anton Bikineev46bbb972021-05-15 17:53:5356#include "third_party/abseil-cpp/absl/types/optional.h"
Hiroki Nakagawa41366152020-07-27 18:31:4057#include "third_party/blink/public/common/loader/previews_state.h"
Minggang Wang1daff4ec2020-08-13 05:06:1758#include "third_party/blink/public/common/loader/referrer_utils.h"
Maks Orlovich5408ddfc2020-07-28 23:07:3559#include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
60#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
61#include "third_party/blink/public/common/privacy_budget/scoped_identifiability_test_sample_collector.h"
[email protected]5e212ed2012-03-21 23:29:1562
Chris Mumford8f812662018-02-22 00:27:5763using extensions::ExtensionRegistry;
64using network::mojom::URLLoader;
Ryan Keane4a17bdf2020-06-23 22:15:5765using testing::_;
66using testing::StrictMock;
[email protected]7491ad02014-07-05 19:10:0767
[email protected]702d8b42013-02-27 20:55:5068namespace extensions {
jamescook8816ae52014-09-05 17:02:3769namespace {
[email protected]5e212ed2012-03-21 23:29:1570
Ryan Keane4a17bdf2020-06-23 22:15:5771// Default extension id to use for extension generation when none is set.
72constexpr char kEmptyExtensionId[] = "";
73
asargenta093ec32016-02-13 01:36:4374base::FilePath GetTestPath(const std::string& name) {
75 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:5276 EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &path));
asargenta093ec32016-02-13 01:36:4377 return path.AppendASCII("extensions").AppendASCII(name);
78}
79
Istiaque Ahmed72816eaa2018-01-30 22:37:0680base::FilePath GetContentVerifierTestPath() {
81 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:5282 EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &path));
Istiaque Ahmed72816eaa2018-01-30 22:37:0683 return path.AppendASCII("content_hash_fetcher")
84 .AppendASCII("different_sized_files");
lazyboyd6dbb262017-03-30 00:57:3085}
86
[email protected]5e212ed2012-03-21 23:29:1587scoped_refptr<Extension> CreateTestExtension(const std::string& name,
Ryan Keane4a17bdf2020-06-23 22:15:5788 bool incognito_split_mode,
89 const ExtensionId& extension_id) {
[email protected]023b3d12013-12-23 18:46:4990 base::DictionaryValue manifest;
[email protected]5e212ed2012-03-21 23:29:1591 manifest.SetString("name", name);
92 manifest.SetString("version", "1");
[email protected]b109bdd2013-11-04 18:08:4393 manifest.SetInteger("manifest_version", 2);
[email protected]5e212ed2012-03-21 23:29:1594 manifest.SetString("incognito", incognito_split_mode ? "split" : "spanning");
95
asargenta093ec32016-02-13 01:36:4396 base::FilePath path = GetTestPath("response_headers");
[email protected]5e212ed2012-03-21 23:29:1597
98 std::string error;
99 scoped_refptr<Extension> extension(
Gyuyoung Kimabc23382021-03-18 03:09:18100 Extension::Create(path, mojom::ManifestLocation::kInternal, manifest,
101 Extension::NO_FLAGS, extension_id, &error));
[email protected]5e212ed2012-03-21 23:29:15102 EXPECT_TRUE(extension.get()) << error;
103 return extension;
104}
105
Ryan Keane4a17bdf2020-06-23 22:15:57106scoped_refptr<Extension> CreateTestExtension(const std::string& name,
107 bool incognito_split_mode) {
108 return CreateTestExtension(name, incognito_split_mode, kEmptyExtensionId);
109}
110
[email protected]93ac047a2012-12-13 02:53:49111scoped_refptr<Extension> CreateWebStoreExtension() {
Devlin Croninf43c3312018-03-27 19:54:17112 std::unique_ptr<base::DictionaryValue> manifest =
113 DictionaryBuilder()
114 .Set("name", "WebStore")
115 .Set("version", "1")
116 .Set("manifest_version", 2)
117 .Set("icons",
118 DictionaryBuilder().Set("16", "webstore_icon_16.png").Build())
119 .Set("web_accessible_resources",
120 ListBuilder().Append("webstore_icon_16.png").Build())
121 .Build();
[email protected]93ac047a2012-12-13 02:53:49122
[email protected]650b2d52013-02-10 03:41:45123 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:52124 EXPECT_TRUE(base::PathService::Get(chrome::DIR_RESOURCES, &path));
[email protected]93ac047a2012-12-13 02:53:49125 path = path.AppendASCII("web_store");
126
127 std::string error;
Gyuyoung Kimabc23382021-03-18 03:09:18128 scoped_refptr<Extension> extension(
129 Extension::Create(path, mojom::ManifestLocation::kComponent, *manifest,
130 Extension::NO_FLAGS, &error));
[email protected]93ac047a2012-12-13 02:53:49131 EXPECT_TRUE(extension.get()) << error;
132 return extension;
133}
134
Devlin Cronin8e5892f2018-10-04 00:13:43135scoped_refptr<const Extension> CreateTestResponseHeaderExtension() {
Devlin Cronin1fa235b62018-04-12 14:04:07136 return ExtensionBuilder("An extension with web-accessible resources")
Devlin Cronin98cd6582018-05-08 19:18:12137 .SetManifestKey("web_accessible_resources",
138 ListBuilder().Append("test.dat").Build())
Devlin Cronin1fa235b62018-04-12 14:04:07139 .SetPath(GetTestPath("response_headers"))
140 .Build();
[email protected]6f7d7062013-06-04 03:49:33141}
142
Chris Mumford8f812662018-02-22 00:27:57143// Helper function to create a |ResourceRequest| for testing purposes.
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15144network::ResourceRequest CreateResourceRequest(
145 const std::string& method,
146 network::mojom::RequestDestination destination,
147 const GURL& url) {
Chris Mumford8f812662018-02-22 00:27:57148 network::ResourceRequest request;
149 request.method = method;
150 request.url = url;
Maks Orlovich5d02d9e02019-12-15 22:14:10151 request.site_for_cookies =
152 net::SiteForCookies::FromUrl(url); // bypass third-party cookie blocking.
Chris Mumford8f812662018-02-22 00:27:57153 request.request_initiator =
154 url::Origin::Create(url); // ensure initiator set.
Minggang Wang1daff4ec2020-08-13 05:06:17155 request.referrer_policy = blink::ReferrerUtils::GetDefaultNetReferrerPolicy();
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15156 request.destination = destination;
Minggang Wangee5af392020-02-05 02:55:28157 request.is_main_frame =
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15158 destination == network::mojom::RequestDestination::kDocument;
Chris Mumford8f812662018-02-22 00:27:57159 return request;
160}
161
Chris Mumford8f812662018-02-22 00:27:57162// The result of either a URLRequest of a URLLoader response (but not both)
163// depending on the on test type.
164class GetResult {
165 public:
Lucas Furukawa Gadani06902602019-09-27 20:44:27166 GetResult(network::mojom::URLResponseHeadPtr response, int result)
167 : response_(std::move(response)), result_(result) {}
Clark DuVallc7e3b4692019-06-13 22:07:11168 GetResult(GetResult&& other) : result_(other.result_) {}
Peter Boström53c6c5952021-09-17 09:41:26169
170 GetResult(const GetResult&) = delete;
171 GetResult& operator=(const GetResult&) = delete;
172
Chris Mumford8f812662018-02-22 00:27:57173 ~GetResult() = default;
174
175 std::string GetResponseHeaderByName(const std::string& name) const {
176 std::string value;
Lucas Furukawa Gadani06902602019-09-27 20:44:27177 if (response_ && response_->headers)
178 response_->headers->GetNormalizedHeader(name, &value);
Chris Mumford8f812662018-02-22 00:27:57179 return value;
180 }
181
182 int result() const { return result_; }
183
184 private:
Lucas Furukawa Gadani06902602019-09-27 20:44:27185 network::mojom::URLResponseHeadPtr response_;
Chris Mumford8f812662018-02-22 00:27:57186 int result_;
Chris Mumford8f812662018-02-22 00:27:57187};
188
jamescook8816ae52014-09-05 17:02:37189} // namespace
190
191// This test lives in src/chrome instead of src/extensions because it tests
192// functionality delegated back to Chrome via ChromeExtensionsBrowserClient.
lfg048201a2014-09-16 19:09:36193// See chrome/browser/extensions/chrome_url_request_util.cc.
Clark DuVallc7e3b4692019-06-13 22:07:11194class ExtensionProtocolsTestBase : public testing::Test {
[email protected]5e212ed2012-03-21 23:29:15195 public:
Alexey Baskakovf0f9d8f2019-01-19 02:31:54196 explicit ExtensionProtocolsTestBase(bool force_incognito)
Gabriel Charette798fde72019-08-20 22:24:04197 : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
Chris Mumford8f812662018-02-22 00:27:57198 rvh_test_enabler_(new content::RenderViewHostTestEnabler()),
Maks Orlovich5408ddfc2020-07-28 23:07:35199 force_incognito_(force_incognito),
Yue Ru Sun03a6990a2020-10-24 18:04:31200 test_ukm_id_(ukm::SourceIdObj::New()) {}
[email protected]5e212ed2012-03-21 23:29:15201
dcheng72191812014-10-28 20:49:56202 void SetUp() override {
[email protected]06492ed2013-03-24 22:13:14203 testing::Test::SetUp();
lazyboyd6dbb262017-03-30 00:57:30204 testing_profile_ = TestingProfile::Builder().Build();
Erik Chen5bab4992018-05-05 15:19:53205 contents_ = CreateTestWebContents();
lazyboyd6dbb262017-03-30 00:57:30206
207 // Set up content verification.
208 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
209 command_line->AppendSwitchASCII(
210 switches::kExtensionContentVerification,
211 switches::kExtensionContentVerificationEnforce);
212 content_verifier_ = new ContentVerifier(
Chris Mumford8f812662018-02-22 00:27:57213 browser_context(),
214 std::make_unique<ChromeContentVerifierDelegate>(browser_context()));
John Abd-El-Malekea006302018-05-10 05:50:46215 info_map()->SetContentVerifier(content_verifier_.get());
[email protected]5e212ed2012-03-21 23:29:15216 }
217
dcheng72191812014-10-28 20:49:56218 void TearDown() override {
Chris Mumford8f812662018-02-22 00:27:57219 loader_factory_.reset();
lazyboyd6dbb262017-03-30 00:57:30220 content_verifier_->Shutdown();
Matt Menkedb9fc40b2019-06-19 17:57:35221 // Shut down the PowerMonitor if initialized.
222 base::PowerMonitor::ShutdownForTesting();
[email protected]5e212ed2012-03-21 23:29:15223 }
224
[email protected]1791e6c92014-04-11 08:29:01225 void SetProtocolHandler(bool is_incognito) {
Lukasz Anforowicza782c5a2020-09-26 02:15:17226 loader_factory_.Bind(extensions::CreateExtensionNavigationURLLoaderFactory(
227 browser_context(), test_ukm_id_, false));
[email protected]93ac047a2012-12-13 02:53:49228 }
229
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15230 GetResult RequestOrLoad(const GURL& url,
231 network::mojom::RequestDestination destination) {
232 return LoadURL(url, destination);
Chris Mumford8f812662018-02-22 00:27:57233 }
234
235 void AddExtension(const scoped_refptr<const Extension>& extension,
236 bool incognito_enabled,
237 bool notifications_disabled) {
John Abd-El-Malekea006302018-05-10 05:50:46238 info_map()->AddExtension(extension.get(), base::Time::Now(),
239 incognito_enabled, notifications_disabled);
Clark DuVallc7e3b4692019-06-13 22:07:11240 EXPECT_TRUE(extension_registry()->AddEnabled(extension));
241 ExtensionPrefs::Get(browser_context())
242 ->SetIsIncognitoEnabled(extension->id(), incognito_enabled);
Chris Mumford8f812662018-02-22 00:27:57243 }
244
245 void RemoveExtension(const scoped_refptr<const Extension>& extension,
246 const UnloadedExtensionReason reason) {
John Abd-El-Malekea006302018-05-10 05:50:46247 info_map()->RemoveExtension(extension->id(), reason);
Clark DuVallc7e3b4692019-06-13 22:07:11248 EXPECT_TRUE(extension_registry()->RemoveEnabled(extension->id()));
249 if (reason == UnloadedExtensionReason::DISABLE)
250 EXPECT_TRUE(extension_registry()->AddDisabled(extension));
Chris Mumford8f812662018-02-22 00:27:57251 }
252
253 // Helper method to create a URL request/loader, call RequestOrLoad on it, and
254 // return the result. If |extension| hasn't already been added to
John Abd-El-Malekea006302018-05-10 05:50:46255 // info_map(), this will add it.
Chris Mumford8f812662018-02-22 00:27:57256 GetResult DoRequestOrLoad(const scoped_refptr<Extension> extension,
257 const std::string& relative_path) {
John Abd-El-Malekea006302018-05-10 05:50:46258 if (!info_map()->extensions().Contains(extension->id())) {
Chris Mumford8f812662018-02-22 00:27:57259 AddExtension(extension.get(),
260 /*incognito_enabled=*/false,
261 /*notifications_disabled=*/false);
262 }
263 return RequestOrLoad(extension->GetResourceURL(relative_path),
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15264 network::mojom::RequestDestination::kDocument);
Chris Mumford8f812662018-02-22 00:27:57265 }
266
267 ExtensionRegistry* extension_registry() {
268 return ExtensionRegistry::Get(browser_context());
269 }
270
John Abd-El-Malekea006302018-05-10 05:50:46271 InfoMap* info_map() {
272 return ExtensionSystem::Get(browser_context())->info_map();
273 }
274
Alexey Baskakovf0f9d8f2019-01-19 02:31:54275 content::BrowserContext* browser_context() {
Ramin Halavati94e457272021-04-13 12:27:51276 return force_incognito_ ? testing_profile_->GetPrimaryOTRProfile(
277 /*create_if_needed=*/true)
Alexey Baskakovf0f9d8f2019-01-19 02:31:54278 : testing_profile_.get();
279 }
Chris Mumford8f812662018-02-22 00:27:57280
Etienne Bergeron53917b502021-04-06 20:23:56281 void EnableSimulationOfSystemSuspendForRequests() {
282 power_monitor_source_.emplace();
Karandeep Bhatiaab489a4d2018-11-28 21:56:06283 }
284
Ryan Keane4a17bdf2020-06-23 22:15:57285 void AddExtensionAndPerformResourceLoad(const ExtensionId& extension_id) {
286 // Register a non-incognito extension protocol handler.
287 SetProtocolHandler(false);
288
289 scoped_refptr<Extension> extension =
290 CreateTestExtension("foo", false, extension_id);
291 AddExtension(extension, false, false);
292 ASSERT_EQ(extension->id(), extension_id);
293
294 // Load the extension.
295 {
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15296 auto get_result =
297 RequestOrLoad(extension->GetResourceURL("test.dat"),
298 network::mojom::RequestDestination::kDocument);
Ryan Keane4a17bdf2020-06-23 22:15:57299 EXPECT_EQ(net::OK, get_result.result());
300 }
301 }
302
Maks Orlovich5408ddfc2020-07-28 23:07:35303 void ExpectExtensionAccessResult(
304 scoped_refptr<Extension> extension,
305 const std::vector<
306 blink::test::ScopedIdentifiabilityTestSampleCollector::Entry>&
307 entries,
308 ExtensionResourceAccessResult expected) {
309 ASSERT_EQ(1u, entries.size());
Yue Ru Sunb5c5cc3a82020-10-20 23:01:03310 EXPECT_EQ(test_ukm_id_.ToInt64(), entries[0].source);
Maks Orlovich5408ddfc2020-07-28 23:07:35311 ASSERT_EQ(1u, entries[0].metrics.size());
Asanka Herath74ec31fc2020-09-29 05:30:43312 EXPECT_EQ(blink::IdentifiableSurface::FromTypeAndToken(
Maks Orlovich5408ddfc2020-07-28 23:07:35313 blink::IdentifiableSurface::Type::kExtensionFileAccess,
Asanka Herath74ec31fc2020-09-29 05:30:43314 base::as_bytes(base::make_span(extension->id()))),
315 entries[0].metrics[0].surface);
316 EXPECT_EQ(blink::IdentifiableToken(expected), entries[0].metrics[0].value);
Maks Orlovich5408ddfc2020-07-28 23:07:35317 }
318
Chris Mumford8f812662018-02-22 00:27:57319 protected:
320 scoped_refptr<ContentVerifier> content_verifier_;
Chris Mumford8f812662018-02-22 00:27:57321
322 private:
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15323 GetResult LoadURL(const GURL& url,
324 network::mojom::RequestDestination destination) {
Chris Mumford8f812662018-02-22 00:27:57325 constexpr int32_t kRequestId = 28;
326
Julie Jeongeun Kim917c197902019-11-26 03:36:14327 mojo::PendingRemote<network::mojom::URLLoader> loader;
Chris Mumford8f812662018-02-22 00:27:57328 network::TestURLLoaderClient client;
329 loader_factory_->CreateLoaderAndStart(
Dave Tapuska28226d042021-03-17 14:21:29330 loader.InitWithNewPipeAndPassReceiver(), kRequestId,
Chris Mumford8f812662018-02-22 00:27:57331 network::mojom::kURLLoadOptionNone,
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15332 CreateResourceRequest("GET", destination, url), client.CreateRemote(),
Chris Mumford8f812662018-02-22 00:27:57333 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
334
Etienne Bergeron53917b502021-04-06 20:23:56335 // If `power_monitor_source_` is set, simulates power suspend and resume
336 // notifications. These notifications are posted tasks that will be executed
337 // by `client.RunUntilComplete()`.
Karandeep Bhatiaab489a4d2018-11-28 21:56:06338 if (power_monitor_source_) {
Etienne Bergeron53917b502021-04-06 20:23:56339 power_monitor_source_->Suspend();
340 power_monitor_source_->Resume();
Karandeep Bhatiaab489a4d2018-11-28 21:56:06341 }
342
Chris Mumford8f812662018-02-22 00:27:57343 client.RunUntilComplete();
Lucas Furukawa Gadani06902602019-09-27 20:44:27344 return GetResult(client.response_head().Clone(),
Chris Mumford8f812662018-02-22 00:27:57345 client.completion_status().error_code);
346 }
347
Erik Chen5bab4992018-05-05 15:19:53348 std::unique_ptr<content::WebContents> CreateTestWebContents() {
Chris Mumford8f812662018-02-22 00:27:57349 auto site_instance = content::SiteInstance::Create(browser_context());
350 return content::WebContentsTester::CreateTestWebContents(
351 browser_context(), std::move(site_instance));
asargenta093ec32016-02-13 01:36:43352 }
353
Chris Mumford8f812662018-02-22 00:27:57354 content::WebContents* web_contents() { return contents_.get(); }
355
356 content::RenderFrameHost* main_rfh() {
357 return web_contents()->GetMainFrame();
358 }
359
Gabriel Charette798fde72019-08-20 22:24:04360 content::BrowserTaskEnvironment task_environment_;
Chris Mumford8f812662018-02-22 00:27:57361 std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_;
Lukasz Anforowicza782c5a2020-09-26 02:15:17362 mojo::Remote<network::mojom::URLLoaderFactory> loader_factory_;
lazyboyd6dbb262017-03-30 00:57:30363 std::unique_ptr<TestingProfile> testing_profile_;
Chris Mumford8f812662018-02-22 00:27:57364 std::unique_ptr<content::WebContents> contents_;
Alexey Baskakovf0f9d8f2019-01-19 02:31:54365 const bool force_incognito_;
Yue Ru Sun03a6990a2020-10-24 18:04:31366 const ukm::SourceIdObj test_ukm_id_;
Karandeep Bhatiaab489a4d2018-11-28 21:56:06367
Anton Bikineev46bbb972021-05-15 17:53:53368 absl::optional<base::test::ScopedPowerMonitorTestSource>
Etienne Bergeron53917b502021-04-06 20:23:56369 power_monitor_source_;
[email protected]5e212ed2012-03-21 23:29:15370};
371
Alexey Baskakovf0f9d8f2019-01-19 02:31:54372class ExtensionProtocolsTest : public ExtensionProtocolsTestBase {
373 public:
374 ExtensionProtocolsTest()
375 : ExtensionProtocolsTestBase(false /*force_incognito*/) {}
376};
377
378class ExtensionProtocolsIncognitoTest : public ExtensionProtocolsTestBase {
379 public:
380 ExtensionProtocolsIncognitoTest()
381 : ExtensionProtocolsTestBase(true /*force_incognito*/) {}
382};
383
[email protected]5e212ed2012-03-21 23:29:15384// Tests that making a chrome-extension request in an incognito context is
385// only allowed under the right circumstances (if the extension is allowed
386// in incognito, and it's either a non-main-frame request or a split-mode
387// extension).
Clark DuVallc7e3b4692019-06-13 22:07:11388TEST_F(ExtensionProtocolsIncognitoTest, IncognitoRequest) {
[email protected]93ac047a2012-12-13 02:53:49389 // Register an incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01390 SetProtocolHandler(true);
[email protected]93ac047a2012-12-13 02:53:49391
[email protected]5e212ed2012-03-21 23:29:15392 struct TestCase {
393 // Inputs.
394 std::string name;
395 bool incognito_split_mode;
396 bool incognito_enabled;
397
398 // Expected results.
399 bool should_allow_main_frame_load;
400 bool should_allow_sub_frame_load;
401 } cases[] = {
Ryan Keane4a17bdf2020-06-23 22:15:57402 {"spanning disabled", false, false, false, false},
403 {"split disabled", true, false, false, false},
404 {"spanning enabled", false, true, false, false},
405 {"split enabled", true, true, true, false},
[email protected]5e212ed2012-03-21 23:29:15406 };
407
Avi Drissman5f0fb8c2018-12-25 23:20:49408 for (size_t i = 0; i < base::size(cases); ++i) {
[email protected]5e212ed2012-03-21 23:29:15409 scoped_refptr<Extension> extension =
410 CreateTestExtension(cases[i].name, cases[i].incognito_split_mode);
Chris Mumford8f812662018-02-22 00:27:57411 AddExtension(extension, cases[i].incognito_enabled, false);
[email protected]5e212ed2012-03-21 23:29:15412
413 // First test a main frame request.
414 {
Maks Orlovich5408ddfc2020-07-28 23:07:35415 blink::test::ScopedIdentifiabilityTestSampleCollector metrics;
416
[email protected]5e212ed2012-03-21 23:29:15417 // It doesn't matter that the resource doesn't exist. If the resource
naskob9164c42016-06-07 01:21:35418 // is blocked, we should see BLOCKED_BY_CLIENT. Otherwise, the request
[email protected]5e212ed2012-03-21 23:29:15419 // should just fail because the file doesn't exist.
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15420 auto get_result =
421 RequestOrLoad(extension->GetResourceURL("404.html"),
422 network::mojom::RequestDestination::kDocument);
[email protected]5e212ed2012-03-21 23:29:15423
424 if (cases[i].should_allow_main_frame_load) {
Chris Mumford8f812662018-02-22 00:27:57425 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, get_result.result())
maksim.sisov1b83bb72016-10-07 06:07:23426 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15427 } else {
Chris Mumford8f812662018-02-22 00:27:57428 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, get_result.result())
naskob9164c42016-06-07 01:21:35429 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15430 }
Maks Orlovich5408ddfc2020-07-28 23:07:35431
432 // Either way it's a failure to the outside.
433 ExpectExtensionAccessResult(extension, metrics.entries(),
434 ExtensionResourceAccessResult::kFailure);
[email protected]5e212ed2012-03-21 23:29:15435 }
436
John Abd-El-Malek2305cdc2018-02-14 20:26:28437 // Subframe navigation requests are blocked in ExtensionNavigationThrottle
438 // which isn't added in this unit test. This is tested in an integration
439 // test in ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
Chris Mumford8f812662018-02-22 00:27:57440 RemoveExtension(extension, UnloadedExtensionReason::UNINSTALL);
[email protected]5e212ed2012-03-21 23:29:15441 }
442}
443
Chris Mumford8f812662018-02-22 00:27:57444void CheckForContentLengthHeader(const GetResult& get_result) {
445 std::string content_length = get_result.GetResponseHeaderByName(
446 net::HttpRequestHeaders::kContentLength);
447
[email protected]774cebd2013-09-26 04:55:01448 EXPECT_FALSE(content_length.empty());
449 int length_value = 0;
450 EXPECT_TRUE(base::StringToInt(content_length, &length_value));
451 EXPECT_GT(length_value, 0);
452}
453
[email protected]93ac047a2012-12-13 02:53:49454// Tests getting a resource for a component extension works correctly, both when
455// the extension is enabled and when it is disabled.
Clark DuVallc7e3b4692019-06-13 22:07:11456TEST_F(ExtensionProtocolsTest, ComponentResourceRequest) {
[email protected]93ac047a2012-12-13 02:53:49457 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01458 SetProtocolHandler(false);
[email protected]93ac047a2012-12-13 02:53:49459
460 scoped_refptr<Extension> extension = CreateWebStoreExtension();
Chris Mumford8f812662018-02-22 00:27:57461 AddExtension(extension, false, false);
[email protected]93ac047a2012-12-13 02:53:49462
463 // First test it with the extension enabled.
464 {
Maks Orlovich5408ddfc2020-07-28 23:07:35465 blink::test::ScopedIdentifiabilityTestSampleCollector metrics;
466
Chris Mumford8f812662018-02-22 00:27:57467 auto get_result =
468 RequestOrLoad(extension->GetResourceURL("webstore_icon_16.png"),
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15469 network::mojom::RequestDestination::kVideo);
Chris Mumford8f812662018-02-22 00:27:57470 EXPECT_EQ(net::OK, get_result.result());
471 CheckForContentLengthHeader(get_result);
472 EXPECT_EQ("image/png", get_result.GetResponseHeaderByName(
473 net::HttpRequestHeaders::kContentType));
Maks Orlovich5408ddfc2020-07-28 23:07:35474
475 ExpectExtensionAccessResult(extension, metrics.entries(),
476 ExtensionResourceAccessResult::kSuccess);
[email protected]93ac047a2012-12-13 02:53:49477 }
478
479 // And then test it with the extension disabled.
Chris Mumford8f812662018-02-22 00:27:57480 RemoveExtension(extension, UnloadedExtensionReason::DISABLE);
[email protected]93ac047a2012-12-13 02:53:49481 {
Maks Orlovich5408ddfc2020-07-28 23:07:35482 blink::test::ScopedIdentifiabilityTestSampleCollector metrics;
483
Chris Mumford8f812662018-02-22 00:27:57484 auto get_result =
485 RequestOrLoad(extension->GetResourceURL("webstore_icon_16.png"),
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15486 network::mojom::RequestDestination::kVideo);
Chris Mumford8f812662018-02-22 00:27:57487 EXPECT_EQ(net::OK, get_result.result());
488 CheckForContentLengthHeader(get_result);
489 EXPECT_EQ("image/png", get_result.GetResponseHeaderByName(
490 net::HttpRequestHeaders::kContentType));
Maks Orlovich5408ddfc2020-07-28 23:07:35491
492 ExpectExtensionAccessResult(extension, metrics.entries(),
493 ExtensionResourceAccessResult::kSuccess);
[email protected]93ac047a2012-12-13 02:53:49494 }
495}
496
[email protected]6f7d7062013-06-04 03:49:33497// Tests that a URL request for resource from an extension returns a few
498// expected response headers.
Clark DuVallc7e3b4692019-06-13 22:07:11499TEST_F(ExtensionProtocolsTest, ResourceRequestResponseHeaders) {
[email protected]6f7d7062013-06-04 03:49:33500 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01501 SetProtocolHandler(false);
[email protected]6f7d7062013-06-04 03:49:33502
Devlin Cronin8e5892f2018-10-04 00:13:43503 scoped_refptr<const Extension> extension =
504 CreateTestResponseHeaderExtension();
Chris Mumford8f812662018-02-22 00:27:57505 AddExtension(extension, false, false);
[email protected]6f7d7062013-06-04 03:49:33506
507 {
Chris Mumford8f812662018-02-22 00:27:57508 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15509 network::mojom::RequestDestination::kVideo);
Chris Mumford8f812662018-02-22 00:27:57510 EXPECT_EQ(net::OK, get_result.result());
[email protected]6f7d7062013-06-04 03:49:33511
512 // Check that cache-related headers are set.
Chris Mumford8f812662018-02-22 00:27:57513 std::string etag = get_result.GetResponseHeaderByName("ETag");
brettw66d1b81b2015-07-06 19:29:40514 EXPECT_TRUE(base::StartsWith(etag, "\"", base::CompareCase::SENSITIVE));
515 EXPECT_TRUE(base::EndsWith(etag, "\"", base::CompareCase::SENSITIVE));
[email protected]6f7d7062013-06-04 03:49:33516
Chris Mumford8f812662018-02-22 00:27:57517 std::string revalidation_header =
518 get_result.GetResponseHeaderByName("cache-control");
[email protected]6f7d7062013-06-04 03:49:33519 EXPECT_EQ("no-cache", revalidation_header);
520
521 // We set test.dat as web-accessible, so it should have a CORS header.
Chris Mumford8f812662018-02-22 00:27:57522 std::string access_control =
523 get_result.GetResponseHeaderByName("Access-Control-Allow-Origin");
[email protected]6f7d7062013-06-04 03:49:33524 EXPECT_EQ("*", access_control);
525 }
526}
527
[email protected]b109bdd2013-11-04 18:08:43528// Tests that a URL request for main frame or subframe from an extension
529// succeeds, but subresources fail. See http://crbug.com/312269.
Clark DuVallc7e3b4692019-06-13 22:07:11530TEST_F(ExtensionProtocolsTest, AllowFrameRequests) {
[email protected]b109bdd2013-11-04 18:08:43531 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01532 SetProtocolHandler(false);
[email protected]b109bdd2013-11-04 18:08:43533
534 scoped_refptr<Extension> extension = CreateTestExtension("foo", false);
Chris Mumford8f812662018-02-22 00:27:57535 AddExtension(extension, false, false);
[email protected]b109bdd2013-11-04 18:08:43536
nasko5cf9d452016-06-01 05:34:56537 // All MAIN_FRAME requests should succeed. SUB_FRAME requests that are not
Chris Mumford8f812662018-02-22 00:27:57538 // explicitly listed in web_accessible_resources or same-origin to the parent
nasko5cf9d452016-06-01 05:34:56539 // should not succeed.
[email protected]b109bdd2013-11-04 18:08:43540 {
Maks Orlovich5408ddfc2020-07-28 23:07:35541 blink::test::ScopedIdentifiabilityTestSampleCollector metrics;
542
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15543 auto get_result =
544 RequestOrLoad(extension->GetResourceURL("test.dat"),
545 network::mojom::RequestDestination::kDocument);
Chris Mumford8f812662018-02-22 00:27:57546 EXPECT_EQ(net::OK, get_result.result());
Maks Orlovich5408ddfc2020-07-28 23:07:35547
548 ExpectExtensionAccessResult(extension, metrics.entries(),
549 ExtensionResourceAccessResult::kSuccess);
[email protected]b109bdd2013-11-04 18:08:43550 }
John Abd-El-Malek2305cdc2018-02-14 20:26:28551
552 // Subframe navigation requests are blocked in ExtensionNavigationThrottle
553 // which isn't added in this unit test. This is tested in an integration test
554 // in ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
[email protected]b109bdd2013-11-04 18:08:43555
556 // And subresource types, such as media, should fail.
557 {
Maks Orlovich5408ddfc2020-07-28 23:07:35558 blink::test::ScopedIdentifiabilityTestSampleCollector metrics;
559
Chris Mumford8f812662018-02-22 00:27:57560 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15561 network::mojom::RequestDestination::kVideo);
Chris Mumford8f812662018-02-22 00:27:57562 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, get_result.result());
Maks Orlovich5408ddfc2020-07-28 23:07:35563
564 ExpectExtensionAccessResult(extension, metrics.entries(),
565 ExtensionResourceAccessResult::kFailure);
[email protected]b109bdd2013-11-04 18:08:43566 }
567}
568
Clark DuVallc7e3b4692019-06-13 22:07:11569TEST_F(ExtensionProtocolsTest, MetadataFolder) {
asargenta093ec32016-02-13 01:36:43570 SetProtocolHandler(false);
571
572 base::FilePath extension_dir = GetTestPath("metadata_folder");
573 std::string error;
Ryan Keane4a17bdf2020-06-23 22:15:57574 scoped_refptr<Extension> extension = file_util::LoadExtension(
Gyuyoung Kim2e954c42021-03-19 14:06:29575 extension_dir, mojom::ManifestLocation::kInternal, Extension::NO_FLAGS,
576 &error);
asargenta093ec32016-02-13 01:36:43577 ASSERT_NE(extension.get(), nullptr) << "error: " << error;
578
579 // Loading "/test.html" should succeed.
Chris Mumford8f812662018-02-22 00:27:57580 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, "test.html").result());
asargenta093ec32016-02-13 01:36:43581
582 // Loading "/_metadata/verified_contents.json" should fail.
583 base::FilePath relative_path =
584 base::FilePath(kMetadataFolder).Append(kVerifiedContentsFilename);
585 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
Chris Mumford8f812662018-02-22 00:27:57586 EXPECT_NE(net::OK,
587 DoRequestOrLoad(extension, relative_path.AsUTF8Unsafe()).result());
asargenta093ec32016-02-13 01:36:43588
589 // Loading "/_metadata/a.txt" should also fail.
590 relative_path = base::FilePath(kMetadataFolder).AppendASCII("a.txt");
591 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
Chris Mumford8f812662018-02-22 00:27:57592 EXPECT_NE(net::OK,
593 DoRequestOrLoad(extension, relative_path.AsUTF8Unsafe()).result());
asargenta093ec32016-02-13 01:36:43594}
595
lazyboyd6dbb262017-03-30 00:57:30596// Tests that unreadable files and deleted files correctly go through
597// ContentVerifyJob.
Clark DuVallc7e3b4692019-06-13 22:07:11598TEST_F(ExtensionProtocolsTest, VerificationSeenForFileAccessErrors) {
lazyboyd6dbb262017-03-30 00:57:30599 SetProtocolHandler(false);
600
Istiaque Ahmed72816eaa2018-01-30 22:37:06601 // Unzip extension containing verification hashes to a temporary directory.
lazyboyd6dbb262017-03-30 00:57:30602 base::ScopedTempDir temp_dir;
603 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Istiaque Ahmed72816eaa2018-01-30 22:37:06604 base::FilePath unzipped_path = temp_dir.GetPath();
605 scoped_refptr<Extension> extension =
606 content_verifier_test_utils::UnzipToDirAndLoadExtension(
607 GetContentVerifierTestPath().AppendASCII("source.zip"),
608 unzipped_path);
lazyboyd6dbb262017-03-30 00:57:30609 ASSERT_TRUE(extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06610 ExtensionId extension_id = extension->id();
lazyboyd6dbb262017-03-30 00:57:30611
Istiaque Ahmed72816eaa2018-01-30 22:37:06612 const std::string kJs("1024.js");
613 base::FilePath kRelativePath(FILE_PATH_LITERAL("1024.js"));
lazyboyd6dbb262017-03-30 00:57:30614
Istiaque Ahmed72816eaa2018-01-30 22:37:06615 // Valid and readable 1024.js.
616 {
Istiaque Ahmed584fe142018-03-13 09:19:04617 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
lazyboyd6dbb262017-03-30 00:57:30618
Chris Mumford8f812662018-02-22 00:27:57619 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06620 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
621 content::RunAllPendingInMessageLoop();
622
Chris Mumford8f812662018-02-22 00:27:57623 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36624 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06625 }
626
627 // chmod -r 1024.js.
628 {
Oleg Davydovb7559452020-02-07 15:01:25629 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06630 base::FilePath file_path = unzipped_path.AppendASCII(kJs);
631 ASSERT_TRUE(base::MakeFileUnreadable(file_path));
Chris Mumford8f812662018-02-22 00:27:57632 EXPECT_EQ(net::ERR_ACCESS_DENIED, DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36633 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06634 // NOTE: In production, hash mismatch would have disabled |extension|, but
635 // since UnzipToDirAndLoadExtension() doesn't add the extension to
636 // ExtensionRegistry, ChromeContentVerifierDelegate won't disable it.
637 // TODO(lazyboy): We may want to update this to more closely reflect the
638 // real flow.
639 }
640
641 // Delete 1024.js.
642 {
Istiaque Ahmed584fe142018-03-13 09:19:04643 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06644 base::FilePath file_path = unzipped_path.AppendASCII(kJs);
645 ASSERT_TRUE(base::DieFileDie(file_path, false));
Chris Mumford8f812662018-02-22 00:27:57646 EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
647 DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36648 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06649 }
lazyboyd6dbb262017-03-30 00:57:30650}
651
lazyboye83ab9c62017-03-30 03:18:26652// Tests that zero byte files correctly go through ContentVerifyJob.
Clark DuVallc7e3b4692019-06-13 22:07:11653TEST_F(ExtensionProtocolsTest, VerificationSeenForZeroByteFile) {
lazyboye83ab9c62017-03-30 03:18:26654 SetProtocolHandler(false);
655
Istiaque Ahmed72816eaa2018-01-30 22:37:06656 const std::string kEmptyJs("empty.js");
lazyboye83ab9c62017-03-30 03:18:26657 base::ScopedTempDir temp_dir;
658 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Istiaque Ahmed72816eaa2018-01-30 22:37:06659 base::FilePath unzipped_path = temp_dir.GetPath();
lazyboye83ab9c62017-03-30 03:18:26660
Istiaque Ahmed72816eaa2018-01-30 22:37:06661 scoped_refptr<Extension> extension =
662 content_verifier_test_utils::UnzipToDirAndLoadExtension(
663 GetContentVerifierTestPath().AppendASCII("source.zip"),
664 unzipped_path);
665 ASSERT_TRUE(extension.get());
666
667 base::FilePath kRelativePath(FILE_PATH_LITERAL("empty.js"));
668 ExtensionId extension_id = extension->id();
669
670 // Sanity check empty.js.
671 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
lazyboye83ab9c62017-03-30 03:18:26672 int64_t foo_file_size = -1;
Istiaque Ahmed72816eaa2018-01-30 22:37:06673 ASSERT_TRUE(base::GetFileSize(file_path, &foo_file_size));
lazyboye83ab9c62017-03-30 03:18:26674 ASSERT_EQ(0, foo_file_size);
675
Istiaque Ahmed72816eaa2018-01-30 22:37:06676 // Request empty.js.
677 {
Istiaque Ahmed584fe142018-03-13 09:19:04678 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
lazyboye83ab9c62017-03-30 03:18:26679
Chris Mumford8f812662018-02-22 00:27:57680 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06681 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
682 content::RunAllPendingInMessageLoop();
lazyboye83ab9c62017-03-30 03:18:26683
Chris Mumford8f812662018-02-22 00:27:57684 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36685 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06686 }
687
688 // chmod -r empty.js.
689 // Unreadable empty file doesn't generate hash mismatch. Note that this is the
690 // current behavior of ContentVerifyJob.
691 // TODO(lazyboy): The behavior is probably incorrect.
692 {
Oleg Davydovb7559452020-02-07 15:01:25693 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06694 ASSERT_TRUE(base::MakeFileUnreadable(file_path));
Chris Mumford8f812662018-02-22 00:27:57695 EXPECT_EQ(net::ERR_ACCESS_DENIED,
696 DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36697 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06698 }
699
700 // rm empty.js.
701 // Deleted empty file doesn't generate hash mismatch. Note that this is the
702 // current behavior of ContentVerifyJob.
703 // TODO(lazyboy): The behavior is probably incorrect.
704 {
Istiaque Ahmed584fe142018-03-13 09:19:04705 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06706 ASSERT_TRUE(base::DieFileDie(file_path, false));
Chris Mumford8f812662018-02-22 00:27:57707 EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
708 DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36709 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06710 }
lazyboye83ab9c62017-03-30 03:18:26711}
712
Clark DuVallc7e3b4692019-06-13 22:07:11713TEST_F(ExtensionProtocolsTest, VerifyScriptListedAsIcon) {
proberge4f9644c2018-03-27 23:01:54714 SetProtocolHandler(false);
715
716 const std::string kBackgroundJs("background.js");
717 base::ScopedTempDir temp_dir;
718 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
719 base::FilePath unzipped_path = temp_dir.GetPath();
720
721 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:52722 EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &path));
proberge4f9644c2018-03-27 23:01:54723
724 scoped_refptr<Extension> extension =
725 content_verifier_test_utils::UnzipToDirAndLoadExtension(
726 path.AppendASCII("content_hash_fetcher")
727 .AppendASCII("manifest_mislabeled_script")
728 .AppendASCII("source.zip"),
729 unzipped_path);
730 ASSERT_TRUE(extension.get());
731
732 base::FilePath kRelativePath(FILE_PATH_LITERAL("background.js"));
733 ExtensionId extension_id = extension->id();
734
735 // Request background.js.
736 {
737 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
738
739 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
740 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
741 base::RunLoop().RunUntilIdle();
742
743 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kBackgroundJs).result());
744 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
745 }
746
747 // Modify background.js and request it.
748 {
749 base::FilePath file_path = unzipped_path.AppendASCII("background.js");
750 const std::string content = "new content";
Lei Zhanga5bd23f12020-05-07 05:50:15751 EXPECT_TRUE(base::WriteFile(file_path, content));
proberge4f9644c2018-03-27 23:01:54752 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
753
754 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
755 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
756 base::RunLoop().RunUntilIdle();
757
758 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kBackgroundJs).result());
759 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
760 }
761}
762
Devlin Croninc3f88072018-01-30 02:10:11763// Tests that mime types are properly set for returned extension resources.
Clark DuVallc7e3b4692019-06-13 22:07:11764TEST_F(ExtensionProtocolsTest, MimeTypesForKnownFiles) {
Devlin Croninc3f88072018-01-30 02:10:11765 // Register a non-incognito extension protocol handler.
766 SetProtocolHandler(false);
767
768 TestExtensionDir test_dir;
769 constexpr char kManifest[] = R"(
770 {
771 "name": "Test Ext",
772 "description": "A test extension",
773 "manifest_version": 2,
774 "version": "0.1",
775 "web_accessible_resources": ["*"]
776 })";
777 test_dir.WriteManifest(kManifest);
778 std::unique_ptr<base::DictionaryValue> manifest =
Lei Zhang9b9d5792019-02-20 07:24:42779 base::DictionaryValue::From(base::test::ParseJsonDeprecated(kManifest));
Devlin Croninc3f88072018-01-30 02:10:11780 ASSERT_TRUE(manifest);
781
782 test_dir.WriteFile(FILE_PATH_LITERAL("json_file.json"), "{}");
783 test_dir.WriteFile(FILE_PATH_LITERAL("js_file.js"), "function() {}");
784
785 base::FilePath unpacked_path = test_dir.UnpackedPath();
786 ASSERT_TRUE(base::PathExists(unpacked_path.AppendASCII("json_file.json")));
787 std::string error;
788 scoped_refptr<const Extension> extension =
789 ExtensionBuilder()
790 .SetManifest(std::move(manifest))
791 .SetPath(unpacked_path)
Gyuyoung Kimd1406582021-03-16 10:06:22792 .SetLocation(mojom::ManifestLocation::kInternal)
Devlin Croninc3f88072018-01-30 02:10:11793 .Build();
794 ASSERT_TRUE(extension);
795
Chris Mumford8f812662018-02-22 00:27:57796 AddExtension(extension.get(), false, false);
Devlin Croninc3f88072018-01-30 02:10:11797
798 struct {
799 const char* file_name;
800 const char* expected_mime_type;
801 } test_cases[] = {
dstockwell00677932019-04-09 02:12:08802 {"json_file.json", "application/json"},
803 {"js_file.js", "text/javascript"},
804 {"mem_file.mem", ""},
Devlin Croninc3f88072018-01-30 02:10:11805 };
806
807 for (const auto& test_case : test_cases) {
808 SCOPED_TRACE(test_case.file_name);
Chris Mumford8f812662018-02-22 00:27:57809 auto result = RequestOrLoad(extension->GetResourceURL(test_case.file_name),
Julie Jeongeun Kimab3f20d2020-12-08 05:01:15810 network::mojom::RequestDestination::kEmpty);
Chris Mumford8f812662018-02-22 00:27:57811 EXPECT_EQ(
812 test_case.expected_mime_type,
813 result.GetResponseHeaderByName(net::HttpRequestHeaders::kContentType));
Devlin Croninc3f88072018-01-30 02:10:11814 }
815}
816
Karandeep Bhatiaab489a4d2018-11-28 21:56:06817// Tests that requests for extension resources (including the generated
818// background page) are not aborted on system suspend.
Etienne Bergeron53917b502021-04-06 20:23:56819TEST_F(ExtensionProtocolsTest, ExtensionRequestsNotAborted) {
Karandeep Bhatiaab489a4d2018-11-28 21:56:06820 // Register a non-incognito extension protocol handler.
821 SetProtocolHandler(false);
822
823 base::FilePath extension_dir =
824 GetTestPath("common").AppendASCII("background_script");
825 std::string error;
826 scoped_refptr<Extension> extension = file_util::LoadExtension(
Gyuyoung Kim2e954c42021-03-19 14:06:29827 extension_dir, mojom::ManifestLocation::kInternal, Extension::NO_FLAGS,
828 &error);
Karandeep Bhatiaab489a4d2018-11-28 21:56:06829 ASSERT_TRUE(extension.get()) << error;
830
Etienne Bergeron53917b502021-04-06 20:23:56831 EnableSimulationOfSystemSuspendForRequests();
Karandeep Bhatiaab489a4d2018-11-28 21:56:06832
833 // Request the generated background page. Ensure the request completes
834 // successfully.
835 EXPECT_EQ(net::OK,
836 DoRequestOrLoad(extension.get(), kGeneratedBackgroundPageFilename)
837 .result());
838
839 // Request the background.js file. Ensure the request completes successfully.
Ryan Keane4a17bdf2020-06-23 22:15:57840 EXPECT_EQ(net::OK,
841 DoRequestOrLoad(extension.get(), "background.js").result());
842}
843
[email protected]702d8b42013-02-27 20:55:50844} // namespace extensions