summaryrefslogtreecommitdiffstats
path: root/chrome/browser/privacy_blacklist
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/privacy_blacklist')
-rw-r--r--chrome/browser/privacy_blacklist/blacklist_manager.cc189
-rw-r--r--chrome/browser/privacy_blacklist/blacklist_manager.h96
-rw-r--r--chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc280
3 files changed, 565 insertions, 0 deletions
diff --git a/chrome/browser/privacy_blacklist/blacklist_manager.cc b/chrome/browser/privacy_blacklist/blacklist_manager.cc
new file mode 100644
index 0000000..4cad97b
--- /dev/null
+++ b/chrome/browser/privacy_blacklist/blacklist_manager.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/privacy_blacklist/blacklist_manager.h"
+
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "base/thread.h"
+#include "chrome/browser/privacy_blacklist/blacklist.h"
+#include "chrome/browser/privacy_blacklist/blacklist_io.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+// Base class for tasks that use BlacklistManager. It ensures that the
+// BlacklistManager won't get destroyed while we need it, and that it
+// will be destroyed always on the same thread. That's why we use
+// a custom Task instead of just NewRunnableMethod.
+class BlacklistManagerTask : public Task {
+ public:
+ explicit BlacklistManagerTask(BlacklistManager* manager)
+ : manager_(manager),
+ original_loop_(MessageLoop::current()) {
+ DCHECK(original_loop_);
+ manager->AddRef();
+ }
+
+ ~BlacklistManagerTask() {
+ original_loop_->ReleaseSoon(FROM_HERE, manager_);
+ }
+
+ protected:
+ BlacklistManager* blacklist_manager() const { return manager_; }
+
+ private:
+ BlacklistManager* manager_;
+
+ MessageLoop* original_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlacklistManagerTask);
+};
+
+BlacklistPathProvider::~BlacklistPathProvider() {
+}
+
+class BlacklistManager::CompileBlacklistTask : public BlacklistManagerTask {
+ public:
+ CompileBlacklistTask(BlacklistManager* manager,
+ const FilePath& destination_blacklist,
+ const std::vector<FilePath>& source_blacklists)
+ : BlacklistManagerTask(manager),
+ destination_blacklist_(destination_blacklist),
+ source_blacklists_(source_blacklists) {
+ }
+
+ virtual void Run() {
+ BlacklistIO io;
+ bool success = true;
+
+ for (std::vector<FilePath>::const_iterator i = source_blacklists_.begin();
+ i != source_blacklists_.end(); ++i) {
+ if (!io.Read(*i)) {
+ success = false;
+ break;
+ }
+ }
+
+ // Only overwrite the current compiled blacklist if we read all source
+ // files successfully.
+ if (success)
+ success = io.Write(destination_blacklist_);
+
+ blacklist_manager()->OnBlacklistCompilationFinished(success);
+ }
+
+ private:
+ FilePath destination_blacklist_;
+
+ std::vector<FilePath> source_blacklists_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompileBlacklistTask);
+};
+
+class BlacklistManager::ReadBlacklistTask : public BlacklistManagerTask {
+ public:
+ ReadBlacklistTask(BlacklistManager* manager, const FilePath& blacklist_path)
+ : BlacklistManagerTask(manager),
+ blacklist_path_(blacklist_path) {
+ }
+
+ virtual void Run() {
+ Blacklist* blacklist = new Blacklist(blacklist_path_);
+ blacklist_manager()->OnBlacklistReadFinished(blacklist);
+ }
+
+ private:
+ FilePath blacklist_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadBlacklistTask);
+};
+
+BlacklistManager::BlacklistManager(Profile* profile,
+ base::Thread* backend_thread)
+ : compiled_blacklist_path_(
+ profile->GetPath().Append(chrome::kPrivacyBlacklistFileName)),
+ compiling_blacklist_(false),
+ backend_thread_(backend_thread) {
+ registrar_.Add(this,
+ NotificationType::PRIVACY_BLACKLIST_PATH_PROVIDER_UPDATED,
+ Source<Profile>(profile));
+ ReadBlacklist();
+}
+
+void BlacklistManager::RegisterBlacklistPathProvider(
+ BlacklistPathProvider* provider) {
+ DCHECK(providers_.find(provider) == providers_.end());
+ providers_.insert(provider);
+}
+
+void BlacklistManager::UnregisterBlacklistPathProvider(
+ BlacklistPathProvider* provider) {
+ DCHECK(providers_.find(provider) != providers_.end());
+ providers_.erase(provider);
+}
+
+void BlacklistManager::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::PRIVACY_BLACKLIST_PATH_PROVIDER_UPDATED);
+ CompileBlacklist();
+}
+
+void BlacklistManager::CompileBlacklist() {
+ if (compiling_blacklist_) {
+ // If we end up here, that means that initial compile succeeded,
+ // but then we couldn't read back the resulting Blacklist. Return early
+ // to avoid a potential infinite loop.
+ // TODO(phajdan.jr): Report the error.
+ compiling_blacklist_ = false;
+ return;
+ }
+
+ compiling_blacklist_ = true;
+
+ std::vector<FilePath> source_blacklists;
+
+ for (ProvidersSet::iterator provider = providers_.begin();
+ provider != providers_.end(); ++provider) {
+ std::vector<FilePath> provided_paths((*provider)->GetBlacklistPaths());
+ source_blacklists.insert(source_blacklists.end(),
+ provided_paths.begin(), provided_paths.end());
+ }
+
+ RunTaskOnBackendThread(new CompileBlacklistTask(this, compiled_blacklist_path_,
+ source_blacklists));
+}
+
+void BlacklistManager::ReadBlacklist() {
+ RunTaskOnBackendThread(new ReadBlacklistTask(this, compiled_blacklist_path_));
+}
+
+void BlacklistManager::OnBlacklistCompilationFinished(bool success) {
+ if (success) {
+ ReadBlacklist();
+ } else {
+ // TODO(phajdan.jr): Report the error.
+ }
+}
+
+void BlacklistManager::OnBlacklistReadFinished(Blacklist* blacklist) {
+ if (blacklist->is_good()) {
+ compiled_blacklist_.reset(blacklist);
+ compiling_blacklist_ = false;
+ } else {
+ delete blacklist;
+ CompileBlacklist();
+ }
+}
+
+void BlacklistManager::RunTaskOnBackendThread(Task* task) {
+ if (backend_thread_) {
+ backend_thread_->message_loop()->PostTask(FROM_HERE, task);
+ } else {
+ task->Run();
+ delete task;
+ }
+}
diff --git a/chrome/browser/privacy_blacklist/blacklist_manager.h b/chrome/browser/privacy_blacklist/blacklist_manager.h
new file mode 100644
index 0000000..35cf37f
--- /dev/null
+++ b/chrome/browser/privacy_blacklist/blacklist_manager.h
@@ -0,0 +1,96 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_MANAGER_H_
+#define CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_MANAGER_H_
+
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/non_thread_safe.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/notification_registrar.h"
+
+class Blacklist;
+class MessageLoop;
+class Profile;
+class Task;
+
+namespace base {
+class Thread;
+}
+
+class BlacklistPathProvider {
+ public:
+ virtual ~BlacklistPathProvider();
+
+ virtual std::vector<FilePath> GetBlacklistPaths() = 0;
+};
+
+// Updates one compiled binary blacklist based on a list of plaintext
+// blacklists.
+class BlacklistManager : public base::RefCountedThreadSafe<BlacklistManager>,
+ public NotificationObserver,
+ public NonThreadSafe {
+ public:
+ // You must create and destroy BlacklistManager on the same thread.
+ BlacklistManager(Profile* profile, base::Thread* backend_thread);
+
+ void RegisterBlacklistPathProvider(BlacklistPathProvider* provider);
+ void UnregisterBlacklistPathProvider(BlacklistPathProvider* provider);
+
+ const Blacklist* GetCompiledBlacklist() const {
+ return compiled_blacklist_.get();
+ }
+
+ // NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+#ifdef UNIT_TEST
+ const FilePath& compiled_blacklist_path() { return compiled_blacklist_path_; }
+#endif // UNIT_TEST
+
+ private:
+ class CompileBlacklistTask;
+ class ReadBlacklistTask;
+
+ typedef std::set<BlacklistPathProvider*> ProvidersSet;
+
+ void CompileBlacklist();
+ void ReadBlacklist();
+
+ void OnBlacklistCompilationFinished(bool success);
+ void OnBlacklistReadFinished(Blacklist* blacklist);
+
+ void RunTaskOnBackendThread(Task* task);
+
+ // Path where we store the compiled blacklist.
+ FilePath compiled_blacklist_path_;
+
+ // Keep the compiled blacklist object in memory.
+ scoped_ptr<Blacklist> compiled_blacklist_;
+
+ // If true, then we started compiling a blacklist and haven't yet finished
+ // successfully. This helps prevent an infinite loop in case of multiple
+ // I/O errors.
+ bool compiling_blacklist_;
+
+ // Registered blacklist paths providers.
+ ProvidersSet providers_;
+
+ // Backend thread we will execute I/O operations on (NULL means no separate
+ // thread).
+ base::Thread* backend_thread_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlacklistManager);
+};
+
+#endif // CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_MANAGER_H_
diff --git a/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc b/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc
new file mode 100644
index 0000000..995184f57
--- /dev/null
+++ b/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc
@@ -0,0 +1,280 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/privacy_blacklist/blacklist_manager.h"
+
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
+#include "base/thread.h"
+#include "chrome/browser/privacy_blacklist/blacklist.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MyTestingProfile : public TestingProfile {
+ public:
+ MyTestingProfile() {
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+ path_ = temp_dir_.path();
+ }
+
+ private:
+ ScopedTempDir temp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(MyTestingProfile);
+};
+
+class TestBlacklistPathProvider : public BlacklistPathProvider {
+ public:
+ explicit TestBlacklistPathProvider(Profile* profile) : profile_(profile) {
+ }
+
+ virtual std::vector<FilePath> GetBlacklistPaths() {
+ return paths_;
+ }
+
+ void AddPath(const FilePath& path) {
+ paths_.push_back(path);
+ NotificationService::current()->Notify(
+ NotificationType::PRIVACY_BLACKLIST_PATH_PROVIDER_UPDATED,
+ Source<Profile>(profile_),
+ Details<BlacklistPathProvider>(this));
+ }
+
+ private:
+ Profile* profile_;
+
+ std::vector<FilePath> paths_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestBlacklistPathProvider);
+};
+
+class BlacklistManagerTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_));
+ test_data_dir_ = test_data_dir_.AppendASCII("blacklist_samples");
+ }
+
+ virtual void TearDown() {
+ loop_.RunAllPending();
+ }
+
+ protected:
+ FilePath test_data_dir_;
+
+ MyTestingProfile profile_;
+
+ private:
+ MessageLoop loop_;
+};
+
+TEST_F(BlacklistManagerTest, Basic) {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ const Blacklist* blacklist = manager->GetCompiledBlacklist();
+
+ // We should get an empty, but valid object.
+ ASSERT_TRUE(blacklist);
+ EXPECT_TRUE(blacklist->is_good());
+
+ // Repeated invocations of GetCompiledBlacklist should return the same object.
+ EXPECT_EQ(blacklist, manager->GetCompiledBlacklist());
+}
+
+TEST_F(BlacklistManagerTest, BlacklistPathProvider) {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ const Blacklist* blacklist1 = manager->GetCompiledBlacklist();
+ EXPECT_FALSE(blacklist1->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+
+ TestBlacklistPathProvider provider(&profile_);
+ manager->RegisterBlacklistPathProvider(&provider);
+
+ // Blacklist should not get recompiled.
+ EXPECT_EQ(blacklist1, manager->GetCompiledBlacklist());
+
+ provider.AddPath(test_data_dir_.AppendASCII("annoying_ads.pbl"));
+
+ const Blacklist* blacklist2 = manager->GetCompiledBlacklist();
+
+ // Added a real blacklist, the manager should recompile.
+ EXPECT_NE(blacklist1, blacklist2);
+ EXPECT_TRUE(blacklist2->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+
+ manager->UnregisterBlacklistPathProvider(&provider);
+
+ // Just unregistering the provider doesn't remove the blacklist paths
+ // from the manager.
+ EXPECT_EQ(blacklist2, manager->GetCompiledBlacklist());
+}
+
+TEST_F(BlacklistManagerTest, RealThread) {
+ base::Thread backend_thread("backend_thread");
+ backend_thread.Start();
+
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, &backend_thread));
+
+ // Make sure all pending tasks run.
+ backend_thread.Stop();
+ backend_thread.Start();
+
+ const Blacklist* blacklist1 = manager->GetCompiledBlacklist();
+ EXPECT_FALSE(blacklist1->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+
+ TestBlacklistPathProvider provider(&profile_);
+ manager->RegisterBlacklistPathProvider(&provider);
+
+ // Make sure all pending tasks run.
+ backend_thread.Stop();
+ backend_thread.Start();
+
+ // Blacklist should not get recompiled.
+ EXPECT_EQ(blacklist1, manager->GetCompiledBlacklist());
+
+ provider.AddPath(test_data_dir_.AppendASCII("annoying_ads.pbl"));
+
+ // Make sure all pending tasks run.
+ backend_thread.Stop();
+ backend_thread.Start();
+
+ const Blacklist* blacklist2 = manager->GetCompiledBlacklist();
+
+ // Added a real blacklist, the manager should recompile.
+ EXPECT_NE(blacklist1, blacklist2);
+ EXPECT_TRUE(blacklist2->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+
+ manager->UnregisterBlacklistPathProvider(&provider);
+
+ // Make sure all pending tasks run.
+ backend_thread.Stop();
+ backend_thread.Start();
+
+ // Just unregistering the provider doesn't remove the blacklist paths
+ // from the manager.
+ EXPECT_EQ(blacklist2, manager->GetCompiledBlacklist());
+}
+
+TEST_F(BlacklistManagerTest, CompiledBlacklistStaysOnDisk) {
+ {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ TestBlacklistPathProvider provider(&profile_);
+ manager->RegisterBlacklistPathProvider(&provider);
+ provider.AddPath(test_data_dir_.AppendASCII("annoying_ads.pbl"));
+ const Blacklist* blacklist = manager->GetCompiledBlacklist();
+ EXPECT_TRUE(blacklist->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+ manager->UnregisterBlacklistPathProvider(&provider);
+ }
+
+ {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ // Make sure we read the compiled blacklist from disk and don't even touch
+ // the paths providers.
+ const Blacklist* blacklist = manager->GetCompiledBlacklist();
+ EXPECT_TRUE(blacklist->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+ }
+}
+
+TEST_F(BlacklistManagerTest, BlacklistPathReadError) {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ TestBlacklistPathProvider provider(&profile_);
+ manager->RegisterBlacklistPathProvider(&provider);
+
+ FilePath bogus_path(test_data_dir_.AppendASCII("does_not_exist_randomness"));
+ ASSERT_FALSE(file_util::PathExists(bogus_path));
+ provider.AddPath(bogus_path);
+
+ const Blacklist* blacklist = manager->GetCompiledBlacklist();
+
+ // We should get an empty, but valid object.
+ ASSERT_TRUE(blacklist);
+ EXPECT_TRUE(blacklist->is_good());
+
+ manager->UnregisterBlacklistPathProvider(&provider);
+}
+
+TEST_F(BlacklistManagerTest, CompiledBlacklistReadError) {
+ FilePath compiled_blacklist_path;
+
+ {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ TestBlacklistPathProvider provider(&profile_);
+ manager->RegisterBlacklistPathProvider(&provider);
+ provider.AddPath(test_data_dir_.AppendASCII("annoying_ads.pbl"));
+ const Blacklist* blacklist = manager->GetCompiledBlacklist();
+ EXPECT_TRUE(blacklist->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+ manager->UnregisterBlacklistPathProvider(&provider);
+
+ compiled_blacklist_path = manager->compiled_blacklist_path();
+ }
+
+ ASSERT_TRUE(file_util::PathExists(compiled_blacklist_path));
+ ASSERT_TRUE(file_util::Delete(compiled_blacklist_path, false));
+
+ {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ // Now we don't have any providers, and no compiled blacklist file. We
+ // shouldn't match any URLs.
+ const Blacklist* blacklist = manager->GetCompiledBlacklist();
+ EXPECT_FALSE(blacklist->findMatch(GURL("http://host/annoying_ads/ad.jpg")));
+ }
+}
+
+TEST_F(BlacklistManagerTest, MultipleProviders) {
+ scoped_refptr<BlacklistManager> manager(
+ new BlacklistManager(&profile_, NULL));
+
+ TestBlacklistPathProvider provider1(&profile_);
+ TestBlacklistPathProvider provider2(&profile_);
+ manager->RegisterBlacklistPathProvider(&provider1);
+ manager->RegisterBlacklistPathProvider(&provider2);
+
+ const Blacklist* blacklist1 = manager->GetCompiledBlacklist();
+ EXPECT_FALSE(blacklist1->findMatch(GURL("http://sample/annoying_ads/a.jpg")));
+ EXPECT_FALSE(blacklist1->findMatch(GURL("http://sample/other_ads/a.jpg")));
+ EXPECT_FALSE(blacklist1->findMatch(GURL("http://host/something.doc")));
+
+ provider1.AddPath(test_data_dir_.AppendASCII("annoying_ads.pbl"));
+ const Blacklist* blacklist2 = manager->GetCompiledBlacklist();
+ EXPECT_NE(blacklist1, blacklist2);
+
+ provider2.AddPath(test_data_dir_.AppendASCII("host.pbl"));
+ const Blacklist* blacklist3 = manager->GetCompiledBlacklist();
+ EXPECT_NE(blacklist2, blacklist3);
+
+ EXPECT_TRUE(blacklist3->findMatch(GURL("http://sample/annoying_ads/a.jpg")));
+ EXPECT_FALSE(blacklist3->findMatch(GURL("http://sample/other_ads/a.jpg")));
+ EXPECT_TRUE(blacklist3->findMatch(GURL("http://host/something.doc")));
+
+ provider1.AddPath(test_data_dir_.AppendASCII("other_ads.pbl"));
+
+ const Blacklist* blacklist4 = manager->GetCompiledBlacklist();
+
+ EXPECT_NE(blacklist3, blacklist4);
+ EXPECT_TRUE(blacklist4->findMatch(GURL("http://sample/annoying_ads/a.jpg")));
+ EXPECT_TRUE(blacklist4->findMatch(GURL("http://sample/other_ads/a.jpg")));
+ EXPECT_TRUE(blacklist4->findMatch(GURL("http://host/something.doc")));
+
+ manager->UnregisterBlacklistPathProvider(&provider1);
+ manager->UnregisterBlacklistPathProvider(&provider2);
+}
+
+} // namespace