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