blob: b096d98a3f120c8396cbdc0ba6da9b19bc5b7b07 [file] [log] [blame]
[email protected]5e212ed2012-03-21 23:29:151// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6
7#include "base/file_util.h"
8#include "base/message_loop.h"
[email protected]00e7bef2013-06-10 20:35:179#include "base/strings/string_util.h"
[email protected]06492ed2013-03-24 22:13:1410#include "base/values.h"
[email protected]5e212ed2012-03-21 23:29:1511#include "chrome/browser/extensions/extension_info_map.h"
12#include "chrome/browser/extensions/extension_protocols.h"
[email protected]93ac047a2012-12-13 02:53:4913#include "chrome/common/chrome_paths.h"
[email protected]06492ed2013-03-24 22:13:1414#include "chrome/common/extensions/extension.h"
15#include "chrome/common/extensions/extension_manifest_constants.h"
[email protected]5e212ed2012-03-21 23:29:1516#include "chrome/common/url_constants.h"
17#include "content/public/browser/resource_request_info.h"
[email protected]08a932d52012-06-03 21:42:1218#include "content/public/test/mock_resource_context.h"
[email protected]ec04d3f2013-06-06 21:31:3919#include "content/public/test/test_browser_thread_bundle.h"
[email protected]885c0e92012-11-13 20:27:4220#include "extensions/common/constants.h"
[email protected]5e212ed2012-03-21 23:29:1521#include "net/url_request/url_request.h"
[email protected]9d5730b2012-08-24 17:42:4922#include "net/url_request/url_request_job_factory_impl.h"
[email protected]5e212ed2012-03-21 23:29:1523#include "net/url_request/url_request_status.h"
24#include "net/url_request/url_request_test_util.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
[email protected]702d8b42013-02-27 20:55:5027namespace extensions {
[email protected]5e212ed2012-03-21 23:29:1528
29scoped_refptr<Extension> CreateTestExtension(const std::string& name,
30 bool incognito_split_mode) {
31 DictionaryValue manifest;
32 manifest.SetString("name", name);
33 manifest.SetString("version", "1");
34 manifest.SetString("incognito", incognito_split_mode ? "split" : "spanning");
35
[email protected]650b2d52013-02-10 03:41:4536 base::FilePath path;
[email protected]5e212ed2012-03-21 23:29:1537 EXPECT_TRUE(file_util::GetCurrentDirectory(&path));
38
39 std::string error;
40 scoped_refptr<Extension> extension(
[email protected]1d5e58b2013-01-31 08:41:4041 Extension::Create(path, Manifest::INTERNAL, manifest,
[email protected]ed3b9b12012-05-31 18:37:5142 Extension::NO_FLAGS, &error));
[email protected]5e212ed2012-03-21 23:29:1543 EXPECT_TRUE(extension.get()) << error;
44 return extension;
45}
46
[email protected]93ac047a2012-12-13 02:53:4947scoped_refptr<Extension> CreateWebStoreExtension() {
48 DictionaryValue manifest;
49 manifest.SetString("name", "WebStore");
50 manifest.SetString("version", "1");
51 manifest.SetString("icons.16", "webstore_icon_16.png");
52
[email protected]650b2d52013-02-10 03:41:4553 base::FilePath path;
[email protected]93ac047a2012-12-13 02:53:4954 EXPECT_TRUE(PathService::Get(chrome::DIR_RESOURCES, &path));
55 path = path.AppendASCII("web_store");
56
57 std::string error;
58 scoped_refptr<Extension> extension(
[email protected]1d5e58b2013-01-31 08:41:4059 Extension::Create(path, Manifest::COMPONENT, manifest,
[email protected]93ac047a2012-12-13 02:53:4960 Extension::NO_FLAGS, &error));
61 EXPECT_TRUE(extension.get()) << error;
62 return extension;
63}
64
[email protected]6f7d7062013-06-04 03:49:3365scoped_refptr<Extension> CreateTestResponseHeaderExtension() {
66 DictionaryValue manifest;
67 manifest.SetString("name", "An extension with web-accessible resources");
68 manifest.SetString("version", "2");
69
[email protected]aeca23f2013-06-21 22:34:4170 base::ListValue* web_accessible_list = new base::ListValue();
[email protected]6f7d7062013-06-04 03:49:3371 web_accessible_list->AppendString("test.dat");
72 manifest.Set("web_accessible_resources", web_accessible_list);
73
74 base::FilePath path;
75 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
76 path = path.AppendASCII("extensions").AppendASCII("response_headers");
77
78 std::string error;
79 scoped_refptr<Extension> extension(
80 Extension::Create(path, Manifest::UNPACKED, manifest,
81 Extension::NO_FLAGS, &error));
82 EXPECT_TRUE(extension.get()) << error;
83 return extension;
84}
85
[email protected]5e212ed2012-03-21 23:29:1586class ExtensionProtocolTest : public testing::Test {
87 public:
88 ExtensionProtocolTest()
[email protected]ec04d3f2013-06-06 21:31:3989 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
[email protected]5e212ed2012-03-21 23:29:1590
[email protected]06492ed2013-03-24 22:13:1491 virtual void SetUp() OVERRIDE {
92 testing::Test::SetUp();
[email protected]5e212ed2012-03-21 23:29:1593 extension_info_map_ = new ExtensionInfoMap();
94 net::URLRequestContext* request_context =
95 resource_context_.GetRequestContext();
96 old_factory_ = request_context->job_factory();
[email protected]5e212ed2012-03-21 23:29:1597 }
98
99 virtual void TearDown() {
100 net::URLRequestContext* request_context =
101 resource_context_.GetRequestContext();
102 request_context->set_job_factory(old_factory_);
[email protected]5e212ed2012-03-21 23:29:15103 }
104
[email protected]93ac047a2012-12-13 02:53:49105 void SetProtocolHandler(bool incognito) {
106 net::URLRequestContext* request_context =
107 resource_context_.GetRequestContext();
108 job_factory_.SetProtocolHandler(
[email protected]702d8b42013-02-27 20:55:50109 kExtensionScheme,
[email protected]dc24976f2013-06-02 21:15:09110 CreateExtensionProtocolHandler(incognito, extension_info_map_.get()));
[email protected]93ac047a2012-12-13 02:53:49111 request_context->set_job_factory(&job_factory_);
112 }
113
[email protected]5e212ed2012-03-21 23:29:15114 void StartRequest(net::URLRequest* request,
115 ResourceType::Type resource_type) {
116 content::ResourceRequestInfo::AllocateForTesting(request,
117 resource_type,
[email protected]ef108e72012-06-20 14:03:54118 &resource_context_,
119 -1,
120 -1);
[email protected]5e212ed2012-03-21 23:29:15121 request->Start();
[email protected]b3a25092013-05-28 22:08:16122 base::MessageLoop::current()->Run();
[email protected]5e212ed2012-03-21 23:29:15123 }
124
125 protected:
[email protected]ec04d3f2013-06-06 21:31:39126 content::TestBrowserThreadBundle thread_bundle_;
[email protected]5e212ed2012-03-21 23:29:15127 scoped_refptr<ExtensionInfoMap> extension_info_map_;
[email protected]9d5730b2012-08-24 17:42:49128 net::URLRequestJobFactoryImpl job_factory_;
[email protected]5e212ed2012-03-21 23:29:15129 const net::URLRequestJobFactory* old_factory_;
[email protected]2086a3d2012-11-13 17:49:20130 net::TestDelegate test_delegate_;
[email protected]5e212ed2012-03-21 23:29:15131 content::MockResourceContext resource_context_;
132};
133
134// Tests that making a chrome-extension request in an incognito context is
135// only allowed under the right circumstances (if the extension is allowed
136// in incognito, and it's either a non-main-frame request or a split-mode
137// extension).
138TEST_F(ExtensionProtocolTest, IncognitoRequest) {
[email protected]93ac047a2012-12-13 02:53:49139 // Register an incognito extension protocol handler.
140 SetProtocolHandler(true);
141
[email protected]5e212ed2012-03-21 23:29:15142 struct TestCase {
143 // Inputs.
144 std::string name;
145 bool incognito_split_mode;
146 bool incognito_enabled;
147
148 // Expected results.
149 bool should_allow_main_frame_load;
150 bool should_allow_sub_frame_load;
151 } cases[] = {
152 {"spanning disabled", false, false, false, false},
153 {"split disabled", true, false, false, false},
154 {"spanning enabled", false, true, false, true},
155 {"split enabled", true, true, true, true},
156 };
157
158 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
159 scoped_refptr<Extension> extension =
160 CreateTestExtension(cases[i].name, cases[i].incognito_split_mode);
161 extension_info_map_->AddExtension(
[email protected]dc24976f2013-06-02 21:15:09162 extension.get(), base::Time::Now(), cases[i].incognito_enabled);
[email protected]5e212ed2012-03-21 23:29:15163
164 // First test a main frame request.
165 {
166 // It doesn't matter that the resource doesn't exist. If the resource
167 // is blocked, we should see ADDRESS_UNREACHABLE. Otherwise, the request
168 // should just fail because the file doesn't exist.
169 net::URLRequest request(extension->GetResourceURL("404.html"),
[email protected]94e2bbe2012-06-22 15:26:13170 &test_delegate_,
171 resource_context_.GetRequestContext());
[email protected]5e212ed2012-03-21 23:29:15172 StartRequest(&request, ResourceType::MAIN_FRAME);
173 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
174
175 if (cases[i].should_allow_main_frame_load) {
176 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request.status().error()) <<
177 cases[i].name;
178 } else {
179 EXPECT_EQ(net::ERR_ADDRESS_UNREACHABLE, request.status().error()) <<
180 cases[i].name;
181 }
182 }
183
184 // Now do a subframe request.
185 {
186 net::URLRequest request(extension->GetResourceURL("404.html"),
[email protected]94e2bbe2012-06-22 15:26:13187 &test_delegate_,
188 resource_context_.GetRequestContext());
[email protected]5e212ed2012-03-21 23:29:15189 StartRequest(&request, ResourceType::SUB_FRAME);
190 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
191
192 if (cases[i].should_allow_sub_frame_load) {
193 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request.status().error()) <<
194 cases[i].name;
195 } else {
196 EXPECT_EQ(net::ERR_ADDRESS_UNREACHABLE, request.status().error()) <<
197 cases[i].name;
198 }
199 }
200 }
201}
202
[email protected]93ac047a2012-12-13 02:53:49203// Tests getting a resource for a component extension works correctly, both when
204// the extension is enabled and when it is disabled.
205TEST_F(ExtensionProtocolTest, ComponentResourceRequest) {
206 // Register a non-incognito extension protocol handler.
207 SetProtocolHandler(false);
208
209 scoped_refptr<Extension> extension = CreateWebStoreExtension();
[email protected]dc24976f2013-06-02 21:15:09210 extension_info_map_->AddExtension(extension.get(), base::Time::Now(), false);
[email protected]93ac047a2012-12-13 02:53:49211
212 // First test it with the extension enabled.
213 {
214 net::URLRequest request(extension->GetResourceURL("webstore_icon_16.png"),
215 &test_delegate_,
216 resource_context_.GetRequestContext());
217 StartRequest(&request, ResourceType::MEDIA);
218 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
219 }
220
221 // And then test it with the extension disabled.
222 extension_info_map_->RemoveExtension(extension->id(),
223 extension_misc::UNLOAD_REASON_DISABLE);
224 {
225 net::URLRequest request(extension->GetResourceURL("webstore_icon_16.png"),
226 &test_delegate_,
227 resource_context_.GetRequestContext());
228 StartRequest(&request, ResourceType::MEDIA);
229 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
230 }
231}
232
[email protected]6f7d7062013-06-04 03:49:33233// Tests that a URL request for resource from an extension returns a few
234// expected response headers.
235TEST_F(ExtensionProtocolTest, ResourceRequestResponseHeaders) {
236 // Register a non-incognito extension protocol handler.
237 SetProtocolHandler(false);
238
239 scoped_refptr<Extension> extension = CreateTestResponseHeaderExtension();
[email protected]cadac622013-06-11 16:46:36240 extension_info_map_->AddExtension(extension.get(), base::Time::Now(), false);
[email protected]6f7d7062013-06-04 03:49:33241
242 {
243 net::URLRequest request(extension->GetResourceURL("test.dat"),
244 &test_delegate_,
245 resource_context_.GetRequestContext());
246 StartRequest(&request, ResourceType::MEDIA);
247 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
248
249 // Check that cache-related headers are set.
250 std::string etag;
251 request.GetResponseHeaderByName("ETag", &etag);
252 EXPECT_TRUE(StartsWithASCII(etag, "\"", false));
253 EXPECT_TRUE(EndsWith(etag, "\"", false));
254
255 std::string revalidation_header;
256 request.GetResponseHeaderByName("cache-control", &revalidation_header);
257 EXPECT_EQ("no-cache", revalidation_header);
258
259 // We set test.dat as web-accessible, so it should have a CORS header.
260 std::string access_control;
261 request.GetResponseHeaderByName("Access-Control-Allow-Origin",
262 &access_control);
263 EXPECT_EQ("*", access_control);
264 }
265}
266
[email protected]702d8b42013-02-27 20:55:50267} // namespace extensions