1 // 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.
5 #include "base/message_loop/message_loop.h"
6 #include "base/values.h"
7 #include "chrome/browser/content_settings/cookie_settings.h"
8 #include "chrome/browser/extensions/extension_special_storage_policy.h"
9 #include "chrome/common/content_settings.h"
10 #include "chrome/common/content_settings_types.h"
11 #include "chrome/common/extensions/extension.h"
12 #include "chrome/test/base/testing_profile.h"
13 #include "content/public/test/test_browser_thread.h"
14 #include "extensions/common/manifest.h"
15 #include "extensions/common/manifest_constants.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using content::BrowserThread
;
19 using extensions::Extension
;
20 using extensions::Manifest
;
21 using quota::SpecialStoragePolicy
;
23 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy
;
25 namespace keys
= extensions::manifest_keys
;
27 class ExtensionSpecialStoragePolicyTest
: public testing::Test
{
29 class PolicyChangeObserver
: public SpecialStoragePolicy::Observer
{
31 PolicyChangeObserver()
32 : expected_type_(NOTIFICATION_TYPE_NONE
),
33 expected_change_flags_(0) {
36 virtual void OnGranted(const GURL
& origin
,
37 int change_flags
) OVERRIDE
{
38 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_GRANT
);
39 EXPECT_EQ(expected_origin_
, origin
);
40 EXPECT_EQ(expected_change_flags_
, change_flags
);
41 expected_type_
= NOTIFICATION_TYPE_NONE
;
44 virtual void OnRevoked(const GURL
& origin
,
45 int change_flags
) OVERRIDE
{
46 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_REVOKE
);
47 EXPECT_EQ(expected_origin_
, origin
);
48 EXPECT_EQ(expected_change_flags_
, change_flags
);
49 expected_type_
= NOTIFICATION_TYPE_NONE
;
52 virtual void OnCleared() OVERRIDE
{
53 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_CLEAR
);
54 expected_type_
= NOTIFICATION_TYPE_NONE
;
57 void ExpectGrant(const std::string
& extension_id
,
59 expected_type_
= NOTIFICATION_TYPE_GRANT
;
60 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
61 expected_change_flags_
= change_flags
;
64 void ExpectRevoke(const std::string
& extension_id
,
66 expected_type_
= NOTIFICATION_TYPE_REVOKE
;
67 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
68 expected_change_flags_
= change_flags
;
72 expected_type_
= NOTIFICATION_TYPE_CLEAR
;
76 return expected_type_
== NOTIFICATION_TYPE_NONE
;
81 NOTIFICATION_TYPE_NONE
,
82 NOTIFICATION_TYPE_GRANT
,
83 NOTIFICATION_TYPE_REVOKE
,
84 NOTIFICATION_TYPE_CLEAR
,
87 GURL expected_origin_
;
88 int expected_change_flags_
;
90 DISALLOW_COPY_AND_ASSIGN(PolicyChangeObserver
);
93 virtual void SetUp() OVERRIDE
{
94 policy_
= new ExtensionSpecialStoragePolicy(NULL
);
97 scoped_refptr
<Extension
> CreateProtectedApp() {
99 base::FilePath
path(FILE_PATH_LITERAL("c:\\foo"));
100 #elif defined(OS_POSIX)
101 base::FilePath
path(FILE_PATH_LITERAL("/foo"));
103 DictionaryValue manifest
;
104 manifest
.SetString(keys::kName
, "Protected");
105 manifest
.SetString(keys::kVersion
, "1");
106 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/protected/start");
107 base::ListValue
* list
= new base::ListValue();
108 list
->Append(new base::StringValue("http://explicit/protected"));
109 list
->Append(new base::StringValue("*://*.wildcards/protected"));
110 manifest
.Set(keys::kWebURLs
, list
);
112 scoped_refptr
<Extension
> protected_app
= Extension::Create(
113 path
, Manifest::INVALID_LOCATION
, manifest
,
114 Extension::NO_FLAGS
, &error
);
115 EXPECT_TRUE(protected_app
.get()) << error
;
116 return protected_app
;
119 scoped_refptr
<Extension
> CreateUnlimitedApp() {
121 base::FilePath
path(FILE_PATH_LITERAL("c:\\bar"));
122 #elif defined(OS_POSIX)
123 base::FilePath
path(FILE_PATH_LITERAL("/bar"));
125 DictionaryValue manifest
;
126 manifest
.SetString(keys::kName
, "Unlimited");
127 manifest
.SetString(keys::kVersion
, "1");
128 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/unlimited/start");
129 base::ListValue
* list
= new base::ListValue();
130 list
->Append(new base::StringValue("unlimitedStorage"));
131 manifest
.Set(keys::kPermissions
, list
);
132 list
= new base::ListValue();
133 list
->Append(new base::StringValue("http://explicit/unlimited"));
134 list
->Append(new base::StringValue("*://*.wildcards/unlimited"));
135 manifest
.Set(keys::kWebURLs
, list
);
137 scoped_refptr
<Extension
> unlimited_app
= Extension::Create(
138 path
, Manifest::INVALID_LOCATION
, manifest
,
139 Extension::NO_FLAGS
, &error
);
140 EXPECT_TRUE(unlimited_app
.get()) << error
;
141 return unlimited_app
;
144 scoped_refptr
<Extension
> CreateRegularApp() {
146 base::FilePath
path(FILE_PATH_LITERAL("c:\\app"));
147 #elif defined(OS_POSIX)
148 base::FilePath
path(FILE_PATH_LITERAL("/app"));
150 DictionaryValue manifest
;
151 manifest
.SetString(keys::kName
, "App");
152 manifest
.SetString(keys::kVersion
, "1");
153 manifest
.SetString(keys::kPlatformAppBackgroundPage
, "background.html");
155 scoped_refptr
<Extension
> app
= Extension::Create(
156 path
, Manifest::INVALID_LOCATION
, manifest
,
157 Extension::NO_FLAGS
, &error
);
158 EXPECT_TRUE(app
.get()) << error
;
162 // Verifies that the set of extensions protecting |url| is *exactly* equal to
163 // |expected_extensions|. Pass in an empty set to verify that an origin is not
165 void ExpectProtectedBy(const ExtensionSet
& expected_extensions
,
167 const ExtensionSet
* extensions
= policy_
->ExtensionsProtectingOrigin(url
);
168 EXPECT_EQ(expected_extensions
.size(), extensions
->size());
169 for (ExtensionSet::const_iterator it
= expected_extensions
.begin();
170 it
!= expected_extensions
.end(); ++it
) {
171 EXPECT_TRUE(extensions
->Contains((*it
)->id()))
172 << "Origin " << url
<< "not protected by extension ID "
177 scoped_refptr
<ExtensionSpecialStoragePolicy
> policy_
;
180 TEST_F(ExtensionSpecialStoragePolicyTest
, EmptyPolicy
) {
181 const GURL
kHttpUrl("http://foo");
182 const GURL
kExtensionUrl("chrome-extension://bar");
183 scoped_refptr
<Extension
> app(CreateRegularApp());
185 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
));
186 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
)); // test cached result
187 EXPECT_FALSE(policy_
->IsStorageUnlimited(kExtensionUrl
));
188 EXPECT_FALSE(policy_
->IsStorageUnlimited(app
->url()));
189 ExtensionSet empty_set
;
190 ExpectProtectedBy(empty_set
, kHttpUrl
);
192 // This one is just based on the scheme.
193 EXPECT_TRUE(policy_
->IsStorageProtected(kExtensionUrl
));
194 EXPECT_TRUE(policy_
->IsStorageProtected(app
->url()));
197 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithProtectedStorage
) {
198 scoped_refptr
<Extension
> extension(CreateProtectedApp());
199 policy_
->GrantRightsForExtension(extension
.get());
200 ExtensionSet protecting_extensions
;
201 protecting_extensions
.Insert(extension
);
202 ExtensionSet empty_set
;
204 EXPECT_FALSE(policy_
->IsStorageUnlimited(extension
->url()));
205 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
206 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
207 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
208 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
209 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
210 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
212 policy_
->RevokeRightsForExtension(extension
.get());
213 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
214 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
215 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
218 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithUnlimitedStorage
) {
219 scoped_refptr
<Extension
> extension(CreateUnlimitedApp());
220 policy_
->GrantRightsForExtension(extension
.get());
221 ExtensionSet protecting_extensions
;
222 protecting_extensions
.Insert(extension
);
223 ExtensionSet empty_set
;
225 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
226 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
227 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
228 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
229 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
230 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
231 EXPECT_TRUE(policy_
->IsStorageUnlimited(extension
->url()));
232 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
233 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
234 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
235 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
236 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
238 policy_
->RevokeRightsForExtension(extension
.get());
239 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
240 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
241 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
242 ExpectProtectedBy(empty_set
, GURL("http://bar.wildcards/"));
243 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
244 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
245 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
248 TEST_F(ExtensionSpecialStoragePolicyTest
, CanQueryDiskSize
) {
249 const GURL
kHttpUrl("http://foo");
250 const GURL
kExtensionUrl("chrome-extension://bar");
251 scoped_refptr
<Extension
> regular_app(CreateRegularApp());
252 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
253 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
254 policy_
->GrantRightsForExtension(regular_app
.get());
255 policy_
->GrantRightsForExtension(protected_app
.get());
256 policy_
->GrantRightsForExtension(unlimited_app
.get());
258 EXPECT_FALSE(policy_
->CanQueryDiskSize(kHttpUrl
));
259 EXPECT_FALSE(policy_
->CanQueryDiskSize(kExtensionUrl
));
260 EXPECT_TRUE(policy_
->CanQueryDiskSize(regular_app
->url()));
261 EXPECT_TRUE(policy_
->CanQueryDiskSize(protected_app
->url()));
262 EXPECT_TRUE(policy_
->CanQueryDiskSize(unlimited_app
->url()));
265 TEST_F(ExtensionSpecialStoragePolicyTest
, HasIsolatedStorage
) {
266 const GURL
kHttpUrl("http://foo");
267 const GURL
kExtensionUrl("chrome-extension://bar");
268 scoped_refptr
<Extension
> app(CreateRegularApp());
269 policy_
->GrantRightsForExtension(app
.get());
271 EXPECT_FALSE(policy_
->HasIsolatedStorage(kHttpUrl
));
272 EXPECT_FALSE(policy_
->HasIsolatedStorage(kExtensionUrl
));
273 EXPECT_TRUE(policy_
->HasIsolatedStorage(app
->url()));
276 TEST_F(ExtensionSpecialStoragePolicyTest
, OverlappingApps
) {
277 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
278 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
279 policy_
->GrantRightsForExtension(protected_app
.get());
280 policy_
->GrantRightsForExtension(unlimited_app
.get());
281 ExtensionSet protecting_extensions
;
282 ExtensionSet empty_set
;
283 protecting_extensions
.Insert(protected_app
);
284 protecting_extensions
.Insert(unlimited_app
);
286 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
287 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
288 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
289 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
290 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
291 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
292 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
293 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
294 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
295 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
296 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
298 policy_
->RevokeRightsForExtension(unlimited_app
.get());
299 protecting_extensions
.Remove(unlimited_app
->id());
300 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
301 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
302 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
303 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
304 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
305 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
307 policy_
->RevokeRightsForExtension(protected_app
.get());
308 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
309 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
310 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
313 TEST_F(ExtensionSpecialStoragePolicyTest
, HasSessionOnlyOrigins
) {
314 base::MessageLoop message_loop
;
315 content::TestBrowserThread
ui_thread(BrowserThread::UI
, &message_loop
);
317 TestingProfile profile
;
318 CookieSettings
* cookie_settings
=
319 CookieSettings::Factory::GetForProfile(&profile
).get();
320 policy_
= new ExtensionSpecialStoragePolicy(cookie_settings
);
322 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
324 // The default setting can be session-only.
325 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY
);
326 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
328 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW
);
329 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
331 // Or the session-onlyness can affect individual origins.
332 ContentSettingsPattern pattern
=
333 ContentSettingsPattern::FromString("pattern.com");
335 cookie_settings
->SetCookieSetting(pattern
,
336 ContentSettingsPattern::Wildcard(),
337 CONTENT_SETTING_SESSION_ONLY
);
339 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
341 // Clearing an origin-specific rule.
342 cookie_settings
->ResetCookieSetting(pattern
,
343 ContentSettingsPattern::Wildcard());
345 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
348 TEST_F(ExtensionSpecialStoragePolicyTest
, NotificationTest
) {
349 base::MessageLoop message_loop
;
350 content::TestBrowserThread
ui_thread(BrowserThread::UI
, &message_loop
);
351 content::TestBrowserThread
io_thread(BrowserThread::IO
, &message_loop
);
353 PolicyChangeObserver observer
;
354 policy_
->AddObserver(&observer
);
356 scoped_refptr
<Extension
> apps
[] = {
357 CreateProtectedApp(),
358 CreateUnlimitedApp(),
361 int change_flags
[] = {
362 SpecialStoragePolicy::STORAGE_PROTECTED
,
364 SpecialStoragePolicy::STORAGE_PROTECTED
|
365 SpecialStoragePolicy::STORAGE_UNLIMITED
,
368 ASSERT_EQ(arraysize(apps
), arraysize(change_flags
));
369 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
370 SCOPED_TRACE(testing::Message() << "i: " << i
);
371 observer
.ExpectGrant(apps
[i
]->id(), change_flags
[i
]);
372 policy_
->GrantRightsForExtension(apps
[i
].get());
373 message_loop
.RunUntilIdle();
374 EXPECT_TRUE(observer
.IsCompleted());
377 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
378 SCOPED_TRACE(testing::Message() << "i: " << i
);
379 policy_
->GrantRightsForExtension(apps
[i
].get());
380 message_loop
.RunUntilIdle();
381 EXPECT_TRUE(observer
.IsCompleted());
384 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
385 SCOPED_TRACE(testing::Message() << "i: " << i
);
386 observer
.ExpectRevoke(apps
[i
]->id(), change_flags
[i
]);
387 policy_
->RevokeRightsForExtension(apps
[i
].get());
388 message_loop
.RunUntilIdle();
389 EXPECT_TRUE(observer
.IsCompleted());
392 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
393 SCOPED_TRACE(testing::Message() << "i: " << i
);
394 policy_
->RevokeRightsForExtension(apps
[i
].get());
395 message_loop
.RunUntilIdle();
396 EXPECT_TRUE(observer
.IsCompleted());
399 observer
.ExpectClear();
400 policy_
->RevokeRightsForAllExtensions();
401 message_loop
.RunUntilIdle();
402 EXPECT_TRUE(observer
.IsCompleted());
404 policy_
->RemoveObserver(&observer
);