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