blob: c762e8d5599b815cced82bf59933402c5a3a1010 [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>
9
lazyboyd6dbb262017-03-30 00:57:3010#include "base/command_line.h"
thestigc9e38a22014-09-13 01:02:1111#include "base/files/file_util.h"
avia2f4804a2015-12-24 23:11:1312#include "base/macros.h"
fdoraycb32419d2016-06-23 15:52:5513#include "base/run_loop.h"
[email protected]774cebd2013-09-26 04:55:0114#include "base/strings/string_number_conversions.h"
[email protected]00e7bef2013-06-10 20:35:1715#include "base/strings/string_util.h"
lazyboyd6dbb262017-03-30 00:57:3016#include "base/test/test_file_util.h"
[email protected]06492ed2013-03-24 22:13:1417#include "base/values.h"
lazyboyd6dbb262017-03-30 00:57:3018#include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
[email protected]93ac047a2012-12-13 02:53:4919#include "chrome/common/chrome_paths.h"
lazyboyd6dbb262017-03-30 00:57:3020#include "chrome/common/chrome_switches.h"
21#include "chrome/test/base/testing_profile.h"
22#include "components/crx_file/id_util.h"
[email protected]5e212ed2012-03-21 23:29:1523#include "content/public/browser/resource_request_info.h"
jam7e588d6b2016-10-21 16:56:0624#include "content/public/common/browser_side_navigation_policy.h"
megjabloncaf312f2017-01-12 18:47:4925#include "content/public/common/previews_state.h"
[email protected]08a932d52012-06-03 21:42:1226#include "content/public/test/mock_resource_context.h"
[email protected]ec04d3f2013-06-06 21:31:3927#include "content/public/test/test_browser_thread_bundle.h"
lazyboyd6dbb262017-03-30 00:57:3028#include "content/public/test/test_utils.h"
29#include "extensions/browser/content_verifier.h"
[email protected]1791e6c92014-04-11 08:29:0130#include "extensions/browser/extension_protocols.h"
[email protected]38427a12013-11-09 17:34:2031#include "extensions/browser/info_map.h"
[email protected]885c0e92012-11-13 20:27:4232#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4133#include "extensions/common/extension.h"
lazyboyd6dbb262017-03-30 00:57:3034#include "extensions/common/extension_builder.h"
asargenta093ec32016-02-13 01:36:4335#include "extensions/common/file_util.h"
[email protected]2ca01e52013-10-31 22:05:1936#include "net/base/request_priority.h"
[email protected]5e212ed2012-03-21 23:29:1537#include "net/url_request/url_request.h"
[email protected]9d5730b2012-08-24 17:42:4938#include "net/url_request/url_request_job_factory_impl.h"
[email protected]5e212ed2012-03-21 23:29:1539#include "net/url_request/url_request_status.h"
40#include "net/url_request/url_request_test_util.h"
41#include "testing/gtest/include/gtest/gtest.h"
42
[email protected]7491ad02014-07-05 19:10:0743using content::ResourceType;
44
[email protected]702d8b42013-02-27 20:55:5045namespace extensions {
jamescook8816ae52014-09-05 17:02:3746namespace {
[email protected]5e212ed2012-03-21 23:29:1547
asargenta093ec32016-02-13 01:36:4348base::FilePath GetTestPath(const std::string& name) {
49 base::FilePath path;
50 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
51 return path.AppendASCII("extensions").AppendASCII(name);
52}
53
lazyboyd6dbb262017-03-30 00:57:3054// Helper function that creates a file at |relative_path| within |directory|
55// and fills it with |content|.
56bool AddFileToDirectory(const base::FilePath& directory,
57 const base::FilePath& relative_path,
58 const std::string& content) {
59 base::FilePath full_path = directory.Append(relative_path);
60 int result = base::WriteFile(full_path, content.data(), content.size());
61 return static_cast<size_t>(result) == content.size();
62}
63
[email protected]5e212ed2012-03-21 23:29:1564scoped_refptr<Extension> CreateTestExtension(const std::string& name,
65 bool incognito_split_mode) {
[email protected]023b3d12013-12-23 18:46:4966 base::DictionaryValue manifest;
[email protected]5e212ed2012-03-21 23:29:1567 manifest.SetString("name", name);
68 manifest.SetString("version", "1");
[email protected]b109bdd2013-11-04 18:08:4369 manifest.SetInteger("manifest_version", 2);
[email protected]5e212ed2012-03-21 23:29:1570 manifest.SetString("incognito", incognito_split_mode ? "split" : "spanning");
71
asargenta093ec32016-02-13 01:36:4372 base::FilePath path = GetTestPath("response_headers");
[email protected]5e212ed2012-03-21 23:29:1573
74 std::string error;
75 scoped_refptr<Extension> extension(
[email protected]1d5e58b2013-01-31 08:41:4076 Extension::Create(path, Manifest::INTERNAL, manifest,
[email protected]ed3b9b12012-05-31 18:37:5177 Extension::NO_FLAGS, &error));
[email protected]5e212ed2012-03-21 23:29:1578 EXPECT_TRUE(extension.get()) << error;
79 return extension;
80}
81
[email protected]93ac047a2012-12-13 02:53:4982scoped_refptr<Extension> CreateWebStoreExtension() {
[email protected]023b3d12013-12-23 18:46:4983 base::DictionaryValue manifest;
[email protected]93ac047a2012-12-13 02:53:4984 manifest.SetString("name", "WebStore");
85 manifest.SetString("version", "1");
86 manifest.SetString("icons.16", "webstore_icon_16.png");
87
[email protected]650b2d52013-02-10 03:41:4588 base::FilePath path;
[email protected]93ac047a2012-12-13 02:53:4989 EXPECT_TRUE(PathService::Get(chrome::DIR_RESOURCES, &path));
90 path = path.AppendASCII("web_store");
91
92 std::string error;
93 scoped_refptr<Extension> extension(
[email protected]1d5e58b2013-01-31 08:41:4094 Extension::Create(path, Manifest::COMPONENT, manifest,
[email protected]93ac047a2012-12-13 02:53:4995 Extension::NO_FLAGS, &error));
96 EXPECT_TRUE(extension.get()) << error;
97 return extension;
98}
99
[email protected]6f7d7062013-06-04 03:49:33100scoped_refptr<Extension> CreateTestResponseHeaderExtension() {
[email protected]023b3d12013-12-23 18:46:49101 base::DictionaryValue manifest;
[email protected]6f7d7062013-06-04 03:49:33102 manifest.SetString("name", "An extension with web-accessible resources");
103 manifest.SetString("version", "2");
104
[email protected]aeca23f2013-06-21 22:34:41105 base::ListValue* web_accessible_list = new base::ListValue();
[email protected]6f7d7062013-06-04 03:49:33106 web_accessible_list->AppendString("test.dat");
107 manifest.Set("web_accessible_resources", web_accessible_list);
108
asargenta093ec32016-02-13 01:36:43109 base::FilePath path = GetTestPath("response_headers");
[email protected]6f7d7062013-06-04 03:49:33110
111 std::string error;
112 scoped_refptr<Extension> extension(
113 Extension::Create(path, Manifest::UNPACKED, manifest,
114 Extension::NO_FLAGS, &error));
115 EXPECT_TRUE(extension.get()) << error;
116 return extension;
117}
118
lazyboyd6dbb262017-03-30 00:57:30119// A ContentVerifyJob::TestDelegate that observes DoneReading().
120class JobDelegate : public ContentVerifyJob::TestDelegate {
121 public:
122 explicit JobDelegate(const std::string& expected_contents)
123 : expected_contents_(expected_contents), run_loop_(new base::RunLoop()) {
124 ContentVerifyJob::SetDelegateForTests(this);
125 }
126 ~JobDelegate() override { ContentVerifyJob::SetDelegateForTests(nullptr); }
127
128 ContentVerifyJob::FailureReason BytesRead(const ExtensionId& id,
129 int count,
130 const char* data) override {
131 read_contents_.append(data, count);
132 return ContentVerifyJob::NONE;
133 }
134
135 ContentVerifyJob::FailureReason DoneReading(const ExtensionId& id) override {
136 seen_done_reading_extension_ids_.insert(id);
137 if (waiting_for_extension_id_ == id)
138 run_loop_->Quit();
139
140 if (!base::StartsWith(expected_contents_, read_contents_,
141 base::CompareCase::SENSITIVE)) {
142 ADD_FAILURE() << "Unexpected read, expected: " << expected_contents_
143 << ", but found: " << read_contents_;
144 }
145 return ContentVerifyJob::NONE;
146 }
147
148 void WaitForDoneReading(const ExtensionId& id) {
149 ASSERT_FALSE(waiting_for_extension_id_);
150 if (seen_done_reading_extension_ids_.count(id))
151 return;
152 waiting_for_extension_id_ = id;
153 run_loop_->Run();
154 }
155
156 void Reset() {
157 read_contents_.clear();
158 waiting_for_extension_id_.reset();
159 seen_done_reading_extension_ids_.clear();
160 run_loop_ = base::MakeUnique<base::RunLoop>();
161 }
162
163 private:
164 std::string expected_contents_;
165 std::string read_contents_;
166 std::set<ExtensionId> seen_done_reading_extension_ids_;
167 base::Optional<ExtensionId> waiting_for_extension_id_;
168 std::unique_ptr<base::RunLoop> run_loop_;
169
170 DISALLOW_COPY_AND_ASSIGN(JobDelegate);
171};
172
jamescook8816ae52014-09-05 17:02:37173} // namespace
174
175// This test lives in src/chrome instead of src/extensions because it tests
176// functionality delegated back to Chrome via ChromeExtensionsBrowserClient.
lfg048201a2014-09-16 19:09:36177// See chrome/browser/extensions/chrome_url_request_util.cc.
lazyboyd6dbb262017-03-30 00:57:30178class ExtensionProtocolsTest : public testing::Test {
[email protected]5e212ed2012-03-21 23:29:15179 public:
lazyboyd6dbb262017-03-30 00:57:30180 ExtensionProtocolsTest()
[email protected]1791e6c92014-04-11 08:29:01181 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
182 old_factory_(NULL),
183 resource_context_(&test_url_request_context_) {}
[email protected]5e212ed2012-03-21 23:29:15184
dcheng72191812014-10-28 20:49:56185 void SetUp() override {
[email protected]06492ed2013-03-24 22:13:14186 testing::Test::SetUp();
lazyboyd6dbb262017-03-30 00:57:30187 testing_profile_ = TestingProfile::Builder().Build();
[email protected]38427a12013-11-09 17:34:20188 extension_info_map_ = new InfoMap();
[email protected]5e212ed2012-03-21 23:29:15189 net::URLRequestContext* request_context =
190 resource_context_.GetRequestContext();
191 old_factory_ = request_context->job_factory();
lazyboyd6dbb262017-03-30 00:57:30192
193 // Set up content verification.
194 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
195 command_line->AppendSwitchASCII(
196 switches::kExtensionContentVerification,
197 switches::kExtensionContentVerificationEnforce);
198 content_verifier_ = new ContentVerifier(
199 testing_profile_.get(),
200 new ChromeContentVerifierDelegate(testing_profile_.get()));
201 extension_info_map_->SetContentVerifier(content_verifier_.get());
[email protected]5e212ed2012-03-21 23:29:15202 }
203
dcheng72191812014-10-28 20:49:56204 void TearDown() override {
[email protected]5e212ed2012-03-21 23:29:15205 net::URLRequestContext* request_context =
206 resource_context_.GetRequestContext();
207 request_context->set_job_factory(old_factory_);
lazyboyd6dbb262017-03-30 00:57:30208 content_verifier_->Shutdown();
[email protected]5e212ed2012-03-21 23:29:15209 }
210
[email protected]1791e6c92014-04-11 08:29:01211 void SetProtocolHandler(bool is_incognito) {
[email protected]93ac047a2012-12-13 02:53:49212 net::URLRequestContext* request_context =
213 resource_context_.GetRequestContext();
214 job_factory_.SetProtocolHandler(
[email protected]702d8b42013-02-27 20:55:50215 kExtensionScheme,
[email protected]1791e6c92014-04-11 08:29:01216 CreateExtensionProtocolHandler(is_incognito,
[email protected]7b7e0b32014-03-17 16:09:23217 extension_info_map_.get()));
[email protected]93ac047a2012-12-13 02:53:49218 request_context->set_job_factory(&job_factory_);
219 }
220
[email protected]5e212ed2012-03-21 23:29:15221 void StartRequest(net::URLRequest* request,
[email protected]6c1e05212014-07-31 00:59:40222 ResourceType resource_type) {
gabf9d15582014-11-13 16:40:15223 content::ResourceRequestInfo::AllocateForTesting(
megjabloncaf312f2017-01-12 18:47:49224 request, resource_type, &resource_context_,
225 /*render_process_id=*/-1,
226 /*render_view_id=*/-1,
227 /*render_frame_id=*/-1,
228 /*is_main_frame=*/resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
229 /*parent_is_main_frame=*/false,
230 /*allow_download=*/true,
231 /*is_async=*/false, content::PREVIEWS_OFF);
[email protected]5e212ed2012-03-21 23:29:15232 request->Start();
fdoraycb32419d2016-06-23 15:52:55233 base::RunLoop().Run();
[email protected]5e212ed2012-03-21 23:29:15234 }
235
asargenta093ec32016-02-13 01:36:43236 // Helper method to create a URLRequest, call StartRequest on it, and return
237 // the result. If |extension| hasn't already been added to
238 // |extension_info_map_|, this will add it.
maksim.sisov1b83bb72016-10-07 06:07:23239 int DoRequest(const Extension& extension, const std::string& relative_path) {
asargenta093ec32016-02-13 01:36:43240 if (!extension_info_map_->extensions().Contains(extension.id())) {
241 extension_info_map_->AddExtension(&extension,
242 base::Time::Now(),
243 false, // incognito_enabled
244 false); // notifications_disabled
245 }
dchengc963c7142016-04-08 03:55:22246 std::unique_ptr<net::URLRequest> request(
asargenta093ec32016-02-13 01:36:43247 resource_context_.GetRequestContext()->CreateRequest(
dchengc963c7142016-04-08 03:55:22248 extension.GetResourceURL(relative_path), net::DEFAULT_PRIORITY,
asargenta093ec32016-02-13 01:36:43249 &test_delegate_));
250 StartRequest(request.get(), content::RESOURCE_TYPE_MAIN_FRAME);
maksim.sisov1b83bb72016-10-07 06:07:23251 return test_delegate_.request_status();
asargenta093ec32016-02-13 01:36:43252 }
253
[email protected]5e212ed2012-03-21 23:29:15254 protected:
[email protected]ec04d3f2013-06-06 21:31:39255 content::TestBrowserThreadBundle thread_bundle_;
[email protected]38427a12013-11-09 17:34:20256 scoped_refptr<InfoMap> extension_info_map_;
[email protected]9d5730b2012-08-24 17:42:49257 net::URLRequestJobFactoryImpl job_factory_;
[email protected]5e212ed2012-03-21 23:29:15258 const net::URLRequestJobFactory* old_factory_;
[email protected]2086a3d2012-11-13 17:49:20259 net::TestDelegate test_delegate_;
[email protected]37ac95b2013-07-23 23:39:35260 net::TestURLRequestContext test_url_request_context_;
[email protected]5e212ed2012-03-21 23:29:15261 content::MockResourceContext resource_context_;
lazyboyd6dbb262017-03-30 00:57:30262 scoped_refptr<ContentVerifier> content_verifier_;
263 std::unique_ptr<TestingProfile> testing_profile_;
[email protected]5e212ed2012-03-21 23:29:15264};
265
266// Tests that making a chrome-extension request in an incognito context is
267// only allowed under the right circumstances (if the extension is allowed
268// in incognito, and it's either a non-main-frame request or a split-mode
269// extension).
lazyboyd6dbb262017-03-30 00:57:30270TEST_F(ExtensionProtocolsTest, IncognitoRequest) {
[email protected]93ac047a2012-12-13 02:53:49271 // Register an incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01272 SetProtocolHandler(true);
[email protected]93ac047a2012-12-13 02:53:49273
[email protected]5e212ed2012-03-21 23:29:15274 struct TestCase {
275 // Inputs.
276 std::string name;
277 bool incognito_split_mode;
278 bool incognito_enabled;
279
280 // Expected results.
281 bool should_allow_main_frame_load;
282 bool should_allow_sub_frame_load;
283 } cases[] = {
284 {"spanning disabled", false, false, false, false},
285 {"split disabled", true, false, false, false},
nasko5cf9d452016-06-01 05:34:56286 {"spanning enabled", false, true, false, false},
287 {"split enabled", true, true, true, false},
[email protected]5e212ed2012-03-21 23:29:15288 };
289
viettrungluu9e65ad12014-10-16 04:22:26290 for (size_t i = 0; i < arraysize(cases); ++i) {
[email protected]5e212ed2012-03-21 23:29:15291 scoped_refptr<Extension> extension =
292 CreateTestExtension(cases[i].name, cases[i].incognito_split_mode);
293 extension_info_map_->AddExtension(
[email protected]9afacd22013-11-13 20:23:31294 extension.get(), base::Time::Now(), cases[i].incognito_enabled, false);
[email protected]5e212ed2012-03-21 23:29:15295
296 // First test a main frame request.
297 {
298 // It doesn't matter that the resource doesn't exist. If the resource
naskob9164c42016-06-07 01:21:35299 // is blocked, we should see BLOCKED_BY_CLIENT. Otherwise, the request
[email protected]5e212ed2012-03-21 23:29:15300 // should just fail because the file doesn't exist.
dchengc963c7142016-04-08 03:55:22301 std::unique_ptr<net::URLRequest> request(
[email protected]f7022f32014-08-21 16:32:19302 resource_context_.GetRequestContext()->CreateRequest(
dchengc963c7142016-04-08 03:55:22303 extension->GetResourceURL("404.html"), net::DEFAULT_PRIORITY,
davidben151423e2015-03-23 18:48:36304 &test_delegate_));
[email protected]f7022f32014-08-21 16:32:19305 StartRequest(request.get(), content::RESOURCE_TYPE_MAIN_FRAME);
[email protected]5e212ed2012-03-21 23:29:15306
307 if (cases[i].should_allow_main_frame_load) {
maksim.sisov1b83bb72016-10-07 06:07:23308 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, test_delegate_.request_status())
309 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15310 } else {
maksim.sisov1b83bb72016-10-07 06:07:23311 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, test_delegate_.request_status())
naskob9164c42016-06-07 01:21:35312 << cases[i].name;
[email protected]5e212ed2012-03-21 23:29:15313 }
314 }
315
316 // Now do a subframe request.
317 {
jam7e588d6b2016-10-21 16:56:06318 // With PlzNavigate, the subframe navigation requests are blocked in
319 // ExtensionNavigationThrottle which isn't added in this unit test. This
320 // is tested in an integration test in
321 // ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
322 if (!content::IsBrowserSideNavigationEnabled()) {
323 std::unique_ptr<net::URLRequest> request(
324 resource_context_.GetRequestContext()->CreateRequest(
325 extension->GetResourceURL("404.html"), net::DEFAULT_PRIORITY,
326 &test_delegate_));
327 StartRequest(request.get(), content::RESOURCE_TYPE_SUB_FRAME);
[email protected]5e212ed2012-03-21 23:29:15328
jam7e588d6b2016-10-21 16:56:06329 if (cases[i].should_allow_sub_frame_load) {
330 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, test_delegate_.request_status())
331 << cases[i].name;
332 } else {
333 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, test_delegate_.request_status())
334 << cases[i].name;
335 }
[email protected]5e212ed2012-03-21 23:29:15336 }
337 }
338 }
339}
340
[email protected]774cebd2013-09-26 04:55:01341void CheckForContentLengthHeader(net::URLRequest* request) {
342 std::string content_length;
343 request->GetResponseHeaderByName(net::HttpRequestHeaders::kContentLength,
344 &content_length);
345 EXPECT_FALSE(content_length.empty());
346 int length_value = 0;
347 EXPECT_TRUE(base::StringToInt(content_length, &length_value));
348 EXPECT_GT(length_value, 0);
349}
350
[email protected]93ac047a2012-12-13 02:53:49351// Tests getting a resource for a component extension works correctly, both when
352// the extension is enabled and when it is disabled.
lazyboyd6dbb262017-03-30 00:57:30353TEST_F(ExtensionProtocolsTest, ComponentResourceRequest) {
[email protected]93ac047a2012-12-13 02:53:49354 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01355 SetProtocolHandler(false);
[email protected]93ac047a2012-12-13 02:53:49356
357 scoped_refptr<Extension> extension = CreateWebStoreExtension();
[email protected]9afacd22013-11-13 20:23:31358 extension_info_map_->AddExtension(extension.get(),
359 base::Time::Now(),
360 false,
361 false);
[email protected]93ac047a2012-12-13 02:53:49362
363 // First test it with the extension enabled.
364 {
dchengc963c7142016-04-08 03:55:22365 std::unique_ptr<net::URLRequest> request(
[email protected]f7022f32014-08-21 16:32:19366 resource_context_.GetRequestContext()->CreateRequest(
367 extension->GetResourceURL("webstore_icon_16.png"),
dchengc963c7142016-04-08 03:55:22368 net::DEFAULT_PRIORITY, &test_delegate_));
[email protected]f7022f32014-08-21 16:32:19369 StartRequest(request.get(), content::RESOURCE_TYPE_MEDIA);
maksim.sisov1b83bb72016-10-07 06:07:23370 EXPECT_EQ(net::OK, test_delegate_.request_status());
[email protected]f7022f32014-08-21 16:32:19371 CheckForContentLengthHeader(request.get());
[email protected]93ac047a2012-12-13 02:53:49372 }
373
374 // And then test it with the extension disabled.
375 extension_info_map_->RemoveExtension(extension->id(),
[email protected]b0af4792013-10-23 09:12:13376 UnloadedExtensionInfo::REASON_DISABLE);
[email protected]93ac047a2012-12-13 02:53:49377 {
dchengc963c7142016-04-08 03:55:22378 std::unique_ptr<net::URLRequest> request(
[email protected]f7022f32014-08-21 16:32:19379 resource_context_.GetRequestContext()->CreateRequest(
380 extension->GetResourceURL("webstore_icon_16.png"),
dchengc963c7142016-04-08 03:55:22381 net::DEFAULT_PRIORITY, &test_delegate_));
[email protected]f7022f32014-08-21 16:32:19382 StartRequest(request.get(), content::RESOURCE_TYPE_MEDIA);
maksim.sisov1b83bb72016-10-07 06:07:23383 EXPECT_EQ(net::OK, test_delegate_.request_status());
[email protected]f7022f32014-08-21 16:32:19384 CheckForContentLengthHeader(request.get());
[email protected]93ac047a2012-12-13 02:53:49385 }
386}
387
[email protected]6f7d7062013-06-04 03:49:33388// Tests that a URL request for resource from an extension returns a few
389// expected response headers.
lazyboyd6dbb262017-03-30 00:57:30390TEST_F(ExtensionProtocolsTest, ResourceRequestResponseHeaders) {
[email protected]6f7d7062013-06-04 03:49:33391 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01392 SetProtocolHandler(false);
[email protected]6f7d7062013-06-04 03:49:33393
394 scoped_refptr<Extension> extension = CreateTestResponseHeaderExtension();
[email protected]9afacd22013-11-13 20:23:31395 extension_info_map_->AddExtension(extension.get(),
396 base::Time::Now(),
397 false,
398 false);
[email protected]6f7d7062013-06-04 03:49:33399
400 {
dchengc963c7142016-04-08 03:55:22401 std::unique_ptr<net::URLRequest> request(
[email protected]f7022f32014-08-21 16:32:19402 resource_context_.GetRequestContext()->CreateRequest(
dchengc963c7142016-04-08 03:55:22403 extension->GetResourceURL("test.dat"), net::DEFAULT_PRIORITY,
davidben151423e2015-03-23 18:48:36404 &test_delegate_));
[email protected]f7022f32014-08-21 16:32:19405 StartRequest(request.get(), content::RESOURCE_TYPE_MEDIA);
maksim.sisov1b83bb72016-10-07 06:07:23406 EXPECT_EQ(net::OK, test_delegate_.request_status());
[email protected]6f7d7062013-06-04 03:49:33407
408 // Check that cache-related headers are set.
409 std::string etag;
[email protected]f7022f32014-08-21 16:32:19410 request->GetResponseHeaderByName("ETag", &etag);
brettw66d1b81b2015-07-06 19:29:40411 EXPECT_TRUE(base::StartsWith(etag, "\"", base::CompareCase::SENSITIVE));
412 EXPECT_TRUE(base::EndsWith(etag, "\"", base::CompareCase::SENSITIVE));
[email protected]6f7d7062013-06-04 03:49:33413
414 std::string revalidation_header;
[email protected]f7022f32014-08-21 16:32:19415 request->GetResponseHeaderByName("cache-control", &revalidation_header);
[email protected]6f7d7062013-06-04 03:49:33416 EXPECT_EQ("no-cache", revalidation_header);
417
418 // We set test.dat as web-accessible, so it should have a CORS header.
419 std::string access_control;
[email protected]f7022f32014-08-21 16:32:19420 request->GetResponseHeaderByName("Access-Control-Allow-Origin",
[email protected]6f7d7062013-06-04 03:49:33421 &access_control);
422 EXPECT_EQ("*", access_control);
423 }
424}
425
[email protected]b109bdd2013-11-04 18:08:43426// Tests that a URL request for main frame or subframe from an extension
427// succeeds, but subresources fail. See http://crbug.com/312269.
lazyboyd6dbb262017-03-30 00:57:30428TEST_F(ExtensionProtocolsTest, AllowFrameRequests) {
[email protected]b109bdd2013-11-04 18:08:43429 // Register a non-incognito extension protocol handler.
[email protected]1791e6c92014-04-11 08:29:01430 SetProtocolHandler(false);
[email protected]b109bdd2013-11-04 18:08:43431
432 scoped_refptr<Extension> extension = CreateTestExtension("foo", false);
[email protected]9afacd22013-11-13 20:23:31433 extension_info_map_->AddExtension(extension.get(),
434 base::Time::Now(),
435 false,
436 false);
[email protected]b109bdd2013-11-04 18:08:43437
nasko5cf9d452016-06-01 05:34:56438 // All MAIN_FRAME requests should succeed. SUB_FRAME requests that are not
439 // explicitly listed in web_accesible_resources or same-origin to the parent
440 // should not succeed.
[email protected]b109bdd2013-11-04 18:08:43441 {
dchengc963c7142016-04-08 03:55:22442 std::unique_ptr<net::URLRequest> request(
[email protected]f7022f32014-08-21 16:32:19443 resource_context_.GetRequestContext()->CreateRequest(
dchengc963c7142016-04-08 03:55:22444 extension->GetResourceURL("test.dat"), net::DEFAULT_PRIORITY,
davidben151423e2015-03-23 18:48:36445 &test_delegate_));
[email protected]f7022f32014-08-21 16:32:19446 StartRequest(request.get(), content::RESOURCE_TYPE_MAIN_FRAME);
maksim.sisov1b83bb72016-10-07 06:07:23447 EXPECT_EQ(net::OK, test_delegate_.request_status());
[email protected]b109bdd2013-11-04 18:08:43448 }
449 {
jam7e588d6b2016-10-21 16:56:06450 // With PlzNavigate, the subframe navigation requests are blocked in
451 // ExtensionNavigationThrottle which isn't added in this unit test. This is
452 // tested in an integration test in
453 // ExtensionResourceRequestPolicyTest.IframeNavigateToInaccessible.
454 if (!content::IsBrowserSideNavigationEnabled()) {
455 std::unique_ptr<net::URLRequest> request(
456 resource_context_.GetRequestContext()->CreateRequest(
457 extension->GetResourceURL("test.dat"), net::DEFAULT_PRIORITY,
458 &test_delegate_));
459 StartRequest(request.get(), content::RESOURCE_TYPE_SUB_FRAME);
460 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, test_delegate_.request_status());
461 }
[email protected]b109bdd2013-11-04 18:08:43462 }
463
464 // And subresource types, such as media, should fail.
465 {
dchengc963c7142016-04-08 03:55:22466 std::unique_ptr<net::URLRequest> request(
[email protected]f7022f32014-08-21 16:32:19467 resource_context_.GetRequestContext()->CreateRequest(
dchengc963c7142016-04-08 03:55:22468 extension->GetResourceURL("test.dat"), net::DEFAULT_PRIORITY,
davidben151423e2015-03-23 18:48:36469 &test_delegate_));
[email protected]f7022f32014-08-21 16:32:19470 StartRequest(request.get(), content::RESOURCE_TYPE_MEDIA);
maksim.sisov1b83bb72016-10-07 06:07:23471 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, test_delegate_.request_status());
[email protected]b109bdd2013-11-04 18:08:43472 }
473}
474
lazyboyd6dbb262017-03-30 00:57:30475TEST_F(ExtensionProtocolsTest, MetadataFolder) {
asargenta093ec32016-02-13 01:36:43476 SetProtocolHandler(false);
477
478 base::FilePath extension_dir = GetTestPath("metadata_folder");
479 std::string error;
480 scoped_refptr<Extension> extension =
481 file_util::LoadExtension(extension_dir, Manifest::INTERNAL,
482 Extension::NO_FLAGS, &error);
483 ASSERT_NE(extension.get(), nullptr) << "error: " << error;
484
485 // Loading "/test.html" should succeed.
maksim.sisov1b83bb72016-10-07 06:07:23486 EXPECT_EQ(net::OK, DoRequest(*extension, "test.html"));
asargenta093ec32016-02-13 01:36:43487
488 // Loading "/_metadata/verified_contents.json" should fail.
489 base::FilePath relative_path =
490 base::FilePath(kMetadataFolder).Append(kVerifiedContentsFilename);
491 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
maksim.sisov1b83bb72016-10-07 06:07:23492 EXPECT_EQ(net::ERR_FAILED,
asargenta093ec32016-02-13 01:36:43493 DoRequest(*extension, relative_path.AsUTF8Unsafe()));
494
495 // Loading "/_metadata/a.txt" should also fail.
496 relative_path = base::FilePath(kMetadataFolder).AppendASCII("a.txt");
497 EXPECT_TRUE(base::PathExists(extension_dir.Append(relative_path)));
maksim.sisov1b83bb72016-10-07 06:07:23498 EXPECT_EQ(net::ERR_FAILED,
asargenta093ec32016-02-13 01:36:43499 DoRequest(*extension, relative_path.AsUTF8Unsafe()));
500}
501
lazyboyd6dbb262017-03-30 00:57:30502// Tests that unreadable files and deleted files correctly go through
503// ContentVerifyJob.
504TEST_F(ExtensionProtocolsTest, VerificationSeenForFileAccessErrors) {
505 const char kFooJsContents[] = "hello world.";
506 JobDelegate test_job_delegate(kFooJsContents);
507 SetProtocolHandler(false);
508
509 const std::string kFooJs("foo.js");
510 // Create a temporary directory that a fake extension will live in and fill
511 // it with some test files.
512 base::ScopedTempDir temp_dir;
513 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
514 base::FilePath foo_js(FILE_PATH_LITERAL("foo.js"));
515 ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), foo_js, kFooJsContents))
516 << "Failed to write " << temp_dir.GetPath().value() << "/"
517 << foo_js.value();
518
519 ExtensionBuilder builder;
520 builder
521 .SetManifest(DictionaryBuilder()
522 .Set("name", "Foo")
523 .Set("version", "1.0")
524 .Set("manifest_version", 2)
525 .Set("update_url",
526 "https://clients2.google.com/service/update2/crx")
527 .Build())
528 .SetID(crx_file::id_util::GenerateId("whatever"))
529 .SetPath(temp_dir.GetPath())
530 .SetLocation(Manifest::INTERNAL);
531 scoped_refptr<Extension> extension(builder.Build());
532
533 ASSERT_TRUE(extension.get());
534 content_verifier_->OnExtensionLoaded(testing_profile_.get(), extension.get());
535 // Wait for PostTask to ContentVerifierIOData::AddData() to finish.
536 content::RunAllPendingInMessageLoop();
537
538 // Valid and readable foo.js.
539 EXPECT_EQ(net::OK, DoRequest(*extension, kFooJs));
540 test_job_delegate.WaitForDoneReading(extension->id());
541
542 // chmod -r foo.js.
543 base::FilePath foo_path = temp_dir.GetPath().AppendASCII(kFooJs);
544 ASSERT_TRUE(base::MakeFileUnreadable(foo_path));
545 test_job_delegate.Reset();
546 EXPECT_EQ(net::ERR_ACCESS_DENIED, DoRequest(*extension, kFooJs));
547 test_job_delegate.WaitForDoneReading(extension->id());
548
549 // Delete foo.js.
550 ASSERT_TRUE(base::DieFileDie(foo_path, false));
551 test_job_delegate.Reset();
552 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, DoRequest(*extension, kFooJs));
553 test_job_delegate.WaitForDoneReading(extension->id());
554}
555
[email protected]702d8b42013-02-27 20:55:50556} // namespace extensions