blob: 7a259c1d0080831ca5cbdff1da98989738bd235a [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"
thestigc9e38a22014-09-13 01:02:1112#include "base/files/file_util.h"
fdoraycb32419d2016-06-23 15:52:5513#include "base/run_loop.h"
Avi Drissman5f0fb8c2018-12-25 23:20:4914#include "base/stl_util.h"
[email protected]774cebd2013-09-26 04:55:0115#include "base/strings/string_number_conversions.h"
[email protected]00e7bef2013-06-10 20:35:1716#include "base/strings/string_util.h"
Karandeep Bhatiaab489a4d2018-11-28 21:56:0617#include "base/test/power_monitor_test_base.h"
lazyboyd6dbb262017-03-30 00:57:3018#include "base/test/test_file_util.h"
Devlin Croninc3f88072018-01-30 02:10:1119#include "base/test/values_test_util.h"
[email protected]06492ed2013-03-24 22:13:1420#include "base/values.h"
Kevin Marshall4cab5af2019-01-14 20:27:1421#include "build/build_config.h"
lazyboyd6dbb262017-03-30 00:57:3022#include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
[email protected]93ac047a2012-12-13 02:53:4923#include "chrome/common/chrome_paths.h"
lazyboyd6dbb262017-03-30 00:57:3024#include "chrome/common/chrome_switches.h"
25#include "chrome/test/base/testing_profile.h"
26#include "components/crx_file/id_util.h"
Matt Falkenhagenae65b292018-04-25 16:03:2727#include "content/public/browser/render_process_host.h"
[email protected]5e212ed2012-03-21 23:29:1528#include "content/public/browser/resource_request_info.h"
megjabloncaf312f2017-01-12 18:47:4929#include "content/public/common/previews_state.h"
[email protected]ec04d3f2013-06-06 21:31:3930#include "content/public/test/test_browser_thread_bundle.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"
[email protected]885c0e92012-11-13 20:27:4241#include "extensions/common/constants.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"
Devlin Cronin1fa235b62018-04-12 14:04:0746#include "extensions/common/value_builder.h"
Devlin Croninc3f88072018-01-30 02:10:1147#include "extensions/test/test_extension_dir.h"
[email protected]2ca01e52013-10-31 22:05:1948#include "net/base/request_priority.h"
rhalavati04b93382017-04-07 19:00:5449#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]5e212ed2012-03-21 23:29:1550#include "net/url_request/url_request.h"
[email protected]9d5730b2012-08-24 17:42:4951#include "net/url_request/url_request_job_factory_impl.h"
[email protected]5e212ed2012-03-21 23:29:1552#include "net/url_request/url_request_status.h"
53#include "net/url_request/url_request_test_util.h"
Chris Mumford8f812662018-02-22 00:27:5754#include "services/network/test/test_url_loader_client.h"
[email protected]5e212ed2012-03-21 23:29:1555#include "testing/gtest/include/gtest/gtest.h"
56
[email protected]7491ad02014-07-05 19:10:0757using content::ResourceType;
Chris Mumford8f812662018-02-22 00:27:5758using extensions::ExtensionRegistry;
59using network::mojom::URLLoader;
[email protected]7491ad02014-07-05 19:10:0760
[email protected]702d8b42013-02-27 20:55:5061namespace extensions {
jamescook8816ae52014-09-05 17:02:3762namespace {
[email protected]5e212ed2012-03-21 23:29:1563
Chris Mumford8f812662018-02-22 00:27:5764enum class RequestHandlerType {
65 kURLLoader,
66 kURLRequest,
67};
68
69const RequestHandlerType kTestModes[] = {RequestHandlerType::kURLLoader,
70 RequestHandlerType::kURLRequest};
71
asargenta093ec32016-02-13 01:36:4372base::FilePath GetTestPath(const std::string& name) {
73 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:5274 EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &path));
asargenta093ec32016-02-13 01:36:4375 return path.AppendASCII("extensions").AppendASCII(name);
76}
77
Istiaque Ahmed72816eaa2018-01-30 22:37:0678base::FilePath GetContentVerifierTestPath() {
79 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:5280 EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &path));
Istiaque Ahmed72816eaa2018-01-30 22:37:0681 return path.AppendASCII("content_hash_fetcher")
82 .AppendASCII("different_sized_files");
lazyboyd6dbb262017-03-30 00:57:3083}
84
[email protected]5e212ed2012-03-21 23:29:1585scoped_refptr<Extension> CreateTestExtension(const std::string& name,
86 bool incognito_split_mode) {
[email protected]023b3d12013-12-23 18:46:4987 base::DictionaryValue manifest;
[email protected]5e212ed2012-03-21 23:29:1588 manifest.SetString("name", name);
89 manifest.SetString("version", "1");
[email protected]b109bdd2013-11-04 18:08:4390 manifest.SetInteger("manifest_version", 2);
[email protected]5e212ed2012-03-21 23:29:1591 manifest.SetString("incognito", incognito_split_mode ? "split" : "spanning");
92
asargenta093ec32016-02-13 01:36:4393 base::FilePath path = GetTestPath("response_headers");
[email protected]5e212ed2012-03-21 23:29:1594
95 std::string error;
96 scoped_refptr<Extension> extension(
[email protected]1d5e58b2013-01-31 08:41:4097 Extension::Create(path, Manifest::INTERNAL, manifest,
[email protected]ed3b9b12012-05-31 18:37:5198 Extension::NO_FLAGS, &error));
[email protected]5e212ed2012-03-21 23:29:1599 EXPECT_TRUE(extension.get()) << error;
100 return extension;
101}
102
[email protected]93ac047a2012-12-13 02:53:49103scoped_refptr<Extension> CreateWebStoreExtension() {
Devlin Croninf43c3312018-03-27 19:54:17104 std::unique_ptr<base::DictionaryValue> manifest =
105 DictionaryBuilder()
106 .Set("name", "WebStore")
107 .Set("version", "1")
108 .Set("manifest_version", 2)
109 .Set("icons",
110 DictionaryBuilder().Set("16", "webstore_icon_16.png").Build())
111 .Set("web_accessible_resources",
112 ListBuilder().Append("webstore_icon_16.png").Build())
113 .Build();
[email protected]93ac047a2012-12-13 02:53:49114
[email protected]650b2d52013-02-10 03:41:45115 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:52116 EXPECT_TRUE(base::PathService::Get(chrome::DIR_RESOURCES, &path));
[email protected]93ac047a2012-12-13 02:53:49117 path = path.AppendASCII("web_store");
118
119 std::string error;
Devlin Croninf43c3312018-03-27 19:54:17120 scoped_refptr<Extension> extension(Extension::Create(
121 path, Manifest::COMPONENT, *manifest, Extension::NO_FLAGS, &error));
[email protected]93ac047a2012-12-13 02:53:49122 EXPECT_TRUE(extension.get()) << error;
123 return extension;
124}
125
Devlin Cronin8e5892f2018-10-04 00:13:43126scoped_refptr<const Extension> CreateTestResponseHeaderExtension() {
Devlin Cronin1fa235b62018-04-12 14:04:07127 return ExtensionBuilder("An extension with web-accessible resources")
Devlin Cronin98cd6582018-05-08 19:18:12128 .SetManifestKey("web_accessible_resources",
129 ListBuilder().Append("test.dat").Build())
Devlin Cronin1fa235b62018-04-12 14:04:07130 .SetPath(GetTestPath("response_headers"))
131 .Build();
[email protected]6f7d7062013-06-04 03:49:33132}
133
Chris Mumford8f812662018-02-22 00:27:57134// Helper function to create a |ResourceRequest| for testing purposes.
135network::ResourceRequest CreateResourceRequest(const std::string& method,
136 ResourceType resource_type,
137 const GURL& url) {
138 network::ResourceRequest request;
139 request.method = method;
140 request.url = url;
141 request.site_for_cookies = url; // bypass third-party cookie blocking.
142 request.request_initiator =
143 url::Origin::Create(url); // ensure initiator set.
144 request.referrer_policy = content::Referrer::GetDefaultReferrerPolicy();
Daniel Cheng57541be2019-05-07 07:51:07145 request.resource_type = static_cast<int>(resource_type);
Daniel Chengaee5c0312019-04-18 23:49:05146 request.is_main_frame = resource_type == content::ResourceType::kMainFrame;
Chris Mumford8f812662018-02-22 00:27:57147 request.allow_download = true;
148 return request;
149}
150
151// The result of either a URLRequest of a URLLoader response (but not both)
152// depending on the on test type.
153class GetResult {
154 public:
155 GetResult(std::unique_ptr<net::URLRequest> request, int result)
156 : request_(std::move(request)), result_(result) {}
157 GetResult(const network::ResourceResponseHead& response, int result)
158 : resource_response_(response), result_(result) {}
159 GetResult(GetResult&& other)
160 : request_(std::move(other.request_)), result_(other.result_) {}
161 ~GetResult() = default;
162
163 std::string GetResponseHeaderByName(const std::string& name) const {
164 std::string value;
165 if (request_)
166 request_->GetResponseHeaderByName(name, &value);
167 else if (resource_response_.headers)
168 resource_response_.headers->GetNormalizedHeader(name, &value);
169 return value;
170 }
171
172 int result() const { return result_; }
173
174 private:
175 std::unique_ptr<net::URLRequest> request_;
176 const network::ResourceResponseHead resource_response_;
177 int result_;
178
179 DISALLOW_COPY_AND_ASSIGN(GetResult);
180};
181
jamescook8816ae52014-09-05 17:02:37182} // namespace
183
184// This test lives in src/chrome instead of src/extensions because it tests
185// functionality delegated back to Chrome via ChromeExtensionsBrowserClient.
lfg048201a2014-09-16 19:09:36186// See chrome/browser/extensions/chrome_url_request_util.cc.
Alexey Baskakovf0f9d8f2019-01-19 02:31:54187class ExtensionProtocolsTestBase
Chris Mumford8f812662018-02-22 00:27:57188 : public testing::Test,
189 public testing::WithParamInterface<RequestHandlerType> {
[email protected]5e212ed2012-03-21 23:29:15190 public:
Alexey Baskakovf0f9d8f2019-01-19 02:31:54191 explicit ExtensionProtocolsTestBase(bool force_incognito)
[email protected]1791e6c92014-04-11 08:29:01192 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
Chris Mumford8f812662018-02-22 00:27:57193 rvh_test_enabler_(new content::RenderViewHostTestEnabler()),
Alexey Baskakovf0f9d8f2019-01-19 02:31:54194 old_factory_(NULL),
195 force_incognito_(force_incognito) {}
[email protected]5e212ed2012-03-21 23:29:15196
dcheng72191812014-10-28 20:49:56197 void SetUp() override {
[email protected]06492ed2013-03-24 22:13:14198 testing::Test::SetUp();
lazyboyd6dbb262017-03-30 00:57:30199 testing_profile_ = TestingProfile::Builder().Build();
Erik Chen5bab4992018-05-05 15:19:53200 contents_ = CreateTestWebContents();
John Abd-El-Malek6fee6902018-11-28 18:30:57201 old_factory_ = test_url_request_context_.job_factory();
lazyboyd6dbb262017-03-30 00:57:30202
203 // Set up content verification.
204 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
205 command_line->AppendSwitchASCII(
206 switches::kExtensionContentVerification,
207 switches::kExtensionContentVerificationEnforce);
208 content_verifier_ = new ContentVerifier(
Chris Mumford8f812662018-02-22 00:27:57209 browser_context(),
210 std::make_unique<ChromeContentVerifierDelegate>(browser_context()));
John Abd-El-Malekea006302018-05-10 05:50:46211 info_map()->SetContentVerifier(content_verifier_.get());
[email protected]5e212ed2012-03-21 23:29:15212 }
213
dcheng72191812014-10-28 20:49:56214 void TearDown() override {
Chris Mumford8f812662018-02-22 00:27:57215 loader_factory_.reset();
John Abd-El-Malek6fee6902018-11-28 18:30:57216 test_url_request_context_.set_job_factory(old_factory_);
lazyboyd6dbb262017-03-30 00:57:30217 content_verifier_->Shutdown();
[email protected]5e212ed2012-03-21 23:29:15218 }
219
[email protected]1791e6c92014-04-11 08:29:01220 void SetProtocolHandler(bool is_incognito) {
Chris Mumford8f812662018-02-22 00:27:57221 switch (request_handler()) {
222 case RequestHandlerType::kURLLoader:
223 loader_factory_ = extensions::CreateExtensionNavigationURLLoaderFactory(
John Abd-El-Malekea006302018-05-10 05:50:46224 browser_context(), false);
Chris Mumford8f812662018-02-22 00:27:57225 break;
226 case RequestHandlerType::kURLRequest:
227 job_factory_.SetProtocolHandler(
John Abd-El-Malekea006302018-05-10 05:50:46228 kExtensionScheme,
229 CreateExtensionProtocolHandler(is_incognito, info_map()));
John Abd-El-Malek6fee6902018-11-28 18:30:57230 test_url_request_context_.set_job_factory(&job_factory_);
Chris Mumford8f812662018-02-22 00:27:57231 break;
232 }
[email protected]93ac047a2012-12-13 02:53:49233 }
234
Chris Mumford8f812662018-02-22 00:27:57235 GetResult RequestOrLoad(const GURL& url, ResourceType resource_type) {
236 switch (request_handler()) {
237 case RequestHandlerType::kURLLoader:
238 return LoadURL(url, resource_type);
239 case RequestHandlerType::kURLRequest:
240 return RequestURL(url, resource_type);
241 }
242 NOTREACHED();
243 return GetResult(nullptr, net::ERR_FAILED);
244 }
245
246 void AddExtension(const scoped_refptr<const Extension>& extension,
247 bool incognito_enabled,
248 bool notifications_disabled) {
John Abd-El-Malekea006302018-05-10 05:50:46249 info_map()->AddExtension(extension.get(), base::Time::Now(),
250 incognito_enabled, notifications_disabled);
Chris Mumford8f812662018-02-22 00:27:57251 if (request_handler() == RequestHandlerType::kURLLoader) {
252 EXPECT_TRUE(extension_registry()->AddEnabled(extension));
253 ExtensionPrefs::Get(browser_context())
254 ->SetIsIncognitoEnabled(extension->id(), incognito_enabled);
255 }
256 }
257
258 void RemoveExtension(const scoped_refptr<const Extension>& extension,
259 const UnloadedExtensionReason reason) {
John Abd-El-Malekea006302018-05-10 05:50:46260 info_map()->RemoveExtension(extension->id(), reason);
Chris Mumford8f812662018-02-22 00:27:57261 if (request_handler() == RequestHandlerType::kURLLoader) {
262 EXPECT_TRUE(extension_registry()->RemoveEnabled(extension->id()));
263 if (reason == UnloadedExtensionReason::DISABLE)
264 EXPECT_TRUE(extension_registry()->AddDisabled(extension));
265 }
266 }
267
268 // Helper method to create a URL request/loader, call RequestOrLoad on it, and
269 // return the result. If |extension| hasn't already been added to
John Abd-El-Malekea006302018-05-10 05:50:46270 // info_map(), this will add it.
Chris Mumford8f812662018-02-22 00:27:57271 GetResult DoRequestOrLoad(const scoped_refptr<Extension> extension,
272 const std::string& relative_path) {
John Abd-El-Malekea006302018-05-10 05:50:46273 if (!info_map()->extensions().Contains(extension->id())) {
Chris Mumford8f812662018-02-22 00:27:57274 AddExtension(extension.get(),
275 /*incognito_enabled=*/false,
276 /*notifications_disabled=*/false);
277 }
278 return RequestOrLoad(extension->GetResourceURL(relative_path),
Daniel Chengaee5c0312019-04-18 23:49:05279 content::ResourceType::kMainFrame);
Chris Mumford8f812662018-02-22 00:27:57280 }
281
282 ExtensionRegistry* extension_registry() {
283 return ExtensionRegistry::Get(browser_context());
284 }
285
John Abd-El-Malekea006302018-05-10 05:50:46286 InfoMap* info_map() {
287 return ExtensionSystem::Get(browser_context())->info_map();
288 }
289
Alexey Baskakovf0f9d8f2019-01-19 02:31:54290 content::BrowserContext* browser_context() {
291 return force_incognito_ ? testing_profile_->GetOffTheRecordProfile()
292 : testing_profile_.get();
293 }
Chris Mumford8f812662018-02-22 00:27:57294
Karandeep Bhatiaab489a4d2018-11-28 21:56:06295 void SimulateSystemSuspendForRequests() {
296 power_monitor_source_ = new base::PowerMonitorTestSource();
297 power_monitor_ = std::make_unique<base::PowerMonitor>(
298 std::unique_ptr<base::PowerMonitorSource>(power_monitor_source_));
299 }
300
Chris Mumford8f812662018-02-22 00:27:57301 protected:
302 scoped_refptr<ContentVerifier> content_verifier_;
303
304 private:
305 GetResult LoadURL(const GURL& url, ResourceType resource_type) {
306 constexpr int32_t kRoutingId = 81;
307 constexpr int32_t kRequestId = 28;
308
309 network::mojom::URLLoaderPtr loader;
310 network::TestURLLoaderClient client;
311 loader_factory_->CreateLoaderAndStart(
312 mojo::MakeRequest(&loader), kRoutingId, kRequestId,
313 network::mojom::kURLLoadOptionNone,
314 CreateResourceRequest("GET", resource_type, url),
315 client.CreateInterfacePtr(),
316 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
317
Karandeep Bhatiaab489a4d2018-11-28 21:56:06318 if (power_monitor_source_) {
319 power_monitor_source_->GenerateSuspendEvent();
320 power_monitor_source_->GenerateResumeEvent();
321 }
322
Chris Mumford8f812662018-02-22 00:27:57323 client.RunUntilComplete();
324 return GetResult(client.response_head(),
325 client.completion_status().error_code);
326 }
327
328 GetResult RequestURL(const GURL& url, ResourceType resource_type) {
John Abd-El-Malek6fee6902018-11-28 18:30:57329 auto request = test_url_request_context_.CreateRequest(
Chris Mumford8f812662018-02-22 00:27:57330 url, net::DEFAULT_PRIORITY, &test_delegate_,
331 TRAFFIC_ANNOTATION_FOR_TESTS);
332
gabf9d15582014-11-13 16:40:15333 content::ResourceRequestInfo::AllocateForTesting(
John Abd-El-Malek6fee6902018-11-28 18:30:57334 request.get(), resource_type,
Yao Xiao193c09d2019-02-13 17:30:19335 /* resource_context */ nullptr,
megjabloncaf312f2017-01-12 18:47:49336 /*render_process_id=*/-1,
337 /*render_view_id=*/-1,
338 /*render_frame_id=*/-1,
Daniel Chengaee5c0312019-04-18 23:49:05339 /*is_main_frame=*/resource_type == content::ResourceType::kMainFrame,
Yao Xiao193c09d2019-02-13 17:30:19340 content::ResourceInterceptPolicy::kAllowAll,
Jian Li18173422017-11-08 03:00:02341 /*is_async=*/false, content::PREVIEWS_OFF,
342 /*navigation_ui_data*/ nullptr);
[email protected]5e212ed2012-03-21 23:29:15343 request->Start();
Karandeep Bhatiaab489a4d2018-11-28 21:56:06344
345 if (power_monitor_source_) {
346 power_monitor_source_->GenerateSuspendEvent();
347 power_monitor_source_->GenerateResumeEvent();
348
349 // PowerMonitorTestSource calls RunLoop().RunUntilIdle() which causes the
350 // request to be completed.
351 EXPECT_TRUE(test_delegate_.response_completed());
352 } else {
353 base::RunLoop().Run();
354 }
355
Chris Mumford8f812662018-02-22 00:27:57356 return GetResult(std::move(request), test_delegate_.request_status());
[email protected]5e212ed2012-03-21 23:29:15357 }
358
Erik Chen5bab4992018-05-05 15:19:53359 std::unique_ptr<content::WebContents> CreateTestWebContents() {
Chris Mumford8f812662018-02-22 00:27:57360 auto site_instance = content::SiteInstance::Create(browser_context());
361 return content::WebContentsTester::CreateTestWebContents(
362 browser_context(), std::move(site_instance));
asargenta093ec32016-02-13 01:36:43363 }
364
Chris Mumford8f812662018-02-22 00:27:57365 content::WebContents* web_contents() { return contents_.get(); }
366
367 content::RenderFrameHost* main_rfh() {
368 return web_contents()->GetMainFrame();
369 }
370
371 RequestHandlerType request_handler() const { return GetParam(); }
372
[email protected]ec04d3f2013-06-06 21:31:39373 content::TestBrowserThreadBundle thread_bundle_;
Chris Mumford8f812662018-02-22 00:27:57374 std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_;
[email protected]9d5730b2012-08-24 17:42:49375 net::URLRequestJobFactoryImpl job_factory_;
[email protected]5e212ed2012-03-21 23:29:15376 const net::URLRequestJobFactory* old_factory_;
Chris Mumford8f812662018-02-22 00:27:57377 std::unique_ptr<network::mojom::URLLoaderFactory> loader_factory_;
[email protected]37ac95b2013-07-23 23:39:35378 net::TestURLRequestContext test_url_request_context_;
lazyboyd6dbb262017-03-30 00:57:30379 std::unique_ptr<TestingProfile> testing_profile_;
Chris Mumford8f812662018-02-22 00:27:57380 net::TestDelegate test_delegate_;
381 std::unique_ptr<content::WebContents> contents_;
Alexey Baskakovf0f9d8f2019-01-19 02:31:54382 const bool force_incognito_;
Karandeep Bhatiaab489a4d2018-11-28 21:56:06383
384 std::unique_ptr<base::PowerMonitor> power_monitor_;
385
386 // |power_monitor_source_| is owned by |power_monitor_|
387 base::PowerMonitorTestSource* power_monitor_source_ = nullptr;
[email protected]5e212ed2012-03-21 23:29:15388};
389
Alexey Baskakovf0f9d8f2019-01-19 02:31:54390class ExtensionProtocolsTest : public ExtensionProtocolsTestBase {
391 public:
392 ExtensionProtocolsTest()
393 : ExtensionProtocolsTestBase(false /*force_incognito*/) {}
394};
395
396class ExtensionProtocolsIncognitoTest : public ExtensionProtocolsTestBase {
397 public:
398 ExtensionProtocolsIncognitoTest()
399 : ExtensionProtocolsTestBase(true /*force_incognito*/) {}
400};
401
[email protected]5e212ed2012-03-21 23:29:15402// Tests that making a chrome-extension request in an incognito context is
403// only allowed under the right circumstances (if the extension is allowed
404// in incognito, and it's either a non-main-frame request or a split-mode
405// extension).
Alexey Baskakovf0f9d8f2019-01-19 02:31:54406TEST_P(ExtensionProtocolsIncognitoTest, IncognitoRequest) {
[email protected]93ac047a2012-12-13 02:53:49407 // Register an incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01408 SetProtocolHandler(true);
[email protected]93ac047a2012-12-13 02:53:49409
[email protected]5e212ed2012-03-21 23:29:15410 struct TestCase {
411 // Inputs.
412 std::string name;
413 bool incognito_split_mode;
414 bool incognito_enabled;
415
416 // Expected results.
417 bool should_allow_main_frame_load;
418 bool should_allow_sub_frame_load;
419 } cases[] = {
420 {"spanning disabled", false, false, false, false},
421 {"split disabled", true, false, false, false},
nasko5cf9d452016-06-01 05:34:56422 {"spanning enabled", false, true, false, false},
423 {"split enabled", true, true, true, false},
[email protected]5e212ed2012-03-21 23:29:15424 };
425
Avi Drissman5f0fb8c2018-12-25 23:20:49426 for (size_t i = 0; i < base::size(cases); ++i) {
[email protected]5e212ed2012-03-21 23:29:15427 scoped_refptr<Extension> extension =
428 CreateTestExtension(cases[i].name, cases[i].incognito_split_mode);
Chris Mumford8f812662018-02-22 00:27:57429 AddExtension(extension, cases[i].incognito_enabled, false);
[email protected]5e212ed2012-03-21 23:29:15430
431 // First test a main frame request.
432 {
433 // It doesn't matter that the resource doesn't exist. If the resource
naskob9164c42016-06-07 01:21:35434 // is blocked, we should see BLOCKED_BY_CLIENT. Otherwise, the request
[email protected]5e212ed2012-03-21 23:29:15435 // should just fail because the file doesn't exist.
Chris Mumford8f812662018-02-22 00:27:57436 auto get_result = RequestOrLoad(extension->GetResourceURL("404.html"),
Daniel Chengaee5c0312019-04-18 23:49:05437 content::ResourceType::kMainFrame);
[email protected]5e212ed2012-03-21 23:29:15438
439 if (cases[i].should_allow_main_frame_load) {
Chris Mumford8f812662018-02-22 00:27:57440 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, get_result.result())
maksim.sisov1b83bb72016-10-07 06:07:23441 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15442 } else {
Chris Mumford8f812662018-02-22 00:27:57443 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, get_result.result())
naskob9164c42016-06-07 01:21:35444 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15445 }
446 }
447
John Abd-El-Malek2305cdc2018-02-14 20:26:28448 // Subframe navigation requests are blocked in ExtensionNavigationThrottle
449 // which isn't added in this unit test. This is tested in an integration
450 // test in ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
Chris Mumford8f812662018-02-22 00:27:57451 RemoveExtension(extension, UnloadedExtensionReason::UNINSTALL);
[email protected]5e212ed2012-03-21 23:29:15452 }
453}
454
Chris Mumford8f812662018-02-22 00:27:57455void CheckForContentLengthHeader(const GetResult& get_result) {
456 std::string content_length = get_result.GetResponseHeaderByName(
457 net::HttpRequestHeaders::kContentLength);
458
[email protected]774cebd2013-09-26 04:55:01459 EXPECT_FALSE(content_length.empty());
460 int length_value = 0;
461 EXPECT_TRUE(base::StringToInt(content_length, &length_value));
462 EXPECT_GT(length_value, 0);
463}
464
dstockwell944d18882019-04-09 04:25:58465#if defined(OS_CHROMEOS)
466// Tests getting a resource for a component extension works correctly where
467// there is no mime type. Such a resource currently only exists for Chrome OS
468// build.
469TEST_P(ExtensionProtocolsTest, ComponentResourceRequestNoMimeType) {
470 SetProtocolHandler(false);
471 std::unique_ptr<base::DictionaryValue> manifest =
472 DictionaryBuilder()
473 .Set("name", "pdf")
474 .Set("version", "1")
475 .Set("manifest_version", 2)
476 .Set("web_accessible_resources",
477 // Registered by chrome_component_extension_resource_manager.cc
478 ListBuilder().Append("ink/glcore_base.js.mem").Build())
479 .Build();
480
481 base::FilePath path;
482 EXPECT_TRUE(base::PathService::Get(chrome::DIR_RESOURCES, &path));
483 path = path.AppendASCII("pdf");
484
485 std::string error;
486 scoped_refptr<Extension> extension(Extension::Create(
487 path, Manifest::COMPONENT, *manifest, Extension::NO_FLAGS, &error));
488 EXPECT_TRUE(extension.get()) << error;
489 AddExtension(extension, false, false);
490
491 auto get_result =
492 RequestOrLoad(extension->GetResourceURL("ink/glcore_base.js.mem"),
Daniel Chengaee5c0312019-04-18 23:49:05493 content::ResourceType::kXhr);
dstockwell944d18882019-04-09 04:25:58494 EXPECT_EQ(net::OK, get_result.result());
495 CheckForContentLengthHeader(get_result);
496 EXPECT_EQ("", get_result.GetResponseHeaderByName(
497 net::HttpRequestHeaders::kContentType));
498}
499#endif
500
[email protected]93ac047a2012-12-13 02:53:49501// Tests getting a resource for a component extension works correctly, both when
502// the extension is enabled and when it is disabled.
Chris Mumford8f812662018-02-22 00:27:57503TEST_P(ExtensionProtocolsTest, ComponentResourceRequest) {
[email protected]93ac047a2012-12-13 02:53:49504 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01505 SetProtocolHandler(false);
[email protected]93ac047a2012-12-13 02:53:49506
507 scoped_refptr<Extension> extension = CreateWebStoreExtension();
Chris Mumford8f812662018-02-22 00:27:57508 AddExtension(extension, false, false);
[email protected]93ac047a2012-12-13 02:53:49509
510 // First test it with the extension enabled.
511 {
Chris Mumford8f812662018-02-22 00:27:57512 auto get_result =
513 RequestOrLoad(extension->GetResourceURL("webstore_icon_16.png"),
Daniel Chengaee5c0312019-04-18 23:49:05514 content::ResourceType::kMedia);
Chris Mumford8f812662018-02-22 00:27:57515 EXPECT_EQ(net::OK, get_result.result());
516 CheckForContentLengthHeader(get_result);
517 EXPECT_EQ("image/png", get_result.GetResponseHeaderByName(
518 net::HttpRequestHeaders::kContentType));
[email protected]93ac047a2012-12-13 02:53:49519 }
520
521 // And then test it with the extension disabled.
Chris Mumford8f812662018-02-22 00:27:57522 RemoveExtension(extension, UnloadedExtensionReason::DISABLE);
[email protected]93ac047a2012-12-13 02:53:49523 {
Chris Mumford8f812662018-02-22 00:27:57524 auto get_result =
525 RequestOrLoad(extension->GetResourceURL("webstore_icon_16.png"),
Daniel Chengaee5c0312019-04-18 23:49:05526 content::ResourceType::kMedia);
Chris Mumford8f812662018-02-22 00:27:57527 EXPECT_EQ(net::OK, get_result.result());
528 CheckForContentLengthHeader(get_result);
529 EXPECT_EQ("image/png", get_result.GetResponseHeaderByName(
530 net::HttpRequestHeaders::kContentType));
[email protected]93ac047a2012-12-13 02:53:49531 }
532}
533
[email protected]6f7d7062013-06-04 03:49:33534// Tests that a URL request for resource from an extension returns a few
535// expected response headers.
Chris Mumford8f812662018-02-22 00:27:57536TEST_P(ExtensionProtocolsTest, ResourceRequestResponseHeaders) {
[email protected]6f7d7062013-06-04 03:49:33537 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01538 SetProtocolHandler(false);
[email protected]6f7d7062013-06-04 03:49:33539
Devlin Cronin8e5892f2018-10-04 00:13:43540 scoped_refptr<const Extension> extension =
541 CreateTestResponseHeaderExtension();
Chris Mumford8f812662018-02-22 00:27:57542 AddExtension(extension, false, false);
[email protected]6f7d7062013-06-04 03:49:33543
544 {
Chris Mumford8f812662018-02-22 00:27:57545 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
Daniel Chengaee5c0312019-04-18 23:49:05546 content::ResourceType::kMedia);
Chris Mumford8f812662018-02-22 00:27:57547 EXPECT_EQ(net::OK, get_result.result());
[email protected]6f7d7062013-06-04 03:49:33548
549 // Check that cache-related headers are set.
Chris Mumford8f812662018-02-22 00:27:57550 std::string etag = get_result.GetResponseHeaderByName("ETag");
brettw66d1b81b2015-07-06 19:29:40551 EXPECT_TRUE(base::StartsWith(etag, "\"", base::CompareCase::SENSITIVE));
552 EXPECT_TRUE(base::EndsWith(etag, "\"", base::CompareCase::SENSITIVE));
[email protected]6f7d7062013-06-04 03:49:33553
Chris Mumford8f812662018-02-22 00:27:57554 std::string revalidation_header =
555 get_result.GetResponseHeaderByName("cache-control");
[email protected]6f7d7062013-06-04 03:49:33556 EXPECT_EQ("no-cache", revalidation_header);
557
558 // We set test.dat as web-accessible, so it should have a CORS header.
Chris Mumford8f812662018-02-22 00:27:57559 std::string access_control =
560 get_result.GetResponseHeaderByName("Access-Control-Allow-Origin");
[email protected]6f7d7062013-06-04 03:49:33561 EXPECT_EQ("*", access_control);
562 }
563}
564
[email protected]b109bdd2013-11-04 18:08:43565// Tests that a URL request for main frame or subframe from an extension
566// succeeds, but subresources fail. See http://crbug.com/312269.
Chris Mumford8f812662018-02-22 00:27:57567TEST_P(ExtensionProtocolsTest, AllowFrameRequests) {
[email protected]b109bdd2013-11-04 18:08:43568 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01569 SetProtocolHandler(false);
[email protected]b109bdd2013-11-04 18:08:43570
571 scoped_refptr<Extension> extension = CreateTestExtension("foo", false);
Chris Mumford8f812662018-02-22 00:27:57572 AddExtension(extension, false, false);
[email protected]b109bdd2013-11-04 18:08:43573
nasko5cf9d452016-06-01 05:34:56574 // All MAIN_FRAME requests should succeed. SUB_FRAME requests that are not
Chris Mumford8f812662018-02-22 00:27:57575 // explicitly listed in web_accessible_resources or same-origin to the parent
nasko5cf9d452016-06-01 05:34:56576 // should not succeed.
[email protected]b109bdd2013-11-04 18:08:43577 {
Chris Mumford8f812662018-02-22 00:27:57578 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
Daniel Chengaee5c0312019-04-18 23:49:05579 content::ResourceType::kMainFrame);
Chris Mumford8f812662018-02-22 00:27:57580 EXPECT_EQ(net::OK, get_result.result());
[email protected]b109bdd2013-11-04 18:08:43581 }
John Abd-El-Malek2305cdc2018-02-14 20:26:28582
583 // Subframe navigation requests are blocked in ExtensionNavigationThrottle
584 // which isn't added in this unit test. This is tested in an integration test
585 // in ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
[email protected]b109bdd2013-11-04 18:08:43586
587 // And subresource types, such as media, should fail.
588 {
Chris Mumford8f812662018-02-22 00:27:57589 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
Daniel Chengaee5c0312019-04-18 23:49:05590 content::ResourceType::kMedia);
Chris Mumford8f812662018-02-22 00:27:57591 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, get_result.result());
[email protected]b109bdd2013-11-04 18:08:43592 }
593}
594
Chris Mumford8f812662018-02-22 00:27:57595TEST_P(ExtensionProtocolsTest, MetadataFolder) {
asargenta093ec32016-02-13 01:36:43596 SetProtocolHandler(false);
597
598 base::FilePath extension_dir = GetTestPath("metadata_folder");
599 std::string error;
600 scoped_refptr<Extension> extension =
601 file_util::LoadExtension(extension_dir, Manifest::INTERNAL,
602 Extension::NO_FLAGS, &error);
603 ASSERT_NE(extension.get(), nullptr) << "error: " << error;
604
605 // Loading "/test.html" should succeed.
Chris Mumford8f812662018-02-22 00:27:57606 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, "test.html").result());
asargenta093ec32016-02-13 01:36:43607
608 // Loading "/_metadata/verified_contents.json" should fail.
609 base::FilePath relative_path =
610 base::FilePath(kMetadataFolder).Append(kVerifiedContentsFilename);
611 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
Chris Mumford8f812662018-02-22 00:27:57612 EXPECT_NE(net::OK,
613 DoRequestOrLoad(extension, relative_path.AsUTF8Unsafe()).result());
asargenta093ec32016-02-13 01:36:43614
615 // Loading "/_metadata/a.txt" should also fail.
616 relative_path = base::FilePath(kMetadataFolder).AppendASCII("a.txt");
617 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
Chris Mumford8f812662018-02-22 00:27:57618 EXPECT_NE(net::OK,
619 DoRequestOrLoad(extension, relative_path.AsUTF8Unsafe()).result());
asargenta093ec32016-02-13 01:36:43620}
621
lazyboyd6dbb262017-03-30 00:57:30622// Tests that unreadable files and deleted files correctly go through
623// ContentVerifyJob.
Chris Mumford8f812662018-02-22 00:27:57624TEST_P(ExtensionProtocolsTest, VerificationSeenForFileAccessErrors) {
lazyboyd6dbb262017-03-30 00:57:30625 SetProtocolHandler(false);
626
Istiaque Ahmed72816eaa2018-01-30 22:37:06627 // Unzip extension containing verification hashes to a temporary directory.
lazyboyd6dbb262017-03-30 00:57:30628 base::ScopedTempDir temp_dir;
629 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Istiaque Ahmed72816eaa2018-01-30 22:37:06630 base::FilePath unzipped_path = temp_dir.GetPath();
631 scoped_refptr<Extension> extension =
632 content_verifier_test_utils::UnzipToDirAndLoadExtension(
633 GetContentVerifierTestPath().AppendASCII("source.zip"),
634 unzipped_path);
lazyboyd6dbb262017-03-30 00:57:30635 ASSERT_TRUE(extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06636 ExtensionId extension_id = extension->id();
lazyboyd6dbb262017-03-30 00:57:30637
Istiaque Ahmed72816eaa2018-01-30 22:37:06638 const std::string kJs("1024.js");
639 base::FilePath kRelativePath(FILE_PATH_LITERAL("1024.js"));
lazyboyd6dbb262017-03-30 00:57:30640
Istiaque Ahmed72816eaa2018-01-30 22:37:06641 // Valid and readable 1024.js.
642 {
Istiaque Ahmed584fe142018-03-13 09:19:04643 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
lazyboyd6dbb262017-03-30 00:57:30644
Chris Mumford8f812662018-02-22 00:27:57645 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06646 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
647 content::RunAllPendingInMessageLoop();
648
Chris Mumford8f812662018-02-22 00:27:57649 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36650 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06651 }
652
653 // chmod -r 1024.js.
654 {
Istiaque Ahmed584fe142018-03-13 09:19:04655 TestContentVerifySingleJobObserver observer(extension->id(), kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06656 base::FilePath file_path = unzipped_path.AppendASCII(kJs);
657 ASSERT_TRUE(base::MakeFileUnreadable(file_path));
Chris Mumford8f812662018-02-22 00:27:57658 EXPECT_EQ(net::ERR_ACCESS_DENIED, DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36659 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06660 // NOTE: In production, hash mismatch would have disabled |extension|, but
661 // since UnzipToDirAndLoadExtension() doesn't add the extension to
662 // ExtensionRegistry, ChromeContentVerifierDelegate won't disable it.
663 // TODO(lazyboy): We may want to update this to more closely reflect the
664 // real flow.
665 }
666
667 // Delete 1024.js.
668 {
Istiaque Ahmed584fe142018-03-13 09:19:04669 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06670 base::FilePath file_path = unzipped_path.AppendASCII(kJs);
671 ASSERT_TRUE(base::DieFileDie(file_path, false));
Chris Mumford8f812662018-02-22 00:27:57672 EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
673 DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36674 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06675 }
lazyboyd6dbb262017-03-30 00:57:30676}
677
lazyboye83ab9c62017-03-30 03:18:26678// Tests that zero byte files correctly go through ContentVerifyJob.
Chris Mumford8f812662018-02-22 00:27:57679TEST_P(ExtensionProtocolsTest, VerificationSeenForZeroByteFile) {
lazyboye83ab9c62017-03-30 03:18:26680 SetProtocolHandler(false);
681
Istiaque Ahmed72816eaa2018-01-30 22:37:06682 const std::string kEmptyJs("empty.js");
lazyboye83ab9c62017-03-30 03:18:26683 base::ScopedTempDir temp_dir;
684 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Istiaque Ahmed72816eaa2018-01-30 22:37:06685 base::FilePath unzipped_path = temp_dir.GetPath();
lazyboye83ab9c62017-03-30 03:18:26686
Istiaque Ahmed72816eaa2018-01-30 22:37:06687 scoped_refptr<Extension> extension =
688 content_verifier_test_utils::UnzipToDirAndLoadExtension(
689 GetContentVerifierTestPath().AppendASCII("source.zip"),
690 unzipped_path);
691 ASSERT_TRUE(extension.get());
692
693 base::FilePath kRelativePath(FILE_PATH_LITERAL("empty.js"));
694 ExtensionId extension_id = extension->id();
695
696 // Sanity check empty.js.
697 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
lazyboye83ab9c62017-03-30 03:18:26698 int64_t foo_file_size = -1;
Istiaque Ahmed72816eaa2018-01-30 22:37:06699 ASSERT_TRUE(base::GetFileSize(file_path, &foo_file_size));
lazyboye83ab9c62017-03-30 03:18:26700 ASSERT_EQ(0, foo_file_size);
701
Istiaque Ahmed72816eaa2018-01-30 22:37:06702 // Request empty.js.
703 {
Istiaque Ahmed584fe142018-03-13 09:19:04704 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
lazyboye83ab9c62017-03-30 03:18:26705
Chris Mumford8f812662018-02-22 00:27:57706 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06707 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
708 content::RunAllPendingInMessageLoop();
lazyboye83ab9c62017-03-30 03:18:26709
Chris Mumford8f812662018-02-22 00:27:57710 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36711 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06712 }
713
714 // chmod -r empty.js.
715 // Unreadable empty file doesn't generate hash mismatch. Note that this is the
716 // current behavior of ContentVerifyJob.
717 // TODO(lazyboy): The behavior is probably incorrect.
718 {
Istiaque Ahmed584fe142018-03-13 09:19:04719 TestContentVerifySingleJobObserver observer(extension->id(), kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06720 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
721 ASSERT_TRUE(base::MakeFileUnreadable(file_path));
Chris Mumford8f812662018-02-22 00:27:57722 EXPECT_EQ(net::ERR_ACCESS_DENIED,
723 DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36724 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06725 }
726
727 // rm empty.js.
728 // Deleted empty file doesn't generate hash mismatch. Note that this is the
729 // current behavior of ContentVerifyJob.
730 // TODO(lazyboy): The behavior is probably incorrect.
731 {
Istiaque Ahmed584fe142018-03-13 09:19:04732 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06733 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
734 ASSERT_TRUE(base::DieFileDie(file_path, false));
Chris Mumford8f812662018-02-22 00:27:57735 EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
736 DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36737 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06738 }
lazyboye83ab9c62017-03-30 03:18:26739}
740
proberge4f9644c2018-03-27 23:01:54741TEST_P(ExtensionProtocolsTest, VerifyScriptListedAsIcon) {
742 SetProtocolHandler(false);
743
744 const std::string kBackgroundJs("background.js");
745 base::ScopedTempDir temp_dir;
746 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
747 base::FilePath unzipped_path = temp_dir.GetPath();
748
749 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:52750 EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &path));
proberge4f9644c2018-03-27 23:01:54751
752 scoped_refptr<Extension> extension =
753 content_verifier_test_utils::UnzipToDirAndLoadExtension(
754 path.AppendASCII("content_hash_fetcher")
755 .AppendASCII("manifest_mislabeled_script")
756 .AppendASCII("source.zip"),
757 unzipped_path);
758 ASSERT_TRUE(extension.get());
759
760 base::FilePath kRelativePath(FILE_PATH_LITERAL("background.js"));
761 ExtensionId extension_id = extension->id();
762
763 // Request background.js.
764 {
765 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
766
767 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
768 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
769 base::RunLoop().RunUntilIdle();
770
771 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kBackgroundJs).result());
772 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
773 }
774
775 // Modify background.js and request it.
776 {
777 base::FilePath file_path = unzipped_path.AppendASCII("background.js");
778 const std::string content = "new content";
779 EXPECT_NE(base::WriteFile(file_path, content.c_str(), content.size()), -1);
780 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
781
782 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
783 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
784 base::RunLoop().RunUntilIdle();
785
786 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kBackgroundJs).result());
787 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
788 }
789}
790
Devlin Croninc3f88072018-01-30 02:10:11791// Tests that mime types are properly set for returned extension resources.
Chris Mumford8f812662018-02-22 00:27:57792TEST_P(ExtensionProtocolsTest, MimeTypesForKnownFiles) {
Devlin Croninc3f88072018-01-30 02:10:11793 // Register a non-incognito extension protocol handler.
794 SetProtocolHandler(false);
795
796 TestExtensionDir test_dir;
797 constexpr char kManifest[] = R"(
798 {
799 "name": "Test Ext",
800 "description": "A test extension",
801 "manifest_version": 2,
802 "version": "0.1",
803 "web_accessible_resources": ["*"]
804 })";
805 test_dir.WriteManifest(kManifest);
806 std::unique_ptr<base::DictionaryValue> manifest =
Lei Zhang9b9d5792019-02-20 07:24:42807 base::DictionaryValue::From(base::test::ParseJsonDeprecated(kManifest));
Devlin Croninc3f88072018-01-30 02:10:11808 ASSERT_TRUE(manifest);
809
810 test_dir.WriteFile(FILE_PATH_LITERAL("json_file.json"), "{}");
811 test_dir.WriteFile(FILE_PATH_LITERAL("js_file.js"), "function() {}");
812
813 base::FilePath unpacked_path = test_dir.UnpackedPath();
814 ASSERT_TRUE(base::PathExists(unpacked_path.AppendASCII("json_file.json")));
815 std::string error;
816 scoped_refptr<const Extension> extension =
817 ExtensionBuilder()
818 .SetManifest(std::move(manifest))
819 .SetPath(unpacked_path)
820 .SetLocation(Manifest::INTERNAL)
821 .Build();
822 ASSERT_TRUE(extension);
823
Chris Mumford8f812662018-02-22 00:27:57824 AddExtension(extension.get(), false, false);
Devlin Croninc3f88072018-01-30 02:10:11825
826 struct {
827 const char* file_name;
828 const char* expected_mime_type;
829 } test_cases[] = {
dstockwell00677932019-04-09 02:12:08830 {"json_file.json", "application/json"},
831 {"js_file.js", "text/javascript"},
832 {"mem_file.mem", ""},
Devlin Croninc3f88072018-01-30 02:10:11833 };
834
835 for (const auto& test_case : test_cases) {
836 SCOPED_TRACE(test_case.file_name);
Chris Mumford8f812662018-02-22 00:27:57837 auto result = RequestOrLoad(extension->GetResourceURL(test_case.file_name),
Daniel Chengaee5c0312019-04-18 23:49:05838 content::ResourceType::kSubResource);
Chris Mumford8f812662018-02-22 00:27:57839 EXPECT_EQ(
840 test_case.expected_mime_type,
841 result.GetResponseHeaderByName(net::HttpRequestHeaders::kContentType));
Devlin Croninc3f88072018-01-30 02:10:11842 }
843}
844
Kevin Marshall4cab5af2019-01-14 20:27:14845#if defined(OS_WIN)
846#define MAYBE_ExtensionRequestsNotAborted DISABLED_ExtensionRequestsNotAborted
847#else
848#define MAYBE_ExtensionRequestsNotAborted ExtensionRequestsNotAborted
849#endif
Karandeep Bhatiaab489a4d2018-11-28 21:56:06850// Tests that requests for extension resources (including the generated
851// background page) are not aborted on system suspend.
Kevin Marshall4cab5af2019-01-14 20:27:14852//
853// Flaky on Windows.
854// TODO(https://crbug.com/921687): Investigate and fix.
855TEST_P(ExtensionProtocolsTest, MAYBE_ExtensionRequestsNotAborted) {
Karandeep Bhatiaab489a4d2018-11-28 21:56:06856 // Register a non-incognito extension protocol handler.
857 SetProtocolHandler(false);
858
859 base::FilePath extension_dir =
860 GetTestPath("common").AppendASCII("background_script");
861 std::string error;
862 scoped_refptr<Extension> extension = file_util::LoadExtension(
863 extension_dir, Manifest::INTERNAL, Extension::NO_FLAGS, &error);
864 ASSERT_TRUE(extension.get()) << error;
865
866 SimulateSystemSuspendForRequests();
867
868 // Request the generated background page. Ensure the request completes
869 // successfully.
870 EXPECT_EQ(net::OK,
871 DoRequestOrLoad(extension.get(), kGeneratedBackgroundPageFilename)
872 .result());
873
874 // Request the background.js file. Ensure the request completes successfully.
875 EXPECT_EQ(net::OK, DoRequestOrLoad(extension.get(), "background.js").result());
876}
877
Victor Costan4a060e82019-01-28 18:25:34878INSTANTIATE_TEST_SUITE_P(Extensions,
879 ExtensionProtocolsTest,
880 ::testing::ValuesIn(kTestModes));
Chris Mumford8f812662018-02-22 00:27:57881
Victor Costan4a060e82019-01-28 18:25:34882INSTANTIATE_TEST_SUITE_P(Extensions,
883 ExtensionProtocolsIncognitoTest,
884 ::testing::ValuesIn(kTestModes));
Alexey Baskakovf0f9d8f2019-01-19 02:31:54885
[email protected]702d8b42013-02-27 20:55:50886} // namespace extensions