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. 4 5#include "chrome/browser/content_settings/content_settings_pref_provider.h" 6 7#include "base/auto_reset.h" 8#include "base/command_line.h" 9#include "base/memory/scoped_ptr.h" 10#include "base/message_loop/message_loop.h" 11#include "base/prefs/default_pref_store.h" 12#include "base/prefs/overlay_user_pref_store.h" 13#include "base/prefs/pref_change_registrar.h" 14#include "base/prefs/pref_service.h" 15#include "base/prefs/scoped_user_pref_update.h" 16#include "base/prefs/testing_pref_store.h" 17#include "base/test/simple_test_clock.h" 18#include "base/threading/platform_thread.h" 19#include "base/values.h" 20#include "chrome/browser/content_settings/content_settings_mock_observer.h" 21#include "chrome/browser/content_settings/content_settings_utils.h" 22#include "chrome/browser/prefs/browser_prefs.h" 23#include "chrome/browser/prefs/pref_service_mock_factory.h" 24#include "chrome/browser/prefs/pref_service_syncable.h" 25#include "chrome/common/chrome_switches.h" 26#include "chrome/common/pref_names.h" 27#include "chrome/common/url_constants.h" 28#include "chrome/test/base/testing_pref_service_syncable.h" 29#include "chrome/test/base/testing_profile.h" 30#include "components/pref_registry/pref_registry_syncable.h" 31#include "content/public/test/test_browser_thread.h" 32#include "testing/gtest/include/gtest/gtest.h" 33#include "url/gurl.h" 34 35using ::testing::_; 36using content::BrowserThread; 37 38namespace content_settings { 39 40class DeadlockCheckerThread : public base::PlatformThread::Delegate { 41 public: 42 explicit DeadlockCheckerThread(PrefProvider* provider) 43 : provider_(provider) {} 44 45 virtual void ThreadMain() OVERRIDE { 46 bool got_lock = provider_->lock_.Try(); 47 EXPECT_TRUE(got_lock); 48 if (got_lock) 49 provider_->lock_.Release(); 50 } 51 private: 52 PrefProvider* provider_; 53 DISALLOW_COPY_AND_ASSIGN(DeadlockCheckerThread); 54}; 55 56// A helper for observing an preference changes and testing whether 57// |PrefProvider| holds a lock when the preferences change. 58class DeadlockCheckerObserver { 59 public: 60 // |DeadlockCheckerObserver| doesn't take the ownership of |prefs| or 61 // ||provider|. 62 DeadlockCheckerObserver(PrefService* prefs, PrefProvider* provider) 63 : provider_(provider), 64 notification_received_(false) { 65 pref_change_registrar_.Init(prefs); 66 pref_change_registrar_.Add( 67 prefs::kContentSettingsPatternPairs, 68 base::Bind( 69 &DeadlockCheckerObserver::OnContentSettingsPatternPairsChanged, 70 base::Unretained(this))); 71 } 72 virtual ~DeadlockCheckerObserver() {} 73 74 bool notification_received() const { 75 return notification_received_; 76 } 77 78 private: 79 void OnContentSettingsPatternPairsChanged() { 80 // Check whether |provider_| holds its lock. For this, we need a 81 // separate thread. 82 DeadlockCheckerThread thread(provider_); 83 base::PlatformThreadHandle handle; 84 ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle)); 85 base::PlatformThread::Join(handle); 86 notification_received_ = true; 87 } 88 89 PrefProvider* provider_; 90 PrefChangeRegistrar pref_change_registrar_; 91 bool notification_received_; 92 DISALLOW_COPY_AND_ASSIGN(DeadlockCheckerObserver); 93}; 94 95class PrefProviderTest : public testing::Test { 96 public: 97 PrefProviderTest() : ui_thread_( 98 BrowserThread::UI, &message_loop_) { 99 } 100 101 protected: 102 base::MessageLoop message_loop_; 103 content::TestBrowserThread ui_thread_; 104}; 105 106TEST_F(PrefProviderTest, Observer) { 107 TestingProfile profile; 108 PrefProvider pref_content_settings_provider(profile.GetPrefs(), false); 109 110 ContentSettingsPattern pattern = 111 ContentSettingsPattern::FromString("[*.]example.com"); 112 content_settings::MockObserver mock_observer; 113 EXPECT_CALL(mock_observer, 114 OnContentSettingChanged(pattern, 115 ContentSettingsPattern::Wildcard(), 116 CONTENT_SETTINGS_TYPE_IMAGES, 117 "")); 118 119 pref_content_settings_provider.AddObserver(&mock_observer); 120 121 pref_content_settings_provider.SetWebsiteSetting( 122 pattern, 123 ContentSettingsPattern::Wildcard(), 124 CONTENT_SETTINGS_TYPE_IMAGES, 125 std::string(), 126 new base::FundamentalValue(CONTENT_SETTING_ALLOW)); 127 128 pref_content_settings_provider.ShutdownOnUIThread(); 129} 130 131// Test for regression in which the PrefProvider modified the user pref store 132// of the OTR unintentionally: http://crbug.com/74466. 133TEST_F(PrefProviderTest, Incognito) { 134 PersistentPrefStore* user_prefs = new TestingPrefStore(); 135 OverlayUserPrefStore* otr_user_prefs = 136 new OverlayUserPrefStore(user_prefs); 137 138 PrefServiceMockFactory factory; 139 factory.set_user_prefs(make_scoped_refptr(user_prefs)); 140 scoped_refptr<user_prefs::PrefRegistrySyncable> registry( 141 new user_prefs::PrefRegistrySyncable); 142 PrefServiceSyncable* regular_prefs = 143 factory.CreateSyncable(registry.get()).release(); 144 145 chrome::RegisterUserProfilePrefs(registry.get()); 146 147 PrefServiceMockFactory otr_factory; 148 otr_factory.set_user_prefs(make_scoped_refptr(otr_user_prefs)); 149 scoped_refptr<user_prefs::PrefRegistrySyncable> otr_registry( 150 new user_prefs::PrefRegistrySyncable); 151 PrefServiceSyncable* otr_prefs = 152 otr_factory.CreateSyncable(otr_registry.get()).release(); 153 154 chrome::RegisterUserProfilePrefs(otr_registry.get()); 155 156 TestingProfile::Builder profile_builder; 157 profile_builder.SetPrefService(make_scoped_ptr(regular_prefs)); 158 scoped_ptr<TestingProfile> profile = profile_builder.Build(); 159 160 TestingProfile::Builder otr_profile_builder; 161 otr_profile_builder.SetPrefService(make_scoped_ptr(otr_prefs)); 162 otr_profile_builder.BuildIncognito(profile.get()); 163 164 PrefProvider pref_content_settings_provider(regular_prefs, false); 165 PrefProvider pref_content_settings_provider_incognito(otr_prefs, true); 166 ContentSettingsPattern pattern = 167 ContentSettingsPattern::FromString("[*.]example.com"); 168 pref_content_settings_provider.SetWebsiteSetting( 169 pattern, 170 pattern, 171 CONTENT_SETTINGS_TYPE_IMAGES, 172 std::string(), 173 new base::FundamentalValue(CONTENT_SETTING_ALLOW)); 174 175 GURL host("http://example.com/"); 176 // The value should of course be visible in the regular PrefProvider. 177 EXPECT_EQ(CONTENT_SETTING_ALLOW, 178 GetContentSetting(&pref_content_settings_provider, 179 host, 180 host, 181 CONTENT_SETTINGS_TYPE_IMAGES, 182 std::string(), 183 false)); 184 // And also in the OTR version. 185 EXPECT_EQ(CONTENT_SETTING_ALLOW, 186 GetContentSetting(&pref_content_settings_provider_incognito, 187 host, 188 host, 189 CONTENT_SETTINGS_TYPE_IMAGES, 190 std::string(), 191 false)); 192 // But the value should not be overridden in the OTR user prefs accidentally. 193 EXPECT_FALSE(otr_user_prefs->IsSetInOverlay( 194 prefs::kContentSettingsPatternPairs)); 195 196 pref_content_settings_provider.ShutdownOnUIThread(); 197 pref_content_settings_provider_incognito.ShutdownOnUIThread(); 198} 199 200TEST_F(PrefProviderTest, GetContentSettingsValue) { 201 TestingProfile testing_profile; 202 PrefProvider provider(testing_profile.GetPrefs(), false); 203 204 GURL primary_url("http://example.com/"); 205 ContentSettingsPattern primary_pattern = 206 ContentSettingsPattern::FromString("[*.]example.com"); 207 208 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 209 GetContentSetting(&provider, 210 primary_url, 211 primary_url, 212 CONTENT_SETTINGS_TYPE_IMAGES, 213 std::string(), 214 false)); 215 216 EXPECT_EQ(NULL, 217 GetContentSettingValue(&provider, 218 primary_url, 219 primary_url, 220 CONTENT_SETTINGS_TYPE_IMAGES, 221 std::string(), 222 false)); 223 224 provider.SetWebsiteSetting(primary_pattern, 225 primary_pattern, 226 CONTENT_SETTINGS_TYPE_IMAGES, 227 std::string(), 228 new base::FundamentalValue(CONTENT_SETTING_BLOCK)); 229 EXPECT_EQ(CONTENT_SETTING_BLOCK, 230 GetContentSetting(&provider, 231 primary_url, 232 primary_url, 233 CONTENT_SETTINGS_TYPE_IMAGES, 234 std::string(), 235 false)); 236 scoped_ptr<base::Value> value_ptr( 237 GetContentSettingValue(&provider, 238 primary_url, 239 primary_url, 240 CONTENT_SETTINGS_TYPE_IMAGES, 241 std::string(), 242 false)); 243 int int_value = -1; 244 value_ptr->GetAsInteger(&int_value); 245 EXPECT_EQ(CONTENT_SETTING_BLOCK, IntToContentSetting(int_value)); 246 247 provider.SetWebsiteSetting(primary_pattern, 248 primary_pattern, 249 CONTENT_SETTINGS_TYPE_IMAGES, 250 std::string(), 251 NULL); 252 EXPECT_EQ(NULL, 253 GetContentSettingValue(&provider, 254 primary_url, 255 primary_url, 256 CONTENT_SETTINGS_TYPE_IMAGES, 257 std::string(), 258 false)); 259 provider.ShutdownOnUIThread(); 260} 261 262TEST_F(PrefProviderTest, Patterns) { 263 TestingProfile testing_profile; 264 PrefProvider pref_content_settings_provider(testing_profile.GetPrefs(), 265 false); 266 267 GURL host1("http://example.com/"); 268 GURL host2("http://www.example.com/"); 269 GURL host3("http://example.org/"); 270 GURL host4("file:///tmp/test.html"); 271 ContentSettingsPattern pattern1 = 272 ContentSettingsPattern::FromString("[*.]example.com"); 273 ContentSettingsPattern pattern2 = 274 ContentSettingsPattern::FromString("example.org"); 275 ContentSettingsPattern pattern3 = 276 ContentSettingsPattern::FromString("file:///tmp/test.html"); 277 278 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 279 GetContentSetting(&pref_content_settings_provider, 280 host1, 281 host1, 282 CONTENT_SETTINGS_TYPE_IMAGES, 283 std::string(), 284 false)); 285 pref_content_settings_provider.SetWebsiteSetting( 286 pattern1, 287 pattern1, 288 CONTENT_SETTINGS_TYPE_IMAGES, 289 std::string(), 290 new base::FundamentalValue(CONTENT_SETTING_BLOCK)); 291 EXPECT_EQ(CONTENT_SETTING_BLOCK, 292 GetContentSetting(&pref_content_settings_provider, 293 host1, 294 host1, 295 CONTENT_SETTINGS_TYPE_IMAGES, 296 std::string(), 297 false)); 298 EXPECT_EQ(CONTENT_SETTING_BLOCK, 299 GetContentSetting(&pref_content_settings_provider, 300 host2, 301 host2, 302 CONTENT_SETTINGS_TYPE_IMAGES, 303 std::string(), 304 false)); 305 306 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 307 GetContentSetting(&pref_content_settings_provider, 308 host3, 309 host3, 310 CONTENT_SETTINGS_TYPE_IMAGES, 311 std::string(), 312 false)); 313 pref_content_settings_provider.SetWebsiteSetting( 314 pattern2, 315 pattern2, 316 CONTENT_SETTINGS_TYPE_IMAGES, 317 std::string(), 318 new base::FundamentalValue(CONTENT_SETTING_BLOCK)); 319 EXPECT_EQ(CONTENT_SETTING_BLOCK, 320 GetContentSetting(&pref_content_settings_provider, 321 host3, 322 host3, 323 CONTENT_SETTINGS_TYPE_IMAGES, 324 std::string(), 325 false)); 326 327 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 328 GetContentSetting(&pref_content_settings_provider, 329 host4, 330 host4, 331 CONTENT_SETTINGS_TYPE_IMAGES, 332 std::string(), 333 false)); 334 pref_content_settings_provider.SetWebsiteSetting( 335 pattern3, 336 pattern3, 337 CONTENT_SETTINGS_TYPE_IMAGES, 338 std::string(), 339 new base::FundamentalValue(CONTENT_SETTING_BLOCK)); 340 EXPECT_EQ(CONTENT_SETTING_BLOCK, 341 GetContentSetting(&pref_content_settings_provider, 342 host4, 343 host4, 344 CONTENT_SETTINGS_TYPE_IMAGES, 345 std::string(), 346 false)); 347 348 pref_content_settings_provider.ShutdownOnUIThread(); 349} 350 351TEST_F(PrefProviderTest, ResourceIdentifier) { 352 TestingProfile testing_profile; 353 PrefProvider pref_content_settings_provider(testing_profile.GetPrefs(), 354 false); 355 356 GURL host("http://example.com/"); 357 ContentSettingsPattern pattern = 358 ContentSettingsPattern::FromString("[*.]example.com"); 359 std::string resource1("someplugin"); 360 std::string resource2("otherplugin"); 361 362 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 363 GetContentSetting( 364 &pref_content_settings_provider, 365 host, host, CONTENT_SETTINGS_TYPE_PLUGINS, 366 resource1, false)); 367 pref_content_settings_provider.SetWebsiteSetting( 368 pattern, 369 pattern, 370 CONTENT_SETTINGS_TYPE_PLUGINS, 371 resource1, 372 new base::FundamentalValue(CONTENT_SETTING_BLOCK)); 373 EXPECT_EQ(CONTENT_SETTING_BLOCK, 374 GetContentSetting( 375 &pref_content_settings_provider, 376 host, host, CONTENT_SETTINGS_TYPE_PLUGINS, 377 resource1, false)); 378 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 379 GetContentSetting( 380 &pref_content_settings_provider, 381 host, host, CONTENT_SETTINGS_TYPE_PLUGINS, 382 resource2, false)); 383 384 pref_content_settings_provider.ShutdownOnUIThread(); 385} 386 387TEST_F(PrefProviderTest, AutoSubmitCertificateContentSetting) { 388 TestingProfile profile; 389 TestingPrefServiceSyncable* prefs = profile.GetTestingPrefService(); 390 GURL primary_url("https://www.example.com"); 391 GURL secondary_url("https://www.sample.com"); 392 393 PrefProvider provider(prefs, false); 394 395 EXPECT_EQ(CONTENT_SETTING_DEFAULT, 396 GetContentSetting( 397 &provider, 398 primary_url, 399 primary_url, 400 CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, 401 std::string(), 402 false)); 403 404 provider.SetWebsiteSetting(ContentSettingsPattern::FromURL(primary_url), 405 ContentSettingsPattern::Wildcard(), 406 CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, 407 std::string(), 408 new base::FundamentalValue(CONTENT_SETTING_ALLOW)); 409 EXPECT_EQ(CONTENT_SETTING_ALLOW, 410 GetContentSetting( 411 &provider, 412 primary_url, 413 secondary_url, 414 CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, 415 std::string(), 416 false)); 417 provider.ShutdownOnUIThread(); 418} 419 420// http://crosbug.com/17760 421TEST_F(PrefProviderTest, Deadlock) { 422 TestingPrefServiceSyncable prefs; 423 PrefProvider::RegisterProfilePrefs(prefs.registry()); 424 425 // Chain of events: a preference changes, |PrefProvider| notices it, and reads 426 // and writes the preference. When the preference is written, a notification 427 // is sent, and this used to happen when |PrefProvider| was still holding its 428 // lock. 429 430 PrefProvider provider(&prefs, false); 431 DeadlockCheckerObserver observer(&prefs, &provider); 432 { 433 DictionaryPrefUpdate update(&prefs, 434 prefs::kContentSettingsPatternPairs); 435 base::DictionaryValue* mutable_settings = update.Get(); 436 mutable_settings->SetWithoutPathExpansion("www.example.com,*", 437 new base::DictionaryValue()); 438 } 439 EXPECT_TRUE(observer.notification_received()); 440 441 provider.ShutdownOnUIThread(); 442} 443 444TEST_F(PrefProviderTest, LastUsage) { 445 TestingProfile testing_profile; 446 PrefProvider pref_content_settings_provider(testing_profile.GetPrefs(), 447 false); 448 base::SimpleTestClock* test_clock = new base::SimpleTestClock; 449 test_clock->SetNow(base::Time::Now()); 450 451 pref_content_settings_provider.SetClockForTesting( 452 scoped_ptr<base::Clock>(test_clock)); 453 GURL host("http://example.com/"); 454 ContentSettingsPattern pattern = 455 ContentSettingsPattern::FromString("[*.]example.com"); 456 457 base::Time no_usage = pref_content_settings_provider.GetLastUsage( 458 pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION); 459 EXPECT_EQ(no_usage.ToDoubleT(), 0); 460 461 pref_content_settings_provider.UpdateLastUsage( 462 pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION); 463 base::Time first = pref_content_settings_provider.GetLastUsage( 464 pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION); 465 466 test_clock->Advance(base::TimeDelta::FromSeconds(10)); 467 468 pref_content_settings_provider.UpdateLastUsage( 469 pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION); 470 base::Time second = pref_content_settings_provider.GetLastUsage( 471 pattern, pattern, CONTENT_SETTINGS_TYPE_GEOLOCATION); 472 473 base::TimeDelta delta = second - first; 474 EXPECT_EQ(delta.InSeconds(), 10); 475 476 pref_content_settings_provider.ShutdownOnUIThread(); 477} 478 479} // namespace content_settings 480