blob: 80d8ccb7200e44e60c7c5cd90d53142dbd3f7077 [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"
lazyboyd6dbb262017-03-30 00:57:3021#include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
[email protected]93ac047a2012-12-13 02:53:4922#include "chrome/common/chrome_paths.h"
lazyboyd6dbb262017-03-30 00:57:3023#include "chrome/common/chrome_switches.h"
24#include "chrome/test/base/testing_profile.h"
25#include "components/crx_file/id_util.h"
Matt Falkenhagenae65b292018-04-25 16:03:2726#include "content/public/browser/render_process_host.h"
[email protected]5e212ed2012-03-21 23:29:1527#include "content/public/browser/resource_request_info.h"
megjabloncaf312f2017-01-12 18:47:4928#include "content/public/common/previews_state.h"
[email protected]ec04d3f2013-06-06 21:31:3929#include "content/public/test/test_browser_thread_bundle.h"
Chris Mumford8f812662018-02-22 00:27:5730#include "content/public/test/test_renderer_host.h"
lazyboyd6dbb262017-03-30 00:57:3031#include "content/public/test/test_utils.h"
Chris Mumford8f812662018-02-22 00:27:5732#include "content/public/test/web_contents_tester.h"
lazyboyd6dbb262017-03-30 00:57:3033#include "extensions/browser/content_verifier.h"
Istiaque Ahmed72816eaa2018-01-30 22:37:0634#include "extensions/browser/content_verifier/test_utils.h"
Chris Mumford8f812662018-02-22 00:27:5735#include "extensions/browser/extension_prefs.h"
[email protected]1791e6c92014-04-11 08:29:0136#include "extensions/browser/extension_protocols.h"
Chris Mumford8f812662018-02-22 00:27:5737#include "extensions/browser/extension_registry.h"
John Abd-El-Malekea006302018-05-10 05:50:4638#include "extensions/browser/extension_system.h"
[email protected]38427a12013-11-09 17:34:2039#include "extensions/browser/info_map.h"
[email protected]885c0e92012-11-13 20:27:4240#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4141#include "extensions/common/extension.h"
lazyboyd6dbb262017-03-30 00:57:3042#include "extensions/common/extension_builder.h"
Istiaque Ahmed72816eaa2018-01-30 22:37:0643#include "extensions/common/extension_paths.h"
asargenta093ec32016-02-13 01:36:4344#include "extensions/common/file_util.h"
Devlin Cronin1fa235b62018-04-12 14:04:0745#include "extensions/common/value_builder.h"
Devlin Croninc3f88072018-01-30 02:10:1146#include "extensions/test/test_extension_dir.h"
[email protected]2ca01e52013-10-31 22:05:1947#include "net/base/request_priority.h"
rhalavati04b93382017-04-07 19:00:5448#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]5e212ed2012-03-21 23:29:1549#include "net/url_request/url_request.h"
[email protected]9d5730b2012-08-24 17:42:4950#include "net/url_request/url_request_job_factory_impl.h"
[email protected]5e212ed2012-03-21 23:29:1551#include "net/url_request/url_request_status.h"
52#include "net/url_request/url_request_test_util.h"
Chris Mumford8f812662018-02-22 00:27:5753#include "services/network/test/test_url_loader_client.h"
[email protected]5e212ed2012-03-21 23:29:1554#include "testing/gtest/include/gtest/gtest.h"
55
[email protected]7491ad02014-07-05 19:10:0756using content::ResourceType;
Chris Mumford8f812662018-02-22 00:27:5757using extensions::ExtensionRegistry;
58using network::mojom::URLLoader;
[email protected]7491ad02014-07-05 19:10:0759
[email protected]702d8b42013-02-27 20:55:5060namespace extensions {
jamescook8816ae52014-09-05 17:02:3761namespace {
[email protected]5e212ed2012-03-21 23:29:1562
Chris Mumford8f812662018-02-22 00:27:5763enum class RequestHandlerType {
64 kURLLoader,
65 kURLRequest,
66};
67
68const RequestHandlerType kTestModes[] = {RequestHandlerType::kURLLoader,
69 RequestHandlerType::kURLRequest};
70
asargenta093ec32016-02-13 01:36:4371base::FilePath GetTestPath(const std::string& name) {
72 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:5273 EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &path));
asargenta093ec32016-02-13 01:36:4374 return path.AppendASCII("extensions").AppendASCII(name);
75}
76
Istiaque Ahmed72816eaa2018-01-30 22:37:0677base::FilePath GetContentVerifierTestPath() {
78 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:5279 EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &path));
Istiaque Ahmed72816eaa2018-01-30 22:37:0680 return path.AppendASCII("content_hash_fetcher")
81 .AppendASCII("different_sized_files");
lazyboyd6dbb262017-03-30 00:57:3082}
83
[email protected]5e212ed2012-03-21 23:29:1584scoped_refptr<Extension> CreateTestExtension(const std::string& name,
85 bool incognito_split_mode) {
[email protected]023b3d12013-12-23 18:46:4986 base::DictionaryValue manifest;
[email protected]5e212ed2012-03-21 23:29:1587 manifest.SetString("name", name);
88 manifest.SetString("version", "1");
[email protected]b109bdd2013-11-04 18:08:4389 manifest.SetInteger("manifest_version", 2);
[email protected]5e212ed2012-03-21 23:29:1590 manifest.SetString("incognito", incognito_split_mode ? "split" : "spanning");
91
asargenta093ec32016-02-13 01:36:4392 base::FilePath path = GetTestPath("response_headers");
[email protected]5e212ed2012-03-21 23:29:1593
94 std::string error;
95 scoped_refptr<Extension> extension(
[email protected]1d5e58b2013-01-31 08:41:4096 Extension::Create(path, Manifest::INTERNAL, manifest,
[email protected]ed3b9b12012-05-31 18:37:5197 Extension::NO_FLAGS, &error));
[email protected]5e212ed2012-03-21 23:29:1598 EXPECT_TRUE(extension.get()) << error;
99 return extension;
100}
101
[email protected]93ac047a2012-12-13 02:53:49102scoped_refptr<Extension> CreateWebStoreExtension() {
Devlin Croninf43c3312018-03-27 19:54:17103 std::unique_ptr<base::DictionaryValue> manifest =
104 DictionaryBuilder()
105 .Set("name", "WebStore")
106 .Set("version", "1")
107 .Set("manifest_version", 2)
108 .Set("icons",
109 DictionaryBuilder().Set("16", "webstore_icon_16.png").Build())
110 .Set("web_accessible_resources",
111 ListBuilder().Append("webstore_icon_16.png").Build())
112 .Build();
[email protected]93ac047a2012-12-13 02:53:49113
[email protected]650b2d52013-02-10 03:41:45114 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:52115 EXPECT_TRUE(base::PathService::Get(chrome::DIR_RESOURCES, &path));
[email protected]93ac047a2012-12-13 02:53:49116 path = path.AppendASCII("web_store");
117
118 std::string error;
Devlin Croninf43c3312018-03-27 19:54:17119 scoped_refptr<Extension> extension(Extension::Create(
120 path, Manifest::COMPONENT, *manifest, Extension::NO_FLAGS, &error));
[email protected]93ac047a2012-12-13 02:53:49121 EXPECT_TRUE(extension.get()) << error;
122 return extension;
123}
124
Devlin Cronin8e5892f2018-10-04 00:13:43125scoped_refptr<const Extension> CreateTestResponseHeaderExtension() {
Devlin Cronin1fa235b62018-04-12 14:04:07126 return ExtensionBuilder("An extension with web-accessible resources")
Devlin Cronin98cd6582018-05-08 19:18:12127 .SetManifestKey("web_accessible_resources",
128 ListBuilder().Append("test.dat").Build())
Devlin Cronin1fa235b62018-04-12 14:04:07129 .SetPath(GetTestPath("response_headers"))
130 .Build();
[email protected]6f7d7062013-06-04 03:49:33131}
132
Chris Mumford8f812662018-02-22 00:27:57133// Helper function to create a |ResourceRequest| for testing purposes.
134network::ResourceRequest CreateResourceRequest(const std::string& method,
135 ResourceType resource_type,
136 const GURL& url) {
137 network::ResourceRequest request;
138 request.method = method;
139 request.url = url;
140 request.site_for_cookies = url; // bypass third-party cookie blocking.
141 request.request_initiator =
142 url::Origin::Create(url); // ensure initiator set.
143 request.referrer_policy = content::Referrer::GetDefaultReferrerPolicy();
144 request.resource_type = resource_type;
145 request.is_main_frame = resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
146 request.allow_download = true;
147 return request;
148}
149
150// The result of either a URLRequest of a URLLoader response (but not both)
151// depending on the on test type.
152class GetResult {
153 public:
154 GetResult(std::unique_ptr<net::URLRequest> request, int result)
155 : request_(std::move(request)), result_(result) {}
156 GetResult(const network::ResourceResponseHead& response, int result)
157 : resource_response_(response), result_(result) {}
158 GetResult(GetResult&& other)
159 : request_(std::move(other.request_)), result_(other.result_) {}
160 ~GetResult() = default;
161
162 std::string GetResponseHeaderByName(const std::string& name) const {
163 std::string value;
164 if (request_)
165 request_->GetResponseHeaderByName(name, &value);
166 else if (resource_response_.headers)
167 resource_response_.headers->GetNormalizedHeader(name, &value);
168 return value;
169 }
170
171 int result() const { return result_; }
172
173 private:
174 std::unique_ptr<net::URLRequest> request_;
175 const network::ResourceResponseHead resource_response_;
176 int result_;
177
178 DISALLOW_COPY_AND_ASSIGN(GetResult);
179};
180
jamescook8816ae52014-09-05 17:02:37181} // namespace
182
183// This test lives in src/chrome instead of src/extensions because it tests
184// functionality delegated back to Chrome via ChromeExtensionsBrowserClient.
lfg048201a2014-09-16 19:09:36185// See chrome/browser/extensions/chrome_url_request_util.cc.
Chris Mumford8f812662018-02-22 00:27:57186class ExtensionProtocolsTest
187 : public testing::Test,
188 public testing::WithParamInterface<RequestHandlerType> {
[email protected]5e212ed2012-03-21 23:29:15189 public:
lazyboyd6dbb262017-03-30 00:57:30190 ExtensionProtocolsTest()
[email protected]1791e6c92014-04-11 08:29:01191 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
Chris Mumford8f812662018-02-22 00:27:57192 rvh_test_enabler_(new content::RenderViewHostTestEnabler()),
John Abd-El-Malek6fee6902018-11-28 18:30:57193 old_factory_(NULL) {}
[email protected]5e212ed2012-03-21 23:29:15194
dcheng72191812014-10-28 20:49:56195 void SetUp() override {
[email protected]06492ed2013-03-24 22:13:14196 testing::Test::SetUp();
lazyboyd6dbb262017-03-30 00:57:30197 testing_profile_ = TestingProfile::Builder().Build();
Erik Chen5bab4992018-05-05 15:19:53198 contents_ = CreateTestWebContents();
John Abd-El-Malek6fee6902018-11-28 18:30:57199 old_factory_ = test_url_request_context_.job_factory();
lazyboyd6dbb262017-03-30 00:57:30200
201 // Set up content verification.
202 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
203 command_line->AppendSwitchASCII(
204 switches::kExtensionContentVerification,
205 switches::kExtensionContentVerificationEnforce);
206 content_verifier_ = new ContentVerifier(
Chris Mumford8f812662018-02-22 00:27:57207 browser_context(),
208 std::make_unique<ChromeContentVerifierDelegate>(browser_context()));
John Abd-El-Malekea006302018-05-10 05:50:46209 info_map()->SetContentVerifier(content_verifier_.get());
[email protected]5e212ed2012-03-21 23:29:15210 }
211
dcheng72191812014-10-28 20:49:56212 void TearDown() override {
Chris Mumford8f812662018-02-22 00:27:57213 loader_factory_.reset();
John Abd-El-Malek6fee6902018-11-28 18:30:57214 test_url_request_context_.set_job_factory(old_factory_);
lazyboyd6dbb262017-03-30 00:57:30215 content_verifier_->Shutdown();
[email protected]5e212ed2012-03-21 23:29:15216 }
217
[email protected]1791e6c92014-04-11 08:29:01218 void SetProtocolHandler(bool is_incognito) {
Chris Mumford8f812662018-02-22 00:27:57219 switch (request_handler()) {
220 case RequestHandlerType::kURLLoader:
221 loader_factory_ = extensions::CreateExtensionNavigationURLLoaderFactory(
John Abd-El-Malekea006302018-05-10 05:50:46222 browser_context(), false);
Chris Mumford8f812662018-02-22 00:27:57223 break;
224 case RequestHandlerType::kURLRequest:
225 job_factory_.SetProtocolHandler(
John Abd-El-Malekea006302018-05-10 05:50:46226 kExtensionScheme,
227 CreateExtensionProtocolHandler(is_incognito, info_map()));
John Abd-El-Malek6fee6902018-11-28 18:30:57228 test_url_request_context_.set_job_factory(&job_factory_);
Chris Mumford8f812662018-02-22 00:27:57229 break;
230 }
231 testing_profile_->ForceIncognito(is_incognito);
[email protected]93ac047a2012-12-13 02:53:49232 }
233
Chris Mumford8f812662018-02-22 00:27:57234 GetResult RequestOrLoad(const GURL& url, ResourceType resource_type) {
235 switch (request_handler()) {
236 case RequestHandlerType::kURLLoader:
237 return LoadURL(url, resource_type);
238 case RequestHandlerType::kURLRequest:
239 return RequestURL(url, resource_type);
240 }
241 NOTREACHED();
242 return GetResult(nullptr, net::ERR_FAILED);
243 }
244
245 void AddExtension(const scoped_refptr<const Extension>& extension,
246 bool incognito_enabled,
247 bool notifications_disabled) {
John Abd-El-Malekea006302018-05-10 05:50:46248 info_map()->AddExtension(extension.get(), base::Time::Now(),
249 incognito_enabled, notifications_disabled);
Chris Mumford8f812662018-02-22 00:27:57250 if (request_handler() == RequestHandlerType::kURLLoader) {
251 EXPECT_TRUE(extension_registry()->AddEnabled(extension));
252 ExtensionPrefs::Get(browser_context())
253 ->SetIsIncognitoEnabled(extension->id(), incognito_enabled);
254 }
255 }
256
257 void RemoveExtension(const scoped_refptr<const Extension>& extension,
258 const UnloadedExtensionReason reason) {
John Abd-El-Malekea006302018-05-10 05:50:46259 info_map()->RemoveExtension(extension->id(), reason);
Chris Mumford8f812662018-02-22 00:27:57260 if (request_handler() == RequestHandlerType::kURLLoader) {
261 EXPECT_TRUE(extension_registry()->RemoveEnabled(extension->id()));
262 if (reason == UnloadedExtensionReason::DISABLE)
263 EXPECT_TRUE(extension_registry()->AddDisabled(extension));
264 }
265 }
266
267 // Helper method to create a URL request/loader, call RequestOrLoad on it, and
268 // return the result. If |extension| hasn't already been added to
John Abd-El-Malekea006302018-05-10 05:50:46269 // info_map(), this will add it.
Chris Mumford8f812662018-02-22 00:27:57270 GetResult DoRequestOrLoad(const scoped_refptr<Extension> extension,
271 const std::string& relative_path) {
John Abd-El-Malekea006302018-05-10 05:50:46272 if (!info_map()->extensions().Contains(extension->id())) {
Chris Mumford8f812662018-02-22 00:27:57273 AddExtension(extension.get(),
274 /*incognito_enabled=*/false,
275 /*notifications_disabled=*/false);
276 }
277 return RequestOrLoad(extension->GetResourceURL(relative_path),
278 content::RESOURCE_TYPE_MAIN_FRAME);
279 }
280
281 ExtensionRegistry* extension_registry() {
282 return ExtensionRegistry::Get(browser_context());
283 }
284
John Abd-El-Malekea006302018-05-10 05:50:46285 InfoMap* info_map() {
286 return ExtensionSystem::Get(browser_context())->info_map();
287 }
288
Chris Mumford8f812662018-02-22 00:27:57289 content::BrowserContext* browser_context() { return testing_profile_.get(); }
290
Karandeep Bhatiaab489a4d2018-11-28 21:56:06291 void SimulateSystemSuspendForRequests() {
292 power_monitor_source_ = new base::PowerMonitorTestSource();
293 power_monitor_ = std::make_unique<base::PowerMonitor>(
294 std::unique_ptr<base::PowerMonitorSource>(power_monitor_source_));
295 }
296
Chris Mumford8f812662018-02-22 00:27:57297 protected:
298 scoped_refptr<ContentVerifier> content_verifier_;
299
300 private:
301 GetResult LoadURL(const GURL& url, ResourceType resource_type) {
302 constexpr int32_t kRoutingId = 81;
303 constexpr int32_t kRequestId = 28;
304
305 network::mojom::URLLoaderPtr loader;
306 network::TestURLLoaderClient client;
307 loader_factory_->CreateLoaderAndStart(
308 mojo::MakeRequest(&loader), kRoutingId, kRequestId,
309 network::mojom::kURLLoadOptionNone,
310 CreateResourceRequest("GET", resource_type, url),
311 client.CreateInterfacePtr(),
312 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
313
Karandeep Bhatiaab489a4d2018-11-28 21:56:06314 if (power_monitor_source_) {
315 power_monitor_source_->GenerateSuspendEvent();
316 power_monitor_source_->GenerateResumeEvent();
317 }
318
Chris Mumford8f812662018-02-22 00:27:57319 client.RunUntilComplete();
320 return GetResult(client.response_head(),
321 client.completion_status().error_code);
322 }
323
324 GetResult RequestURL(const GURL& url, ResourceType resource_type) {
John Abd-El-Malek6fee6902018-11-28 18:30:57325 auto request = test_url_request_context_.CreateRequest(
Chris Mumford8f812662018-02-22 00:27:57326 url, net::DEFAULT_PRIORITY, &test_delegate_,
327 TRAFFIC_ANNOTATION_FOR_TESTS);
328
gabf9d15582014-11-13 16:40:15329 content::ResourceRequestInfo::AllocateForTesting(
John Abd-El-Malek6fee6902018-11-28 18:30:57330 request.get(), resource_type,
331 /* resource_context */nullptr,
megjabloncaf312f2017-01-12 18:47:49332 /*render_process_id=*/-1,
333 /*render_view_id=*/-1,
334 /*render_frame_id=*/-1,
335 /*is_main_frame=*/resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
megjabloncaf312f2017-01-12 18:47:49336 /*allow_download=*/true,
Jian Li18173422017-11-08 03:00:02337 /*is_async=*/false, content::PREVIEWS_OFF,
338 /*navigation_ui_data*/ nullptr);
[email protected]5e212ed2012-03-21 23:29:15339 request->Start();
Karandeep Bhatiaab489a4d2018-11-28 21:56:06340
341 if (power_monitor_source_) {
342 power_monitor_source_->GenerateSuspendEvent();
343 power_monitor_source_->GenerateResumeEvent();
344
345 // PowerMonitorTestSource calls RunLoop().RunUntilIdle() which causes the
346 // request to be completed.
347 EXPECT_TRUE(test_delegate_.response_completed());
348 } else {
349 base::RunLoop().Run();
350 }
351
Chris Mumford8f812662018-02-22 00:27:57352 return GetResult(std::move(request), test_delegate_.request_status());
[email protected]5e212ed2012-03-21 23:29:15353 }
354
Erik Chen5bab4992018-05-05 15:19:53355 std::unique_ptr<content::WebContents> CreateTestWebContents() {
Chris Mumford8f812662018-02-22 00:27:57356 auto site_instance = content::SiteInstance::Create(browser_context());
357 return content::WebContentsTester::CreateTestWebContents(
358 browser_context(), std::move(site_instance));
asargenta093ec32016-02-13 01:36:43359 }
360
Chris Mumford8f812662018-02-22 00:27:57361 content::WebContents* web_contents() { return contents_.get(); }
362
363 content::RenderFrameHost* main_rfh() {
364 return web_contents()->GetMainFrame();
365 }
366
367 RequestHandlerType request_handler() const { return GetParam(); }
368
[email protected]ec04d3f2013-06-06 21:31:39369 content::TestBrowserThreadBundle thread_bundle_;
Chris Mumford8f812662018-02-22 00:27:57370 std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_;
[email protected]9d5730b2012-08-24 17:42:49371 net::URLRequestJobFactoryImpl job_factory_;
[email protected]5e212ed2012-03-21 23:29:15372 const net::URLRequestJobFactory* old_factory_;
Chris Mumford8f812662018-02-22 00:27:57373 std::unique_ptr<network::mojom::URLLoaderFactory> loader_factory_;
[email protected]37ac95b2013-07-23 23:39:35374 net::TestURLRequestContext test_url_request_context_;
lazyboyd6dbb262017-03-30 00:57:30375 std::unique_ptr<TestingProfile> testing_profile_;
Chris Mumford8f812662018-02-22 00:27:57376 net::TestDelegate test_delegate_;
377 std::unique_ptr<content::WebContents> contents_;
Karandeep Bhatiaab489a4d2018-11-28 21:56:06378
379 std::unique_ptr<base::PowerMonitor> power_monitor_;
380
381 // |power_monitor_source_| is owned by |power_monitor_|
382 base::PowerMonitorTestSource* power_monitor_source_ = nullptr;
[email protected]5e212ed2012-03-21 23:29:15383};
384
385// Tests that making a chrome-extension request in an incognito context is
386// only allowed under the right circumstances (if the extension is allowed
387// in incognito, and it's either a non-main-frame request or a split-mode
388// extension).
Chris Mumford8f812662018-02-22 00:27:57389TEST_P(ExtensionProtocolsTest, IncognitoRequest) {
[email protected]93ac047a2012-12-13 02:53:49390 // Register an incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01391 SetProtocolHandler(true);
[email protected]93ac047a2012-12-13 02:53:49392
[email protected]5e212ed2012-03-21 23:29:15393 struct TestCase {
394 // Inputs.
395 std::string name;
396 bool incognito_split_mode;
397 bool incognito_enabled;
398
399 // Expected results.
400 bool should_allow_main_frame_load;
401 bool should_allow_sub_frame_load;
402 } cases[] = {
403 {"spanning disabled", false, false, false, false},
404 {"split disabled", true, false, false, false},
nasko5cf9d452016-06-01 05:34:56405 {"spanning enabled", false, true, false, false},
406 {"split enabled", true, true, true, false},
[email protected]5e212ed2012-03-21 23:29:15407 };
408
Avi Drissman5f0fb8c2018-12-25 23:20:49409 for (size_t i = 0; i < base::size(cases); ++i) {
[email protected]5e212ed2012-03-21 23:29:15410 scoped_refptr<Extension> extension =
411 CreateTestExtension(cases[i].name, cases[i].incognito_split_mode);
Chris Mumford8f812662018-02-22 00:27:57412 AddExtension(extension, cases[i].incognito_enabled, false);
[email protected]5e212ed2012-03-21 23:29:15413
414 // First test a main frame request.
415 {
416 // It doesn't matter that the resource doesn't exist. If the resource
naskob9164c42016-06-07 01:21:35417 // is blocked, we should see BLOCKED_BY_CLIENT. Otherwise, the request
[email protected]5e212ed2012-03-21 23:29:15418 // should just fail because the file doesn't exist.
Chris Mumford8f812662018-02-22 00:27:57419 auto get_result = RequestOrLoad(extension->GetResourceURL("404.html"),
420 content::RESOURCE_TYPE_MAIN_FRAME);
[email protected]5e212ed2012-03-21 23:29:15421
422 if (cases[i].should_allow_main_frame_load) {
Chris Mumford8f812662018-02-22 00:27:57423 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, get_result.result())
maksim.sisov1b83bb72016-10-07 06:07:23424 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15425 } else {
Chris Mumford8f812662018-02-22 00:27:57426 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, get_result.result())
naskob9164c42016-06-07 01:21:35427 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15428 }
429 }
430
John Abd-El-Malek2305cdc2018-02-14 20:26:28431 // Subframe navigation requests are blocked in ExtensionNavigationThrottle
432 // which isn't added in this unit test. This is tested in an integration
433 // test in ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
Chris Mumford8f812662018-02-22 00:27:57434 RemoveExtension(extension, UnloadedExtensionReason::UNINSTALL);
[email protected]5e212ed2012-03-21 23:29:15435 }
436}
437
Chris Mumford8f812662018-02-22 00:27:57438void CheckForContentLengthHeader(const GetResult& get_result) {
439 std::string content_length = get_result.GetResponseHeaderByName(
440 net::HttpRequestHeaders::kContentLength);
441
[email protected]774cebd2013-09-26 04:55:01442 EXPECT_FALSE(content_length.empty());
443 int length_value = 0;
444 EXPECT_TRUE(base::StringToInt(content_length, &length_value));
445 EXPECT_GT(length_value, 0);
446}
447
[email protected]93ac047a2012-12-13 02:53:49448// Tests getting a resource for a component extension works correctly, both when
449// the extension is enabled and when it is disabled.
Chris Mumford8f812662018-02-22 00:27:57450TEST_P(ExtensionProtocolsTest, ComponentResourceRequest) {
[email protected]93ac047a2012-12-13 02:53:49451 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01452 SetProtocolHandler(false);
[email protected]93ac047a2012-12-13 02:53:49453
454 scoped_refptr<Extension> extension = CreateWebStoreExtension();
Chris Mumford8f812662018-02-22 00:27:57455 AddExtension(extension, false, false);
[email protected]93ac047a2012-12-13 02:53:49456
457 // First test it with the extension enabled.
458 {
Chris Mumford8f812662018-02-22 00:27:57459 auto get_result =
460 RequestOrLoad(extension->GetResourceURL("webstore_icon_16.png"),
461 content::RESOURCE_TYPE_MEDIA);
462 EXPECT_EQ(net::OK, get_result.result());
463 CheckForContentLengthHeader(get_result);
464 EXPECT_EQ("image/png", get_result.GetResponseHeaderByName(
465 net::HttpRequestHeaders::kContentType));
[email protected]93ac047a2012-12-13 02:53:49466 }
467
468 // And then test it with the extension disabled.
Chris Mumford8f812662018-02-22 00:27:57469 RemoveExtension(extension, UnloadedExtensionReason::DISABLE);
[email protected]93ac047a2012-12-13 02:53:49470 {
Chris Mumford8f812662018-02-22 00:27:57471 auto get_result =
472 RequestOrLoad(extension->GetResourceURL("webstore_icon_16.png"),
473 content::RESOURCE_TYPE_MEDIA);
474 EXPECT_EQ(net::OK, get_result.result());
475 CheckForContentLengthHeader(get_result);
476 EXPECT_EQ("image/png", get_result.GetResponseHeaderByName(
477 net::HttpRequestHeaders::kContentType));
[email protected]93ac047a2012-12-13 02:53:49478 }
479}
480
[email protected]6f7d7062013-06-04 03:49:33481// Tests that a URL request for resource from an extension returns a few
482// expected response headers.
Chris Mumford8f812662018-02-22 00:27:57483TEST_P(ExtensionProtocolsTest, ResourceRequestResponseHeaders) {
[email protected]6f7d7062013-06-04 03:49:33484 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01485 SetProtocolHandler(false);
[email protected]6f7d7062013-06-04 03:49:33486
Devlin Cronin8e5892f2018-10-04 00:13:43487 scoped_refptr<const Extension> extension =
488 CreateTestResponseHeaderExtension();
Chris Mumford8f812662018-02-22 00:27:57489 AddExtension(extension, false, false);
[email protected]6f7d7062013-06-04 03:49:33490
491 {
Chris Mumford8f812662018-02-22 00:27:57492 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
493 content::RESOURCE_TYPE_MEDIA);
494 EXPECT_EQ(net::OK, get_result.result());
[email protected]6f7d7062013-06-04 03:49:33495
496 // Check that cache-related headers are set.
Chris Mumford8f812662018-02-22 00:27:57497 std::string etag = get_result.GetResponseHeaderByName("ETag");
brettw66d1b81b2015-07-06 19:29:40498 EXPECT_TRUE(base::StartsWith(etag, "\"", base::CompareCase::SENSITIVE));
499 EXPECT_TRUE(base::EndsWith(etag, "\"", base::CompareCase::SENSITIVE));
[email protected]6f7d7062013-06-04 03:49:33500
Chris Mumford8f812662018-02-22 00:27:57501 std::string revalidation_header =
502 get_result.GetResponseHeaderByName("cache-control");
[email protected]6f7d7062013-06-04 03:49:33503 EXPECT_EQ("no-cache", revalidation_header);
504
505 // We set test.dat as web-accessible, so it should have a CORS header.
Chris Mumford8f812662018-02-22 00:27:57506 std::string access_control =
507 get_result.GetResponseHeaderByName("Access-Control-Allow-Origin");
[email protected]6f7d7062013-06-04 03:49:33508 EXPECT_EQ("*", access_control);
509 }
510}
511
[email protected]b109bdd2013-11-04 18:08:43512// Tests that a URL request for main frame or subframe from an extension
513// succeeds, but subresources fail. See http://crbug.com/312269.
Chris Mumford8f812662018-02-22 00:27:57514TEST_P(ExtensionProtocolsTest, AllowFrameRequests) {
[email protected]b109bdd2013-11-04 18:08:43515 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01516 SetProtocolHandler(false);
[email protected]b109bdd2013-11-04 18:08:43517
518 scoped_refptr<Extension> extension = CreateTestExtension("foo", false);
Chris Mumford8f812662018-02-22 00:27:57519 AddExtension(extension, false, false);
[email protected]b109bdd2013-11-04 18:08:43520
nasko5cf9d452016-06-01 05:34:56521 // All MAIN_FRAME requests should succeed. SUB_FRAME requests that are not
Chris Mumford8f812662018-02-22 00:27:57522 // explicitly listed in web_accessible_resources or same-origin to the parent
nasko5cf9d452016-06-01 05:34:56523 // should not succeed.
[email protected]b109bdd2013-11-04 18:08:43524 {
Chris Mumford8f812662018-02-22 00:27:57525 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
526 content::RESOURCE_TYPE_MAIN_FRAME);
527 EXPECT_EQ(net::OK, get_result.result());
[email protected]b109bdd2013-11-04 18:08:43528 }
John Abd-El-Malek2305cdc2018-02-14 20:26:28529
530 // Subframe navigation requests are blocked in ExtensionNavigationThrottle
531 // which isn't added in this unit test. This is tested in an integration test
532 // in ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
[email protected]b109bdd2013-11-04 18:08:43533
534 // And subresource types, such as media, should fail.
535 {
Chris Mumford8f812662018-02-22 00:27:57536 auto get_result = RequestOrLoad(extension->GetResourceURL("test.dat"),
537 content::RESOURCE_TYPE_MEDIA);
538 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, get_result.result());
[email protected]b109bdd2013-11-04 18:08:43539 }
540}
541
Chris Mumford8f812662018-02-22 00:27:57542TEST_P(ExtensionProtocolsTest, MetadataFolder) {
asargenta093ec32016-02-13 01:36:43543 SetProtocolHandler(false);
544
545 base::FilePath extension_dir = GetTestPath("metadata_folder");
546 std::string error;
547 scoped_refptr<Extension> extension =
548 file_util::LoadExtension(extension_dir, Manifest::INTERNAL,
549 Extension::NO_FLAGS, &error);
550 ASSERT_NE(extension.get(), nullptr) << "error: " << error;
551
552 // Loading "/test.html" should succeed.
Chris Mumford8f812662018-02-22 00:27:57553 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, "test.html").result());
asargenta093ec32016-02-13 01:36:43554
555 // Loading "/_metadata/verified_contents.json" should fail.
556 base::FilePath relative_path =
557 base::FilePath(kMetadataFolder).Append(kVerifiedContentsFilename);
558 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
Chris Mumford8f812662018-02-22 00:27:57559 EXPECT_NE(net::OK,
560 DoRequestOrLoad(extension, relative_path.AsUTF8Unsafe()).result());
asargenta093ec32016-02-13 01:36:43561
562 // Loading "/_metadata/a.txt" should also fail.
563 relative_path = base::FilePath(kMetadataFolder).AppendASCII("a.txt");
564 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
Chris Mumford8f812662018-02-22 00:27:57565 EXPECT_NE(net::OK,
566 DoRequestOrLoad(extension, relative_path.AsUTF8Unsafe()).result());
asargenta093ec32016-02-13 01:36:43567}
568
lazyboyd6dbb262017-03-30 00:57:30569// Tests that unreadable files and deleted files correctly go through
570// ContentVerifyJob.
Chris Mumford8f812662018-02-22 00:27:57571TEST_P(ExtensionProtocolsTest, VerificationSeenForFileAccessErrors) {
lazyboyd6dbb262017-03-30 00:57:30572 SetProtocolHandler(false);
573
Istiaque Ahmed72816eaa2018-01-30 22:37:06574 // Unzip extension containing verification hashes to a temporary directory.
lazyboyd6dbb262017-03-30 00:57:30575 base::ScopedTempDir temp_dir;
576 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Istiaque Ahmed72816eaa2018-01-30 22:37:06577 base::FilePath unzipped_path = temp_dir.GetPath();
578 scoped_refptr<Extension> extension =
579 content_verifier_test_utils::UnzipToDirAndLoadExtension(
580 GetContentVerifierTestPath().AppendASCII("source.zip"),
581 unzipped_path);
lazyboyd6dbb262017-03-30 00:57:30582 ASSERT_TRUE(extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06583 ExtensionId extension_id = extension->id();
lazyboyd6dbb262017-03-30 00:57:30584
Istiaque Ahmed72816eaa2018-01-30 22:37:06585 const std::string kJs("1024.js");
586 base::FilePath kRelativePath(FILE_PATH_LITERAL("1024.js"));
lazyboyd6dbb262017-03-30 00:57:30587
Istiaque Ahmed72816eaa2018-01-30 22:37:06588 // Valid and readable 1024.js.
589 {
Istiaque Ahmed584fe142018-03-13 09:19:04590 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
lazyboyd6dbb262017-03-30 00:57:30591
Chris Mumford8f812662018-02-22 00:27:57592 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06593 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
594 content::RunAllPendingInMessageLoop();
595
Chris Mumford8f812662018-02-22 00:27:57596 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36597 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06598 }
599
600 // chmod -r 1024.js.
601 {
Istiaque Ahmed584fe142018-03-13 09:19:04602 TestContentVerifySingleJobObserver observer(extension->id(), kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06603 base::FilePath file_path = unzipped_path.AppendASCII(kJs);
604 ASSERT_TRUE(base::MakeFileUnreadable(file_path));
Chris Mumford8f812662018-02-22 00:27:57605 EXPECT_EQ(net::ERR_ACCESS_DENIED, DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36606 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06607 // NOTE: In production, hash mismatch would have disabled |extension|, but
608 // since UnzipToDirAndLoadExtension() doesn't add the extension to
609 // ExtensionRegistry, ChromeContentVerifierDelegate won't disable it.
610 // TODO(lazyboy): We may want to update this to more closely reflect the
611 // real flow.
612 }
613
614 // Delete 1024.js.
615 {
Istiaque Ahmed584fe142018-03-13 09:19:04616 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06617 base::FilePath file_path = unzipped_path.AppendASCII(kJs);
618 ASSERT_TRUE(base::DieFileDie(file_path, false));
Chris Mumford8f812662018-02-22 00:27:57619 EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
620 DoRequestOrLoad(extension, kJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36621 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06622 }
lazyboyd6dbb262017-03-30 00:57:30623}
624
lazyboye83ab9c62017-03-30 03:18:26625// Tests that zero byte files correctly go through ContentVerifyJob.
Chris Mumford8f812662018-02-22 00:27:57626TEST_P(ExtensionProtocolsTest, VerificationSeenForZeroByteFile) {
lazyboye83ab9c62017-03-30 03:18:26627 SetProtocolHandler(false);
628
Istiaque Ahmed72816eaa2018-01-30 22:37:06629 const std::string kEmptyJs("empty.js");
lazyboye83ab9c62017-03-30 03:18:26630 base::ScopedTempDir temp_dir;
631 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Istiaque Ahmed72816eaa2018-01-30 22:37:06632 base::FilePath unzipped_path = temp_dir.GetPath();
lazyboye83ab9c62017-03-30 03:18:26633
Istiaque Ahmed72816eaa2018-01-30 22:37:06634 scoped_refptr<Extension> extension =
635 content_verifier_test_utils::UnzipToDirAndLoadExtension(
636 GetContentVerifierTestPath().AppendASCII("source.zip"),
637 unzipped_path);
638 ASSERT_TRUE(extension.get());
639
640 base::FilePath kRelativePath(FILE_PATH_LITERAL("empty.js"));
641 ExtensionId extension_id = extension->id();
642
643 // Sanity check empty.js.
644 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
lazyboye83ab9c62017-03-30 03:18:26645 int64_t foo_file_size = -1;
Istiaque Ahmed72816eaa2018-01-30 22:37:06646 ASSERT_TRUE(base::GetFileSize(file_path, &foo_file_size));
lazyboye83ab9c62017-03-30 03:18:26647 ASSERT_EQ(0, foo_file_size);
648
Istiaque Ahmed72816eaa2018-01-30 22:37:06649 // Request empty.js.
650 {
Istiaque Ahmed584fe142018-03-13 09:19:04651 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
lazyboye83ab9c62017-03-30 03:18:26652
Chris Mumford8f812662018-02-22 00:27:57653 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
Istiaque Ahmed72816eaa2018-01-30 22:37:06654 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
655 content::RunAllPendingInMessageLoop();
lazyboye83ab9c62017-03-30 03:18:26656
Chris Mumford8f812662018-02-22 00:27:57657 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36658 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06659 }
660
661 // chmod -r empty.js.
662 // Unreadable empty file doesn't generate hash mismatch. Note that this is the
663 // current behavior of ContentVerifyJob.
664 // TODO(lazyboy): The behavior is probably incorrect.
665 {
Istiaque Ahmed584fe142018-03-13 09:19:04666 TestContentVerifySingleJobObserver observer(extension->id(), kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06667 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
668 ASSERT_TRUE(base::MakeFileUnreadable(file_path));
Chris Mumford8f812662018-02-22 00:27:57669 EXPECT_EQ(net::ERR_ACCESS_DENIED,
670 DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36671 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06672 }
673
674 // rm empty.js.
675 // Deleted empty file doesn't generate hash mismatch. Note that this is the
676 // current behavior of ContentVerifyJob.
677 // TODO(lazyboy): The behavior is probably incorrect.
678 {
Istiaque Ahmed584fe142018-03-13 09:19:04679 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
Istiaque Ahmed72816eaa2018-01-30 22:37:06680 base::FilePath file_path = unzipped_path.AppendASCII(kEmptyJs);
681 ASSERT_TRUE(base::DieFileDie(file_path, false));
Chris Mumford8f812662018-02-22 00:27:57682 EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
683 DoRequestOrLoad(extension, kEmptyJs).result());
Istiaque Ahmed1dec1d42018-02-02 00:01:36684 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
Istiaque Ahmed72816eaa2018-01-30 22:37:06685 }
lazyboye83ab9c62017-03-30 03:18:26686}
687
proberge4f9644c2018-03-27 23:01:54688TEST_P(ExtensionProtocolsTest, VerifyScriptListedAsIcon) {
689 SetProtocolHandler(false);
690
691 const std::string kBackgroundJs("background.js");
692 base::ScopedTempDir temp_dir;
693 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
694 base::FilePath unzipped_path = temp_dir.GetPath();
695
696 base::FilePath path;
Avi Drissman9098f9002018-05-04 00:11:52697 EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &path));
proberge4f9644c2018-03-27 23:01:54698
699 scoped_refptr<Extension> extension =
700 content_verifier_test_utils::UnzipToDirAndLoadExtension(
701 path.AppendASCII("content_hash_fetcher")
702 .AppendASCII("manifest_mislabeled_script")
703 .AppendASCII("source.zip"),
704 unzipped_path);
705 ASSERT_TRUE(extension.get());
706
707 base::FilePath kRelativePath(FILE_PATH_LITERAL("background.js"));
708 ExtensionId extension_id = extension->id();
709
710 // Request background.js.
711 {
712 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
713
714 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
715 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
716 base::RunLoop().RunUntilIdle();
717
718 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kBackgroundJs).result());
719 EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
720 }
721
722 // Modify background.js and request it.
723 {
724 base::FilePath file_path = unzipped_path.AppendASCII("background.js");
725 const std::string content = "new content";
726 EXPECT_NE(base::WriteFile(file_path, content.c_str(), content.size()), -1);
727 TestContentVerifySingleJobObserver observer(extension_id, kRelativePath);
728
729 content_verifier_->OnExtensionLoaded(browser_context(), extension.get());
730 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
731 base::RunLoop().RunUntilIdle();
732
733 EXPECT_EQ(net::OK, DoRequestOrLoad(extension, kBackgroundJs).result());
734 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, observer.WaitForJobFinished());
735 }
736}
737
Devlin Croninc3f88072018-01-30 02:10:11738// Tests that mime types are properly set for returned extension resources.
Chris Mumford8f812662018-02-22 00:27:57739TEST_P(ExtensionProtocolsTest, MimeTypesForKnownFiles) {
Devlin Croninc3f88072018-01-30 02:10:11740 // Register a non-incognito extension protocol handler.
741 SetProtocolHandler(false);
742
743 TestExtensionDir test_dir;
744 constexpr char kManifest[] = R"(
745 {
746 "name": "Test Ext",
747 "description": "A test extension",
748 "manifest_version": 2,
749 "version": "0.1",
750 "web_accessible_resources": ["*"]
751 })";
752 test_dir.WriteManifest(kManifest);
753 std::unique_ptr<base::DictionaryValue> manifest =
754 base::DictionaryValue::From(base::test::ParseJson(kManifest));
755 ASSERT_TRUE(manifest);
756
757 test_dir.WriteFile(FILE_PATH_LITERAL("json_file.json"), "{}");
758 test_dir.WriteFile(FILE_PATH_LITERAL("js_file.js"), "function() {}");
759
760 base::FilePath unpacked_path = test_dir.UnpackedPath();
761 ASSERT_TRUE(base::PathExists(unpacked_path.AppendASCII("json_file.json")));
762 std::string error;
763 scoped_refptr<const Extension> extension =
764 ExtensionBuilder()
765 .SetManifest(std::move(manifest))
766 .SetPath(unpacked_path)
767 .SetLocation(Manifest::INTERNAL)
768 .Build();
769 ASSERT_TRUE(extension);
770
Chris Mumford8f812662018-02-22 00:27:57771 AddExtension(extension.get(), false, false);
Devlin Croninc3f88072018-01-30 02:10:11772
773 struct {
774 const char* file_name;
775 const char* expected_mime_type;
776 } test_cases[] = {
Devlin Croninf8d89882018-06-29 14:52:43777 {"json_file.json", "application/json"}, {"js_file.js", "text/javascript"},
Devlin Croninc3f88072018-01-30 02:10:11778 };
779
780 for (const auto& test_case : test_cases) {
781 SCOPED_TRACE(test_case.file_name);
Chris Mumford8f812662018-02-22 00:27:57782 auto result = RequestOrLoad(extension->GetResourceURL(test_case.file_name),
783 content::RESOURCE_TYPE_SUB_RESOURCE);
784 EXPECT_EQ(
785 test_case.expected_mime_type,
786 result.GetResponseHeaderByName(net::HttpRequestHeaders::kContentType));
Devlin Croninc3f88072018-01-30 02:10:11787 }
788}
789
Karandeep Bhatiaab489a4d2018-11-28 21:56:06790// Tests that requests for extension resources (including the generated
791// background page) are not aborted on system suspend.
792TEST_P(ExtensionProtocolsTest, ExtensionRequestsNotAborted) {
793 // Register a non-incognito extension protocol handler.
794 SetProtocolHandler(false);
795
796 base::FilePath extension_dir =
797 GetTestPath("common").AppendASCII("background_script");
798 std::string error;
799 scoped_refptr<Extension> extension = file_util::LoadExtension(
800 extension_dir, Manifest::INTERNAL, Extension::NO_FLAGS, &error);
801 ASSERT_TRUE(extension.get()) << error;
802
803 SimulateSystemSuspendForRequests();
804
805 // Request the generated background page. Ensure the request completes
806 // successfully.
807 EXPECT_EQ(net::OK,
808 DoRequestOrLoad(extension.get(), kGeneratedBackgroundPageFilename)
809 .result());
810
811 // Request the background.js file. Ensure the request completes successfully.
812 EXPECT_EQ(net::OK, DoRequestOrLoad(extension.get(), "background.js").result());
813}
814
Chris Mumford8f812662018-02-22 00:27:57815INSTANTIATE_TEST_CASE_P(Extensions,
816 ExtensionProtocolsTest,
817 ::testing::ValuesIn(kTestModes));
818
[email protected]702d8b42013-02-27 20:55:50819} // namespace extensions