diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-05 18:14:49 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-05 18:14:49 +0000 |
commit | 363119947a1e9111c19c326a2844bc60a29fabba (patch) | |
tree | a008f948a2591ffec99b7b25040d6c74815b6a01 /chrome/browser/privacy_blacklist | |
parent | 4f67d8a72d73ca17ae35434e3301e708fddd2970 (diff) | |
download | chromium_src-363119947a1e9111c19c326a2844bc60a29fabba.zip chromium_src-363119947a1e9111c19c326a2844bc60a29fabba.tar.gz chromium_src-363119947a1e9111c19c326a2844bc60a29fabba.tar.bz2 |
Implement delaying resource requests until privacy blacklists are ready.
Associate a BlacklistRequestInfo with each URLRequest started by ResourceDispatcherHost so that in various places we get access to the right BlacklistManager (each Profile has its own), and lazily cache a Blacklist::Match.
BlacklistListener controls delaying requests until the privacy blacklist is ready for the request.
BlacklistInterceptor handles substituting real response with a blocking page or blocking image. I've temporarily removed support for unblocking things. It was too hacky.
This change also removes a large block of blacklist-related code from RDH to more focused classes. Should make it a little more readable.
This should also make BlacklistManagerBrowserTest not flaky.
TEST=Covered by browser_tests and unit_tests.
BUG=21541, 29113
Review URL: http://codereview.chromium.org/501082
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35538 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/privacy_blacklist')
19 files changed, 912 insertions, 328 deletions
diff --git a/chrome/browser/privacy_blacklist/blacklist.cc b/chrome/browser/privacy_blacklist/blacklist.cc index bbb8a38..1bec742 100644 --- a/chrome/browser/privacy_blacklist/blacklist.cc +++ b/chrome/browser/privacy_blacklist/blacklist.cc @@ -40,9 +40,6 @@ const unsigned int Blacklist::kModifyReceivedHeaders = const unsigned int Blacklist::kFilterByHeaders = kModifyReceivedHeaders | kBlockByType; -// Value is not important, here just that the object has an address. -const void* const Blacklist::kRequestDataKey = 0; - unsigned int Blacklist::String2Attribute(const std::string& s) { if (s == STRINGIZE(kBlockAll)) return kBlockAll; diff --git a/chrome/browser/privacy_blacklist/blacklist.h b/chrome/browser/privacy_blacklist/blacklist.h index 1999a09..2fba5fb 100644 --- a/chrome/browser/privacy_blacklist/blacklist.h +++ b/chrome/browser/privacy_blacklist/blacklist.h @@ -49,9 +49,6 @@ class Blacklist { static const unsigned int kModifyReceivedHeaders; static const unsigned int kFilterByHeaders; - // Key used to access data attached to URLRequest objects. - static const void* const kRequestDataKey; - // Converts a stringized filter attribute (see above) back to its integer // value. Returns 0 on error. static unsigned int String2Attribute(const std::string&); diff --git a/chrome/browser/privacy_blacklist/blacklist_interceptor.cc b/chrome/browser/privacy_blacklist/blacklist_interceptor.cc new file mode 100644 index 0000000..79c47fb --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_interceptor.cc @@ -0,0 +1,141 @@ +// 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_interceptor.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/privacy_blacklist/blacklist.h" +#include "chrome/browser/privacy_blacklist/blacklist_manager.h" +#include "chrome/browser/privacy_blacklist/blacklist_request_info.h" +#include "chrome/common/jstemplate_builder.h" +#include "net/url_request/url_request_simple_job.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" + +namespace { + +class URLRequestBlacklistJob : public URLRequestSimpleJob { + public: + URLRequestBlacklistJob(URLRequest* request, + const BlacklistRequestInfo& request_info) + : URLRequestSimpleJob(request), + request_info_(request_info) { + } + + virtual bool GetData(std::string* mime_type, + std::string* charset, + std::string* data) const { + if (ResourceType::IsFrame(request_info_.resource_type())) { + *mime_type = "text/html"; + *charset = "utf-8"; + *data = GetHTMLResponse(); + } else { + // TODO(phajdan.jr): For some resources (like script) we may want to + // simulate an error instead or return other MIME type. + *mime_type = "image/png"; + *data = GetImageResponse(); + } + return true; + } + + private: + std::string GetHTMLResponse() const { + return "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html;charset=utf-8\r\n" + "Cache-Control: no-store\r\n\r\n" + GetHTML(); + } + + static std::string GetImageResponse() { + return "HTTP/1.1 200 OK\r\n" + "Content-Type: image/png\r\n" + "Cache-Control: no-store\r\n\r\n" + GetImage(); + } + + static std::string GetImage() { + return ResourceBundle::GetSharedInstance(). + GetDataResource(IDR_BLACKLIST_IMAGE); + } + + std::string GetHTML() const { + DictionaryValue strings; + strings.SetString(L"title", l10n_util::GetString(IDS_BLACKLIST_TITLE)); + strings.SetString(L"message", l10n_util::GetString(IDS_BLACKLIST_MESSAGE)); + + const Blacklist::Provider* provider = GetBestMatchingEntryProvider(); + strings.SetString(L"name", provider->name()); + strings.SetString(L"url", provider->url()); + + const base::StringPiece html = + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_BLACKLIST_HTML); + return jstemplate_builder::GetI18nTemplateHtml(html, &strings); + } + + const Blacklist::Provider* GetBestMatchingEntryProvider() const { + // If kBlockAll is specified, assign blame to such an entry. + // Otherwise pick the first one. + const BlacklistManager* blacklist_manager = + request_info_.GetBlacklistManager(); + const Blacklist* blacklist = blacklist_manager->GetCompiledBlacklist(); + scoped_ptr<Blacklist::Match> match(blacklist->findMatch(request_->url())); + const Blacklist::Entry* entry = NULL; + if (match->attributes() & Blacklist::kBlockAll) { + for (std::vector<const Blacklist::Entry*>::const_iterator i = + match->entries().begin(); i != match->entries().end(); ++i) { + if ((*i)->attributes() == Blacklist::kBlockAll) { + entry = *i; + break; + } + } + } else { + entry = match->entries().front(); + } + return entry->provider(); + } + + const BlacklistRequestInfo& request_info_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestBlacklistJob); +}; + +} // namespace + +BlacklistInterceptor::BlacklistInterceptor() { + URLRequest::RegisterRequestInterceptor(this); +} + +BlacklistInterceptor::~BlacklistInterceptor() { + URLRequest::UnregisterRequestInterceptor(this); +} + +URLRequestJob* BlacklistInterceptor::MaybeIntercept(URLRequest* request) { + BlacklistRequestInfo* request_info = + BlacklistRequestInfo::FromURLRequest(request); + if (!request_info) { + // Not all requests have privacy blacklist data, for example downloads. + return NULL; + } + + const BlacklistManager* blacklist_manager = + request_info->GetBlacklistManager(); + const Blacklist* blacklist = blacklist_manager->GetCompiledBlacklist(); + scoped_ptr<Blacklist::Match> match(blacklist->findMatch(request->url())); + + if (!match.get()) { + // Nothing is blacklisted for this request. Do not intercept. + return NULL; + } + + // TODO(phajdan.jr): Should we have some UI to notify about blocked referrer? + if (match->attributes() & Blacklist::kDontSendReferrer) + request->set_referrer(std::string()); + + if (match->IsBlocked(request->url())) + return new URLRequestBlacklistJob(request, *request_info); + + return NULL; +} diff --git a/chrome/browser/privacy_blacklist/blacklist_interceptor.h b/chrome/browser/privacy_blacklist/blacklist_interceptor.h new file mode 100644 index 0000000..308ce9c --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_interceptor.h @@ -0,0 +1,23 @@ +// 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_INTERCEPTOR_H_ +#define CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_INTERCEPTOR_H_ + +#include "net/url_request/url_request.h" + +// Intercepts requests matched by a privacy blacklist. +class BlacklistInterceptor : public URLRequest::Interceptor { + public: + BlacklistInterceptor(); + ~BlacklistInterceptor(); + + // URLRequest::Interceptor: + virtual URLRequestJob* MaybeIntercept(URLRequest* request); + + private: + DISALLOW_COPY_AND_ASSIGN(BlacklistInterceptor); +}; + +#endif // CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_INTERCEPTOR_H_ diff --git a/chrome/browser/privacy_blacklist/blacklist_interceptor_unittest.cc b/chrome/browser/privacy_blacklist/blacklist_interceptor_unittest.cc new file mode 100644 index 0000000..f1cadcf --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_interceptor_unittest.cc @@ -0,0 +1,94 @@ +// 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 "app/l10n_util.h" +#include "base/message_loop.h" +#include "base/path_service.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/privacy_blacklist/blacklist_interceptor.h" +#include "chrome/browser/privacy_blacklist/blacklist_manager.h" +#include "chrome/browser/privacy_blacklist/blacklist_request_info.h" +#include "chrome/browser/privacy_blacklist/blacklist_test_util.h" +#include "chrome/common/chrome_paths.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" +#include "net/base/io_buffer.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_status.h" +#include "net/url_request/url_request_unittest.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char kDataUrl[] = "data:text/plain,Hello World!"; +const char kBlockedUrl[] = "http://example.com/annoying_ads/ad.jpg"; + +class BlacklistInterceptorTest : public testing::Test { + public: + BlacklistInterceptorTest() + : loop_(MessageLoop::TYPE_IO), + ui_thread_(ChromeThread::UI, &loop_), + file_thread_(ChromeThread::FILE, &loop_), + io_thread_(ChromeThread::IO, &loop_) { + } + + virtual void SetUp() { + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_)); + test_data_dir_ = test_data_dir_.AppendASCII("blacklist_samples"); + } + + protected: + bool InterceptedTestRequest(const std::string& url, + BlacklistRequestInfo* request_info) { + TestDelegate delegate; + TestURLRequest request(GURL(url), &delegate); + request.SetUserData(&BlacklistRequestInfo::kURLRequestDataKey, + request_info); + request.Start(); + MessageLoop::current()->Run(); + + std::string response(delegate.data_received()); + return (ContainsResourceString(response, IDS_BLACKLIST_TITLE) && + ContainsResourceString(response, IDS_BLACKLIST_MESSAGE)); + } + + BlacklistInterceptor interceptor_; + + FilePath test_data_dir_; + + private: + bool ContainsResourceString(const std::string& text, int string_id) { + return text.find(l10n_util::GetStringUTF8(string_id)) != std::string::npos; + } + + MessageLoop loop_; + + ChromeThread ui_thread_; + ChromeThread file_thread_; + ChromeThread io_thread_; +}; + +TEST_F(BlacklistInterceptorTest, Basic) { + EXPECT_FALSE(InterceptedTestRequest(kDataUrl, NULL)); +} + +TEST_F(BlacklistInterceptorTest, Intercepted) { + BlacklistTestingProfile profile; + TestBlacklistPathProvider path_provider(&profile); + path_provider.AddTransientPath( + test_data_dir_.AppendASCII("annoying_ads.pbl")); + scoped_refptr<BlacklistManager> blacklist_manager( + new BlacklistManager(&profile, &path_provider)); + blacklist_manager->Initialize(); + MessageLoop::current()->RunAllPending(); + + EXPECT_FALSE(InterceptedTestRequest(kDataUrl, NULL)); + + BlacklistRequestInfo* request_info = + new BlacklistRequestInfo(GURL(kBlockedUrl), ResourceType::MAIN_FRAME, + blacklist_manager.get()); + EXPECT_TRUE(InterceptedTestRequest(kBlockedUrl, request_info)); +} + +} // namespace diff --git a/chrome/browser/privacy_blacklist/blacklist_listener.cc b/chrome/browser/privacy_blacklist/blacklist_listener.cc new file mode 100644 index 0000000..5e00236 --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_listener.cc @@ -0,0 +1,92 @@ +// 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_listener.h" + +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/privacy_blacklist/blacklist.h" +#include "chrome/browser/privacy_blacklist/blacklist_manager.h" +#include "chrome/browser/privacy_blacklist/blacklist_request_info.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/renderer_host/global_request_id.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" +#include "net/url_request/url_request.h" + +BlacklistListener::BlacklistListener(ResourceQueue* resource_queue) + : resource_queue_(resource_queue) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + registrar_.Add(this, + NotificationType::BLACKLIST_MANAGER_ERROR, + NotificationService::AllSources()); + registrar_.Add(this, + NotificationType::BLACKLIST_MANAGER_BLACKLIST_READ_FINISHED, + NotificationService::AllSources()); +} + +BlacklistListener::~BlacklistListener() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); +} + +void BlacklistListener::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + switch (type.value) { + // TODO(phajdan.jr): Do not resume requests silently after an error. + case NotificationType::BLACKLIST_MANAGER_ERROR: + case NotificationType::BLACKLIST_MANAGER_BLACKLIST_READ_FINISHED: + { + Profile* profile = Source<Profile>(source).ptr(); + ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &BlacklistListener::StartDelayedRequests, + profile->GetBlacklistManager())); + } + break; + default: + NOTREACHED(); + } +} + +bool BlacklistListener::ShouldDelayRequest( + URLRequest* request, + const ResourceDispatcherHostRequestInfo& request_info, + const GlobalRequestID& request_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + + BlacklistRequestInfo* blacklist_request_info = + BlacklistRequestInfo::FromURLRequest(request); + const BlacklistManager* blacklist_manager = + blacklist_request_info->GetBlacklistManager(); + + if (blacklist_manager->GetCompiledBlacklist()) { + // We have a blacklist ready. No need to delay the request. + return false; + } + + delayed_requests_[blacklist_manager].push_back(request_id); + return true; +} + +void BlacklistListener::WillShutdownResourceQueue() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + resource_queue_ = NULL; +} + +void BlacklistListener::StartDelayedRequests( + BlacklistManager* blacklist_manager) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + + if (resource_queue_) { + const RequestList& requests = delayed_requests_[blacklist_manager]; + for (RequestList::const_iterator i = requests.begin(); + i != requests.end(); ++i) { + resource_queue_->StartDelayedRequest(this, *i); + } + } + + delayed_requests_[blacklist_manager].clear(); +} diff --git a/chrome/browser/privacy_blacklist/blacklist_listener.h b/chrome/browser/privacy_blacklist/blacklist_listener.h new file mode 100644 index 0000000..a74ed8e --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_listener.h @@ -0,0 +1,68 @@ +// 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_LISTENER_H_ +#define CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_LISTENER_H_ + +#include <map> +#include <vector> + +#include "base/ref_counted.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/renderer_host/resource_queue.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class BlacklistManager; + +// Delays requests until privacy blacklists are ready. +class BlacklistListener + : public ResourceQueueDelegate, + public NotificationObserver, + public base::RefCountedThreadSafe<BlacklistListener, + ChromeThread::DeleteOnUIThread> { + public: + // UI THREAD ONLY ------------------------------------------------------------ + + explicit BlacklistListener(ResourceQueue* resource_queue); + virtual ~BlacklistListener(); + + // NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // IO THREAD ONLY ------------------------------------------------------------ + + // ResourceQueueDelegate: + virtual bool ShouldDelayRequest( + URLRequest* request, + const ResourceDispatcherHostRequestInfo& request_info, + const GlobalRequestID& request_id); + virtual void WillShutdownResourceQueue(); + + private: + friend class ChromeThread; + friend class DeleteTask<BlacklistListener>; + + // Tell our resource queue to start the requests we requested to be delayed. + void StartDelayedRequests(BlacklistManager* blacklist_manager); + + // Resource queue we're delegate of. + ResourceQueue* resource_queue_; + + typedef std::vector<GlobalRequestID> RequestList; + typedef std::map<const BlacklistManager*, RequestList> DelayedRequestMap; + + // Keep track of requests we have requested to delay so that we can resume + // them as the blacklists load (note that we have a request list per blacklist + // manager). + DelayedRequestMap delayed_requests_; + + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(BlacklistListener); +}; + +#endif // CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_LISTENER_H_ diff --git a/chrome/browser/privacy_blacklist/blacklist_listener_unittest.cc b/chrome/browser/privacy_blacklist/blacklist_listener_unittest.cc new file mode 100644 index 0000000..0625009 --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_listener_unittest.cc @@ -0,0 +1,183 @@ +// 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_listener.h" + +#include "base/message_loop.h" +#include "base/thread.h" +#include "chrome/browser/privacy_blacklist/blacklist.h" +#include "chrome/browser/privacy_blacklist/blacklist_request_info.h" +#include "chrome/browser/privacy_blacklist/blacklist_test_util.h" +#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" +#include "chrome/browser/renderer_host/resource_handler.h" +#include "chrome/browser/renderer_host/resource_queue.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" +#include "net/url_request/url_request_unittest.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char kTestUrl[] = "data:text/plain,Hello World!"; + +// Dummy ResourceHandler required for ResourceDispatcherHostRequestInfo. +class DummyResourceHandler : public ResourceHandler { + public: + DummyResourceHandler() { + } + + virtual bool OnRequestRedirected(int request_id, const GURL& url, + ResourceResponse* response, + bool* defer) { + NOTREACHED(); + return true; + } + + virtual bool OnResponseStarted(int request_id, + ResourceResponse* response) { + NOTREACHED(); + return true; + } + + virtual bool OnWillRead(int request_id, + net::IOBuffer** buf, + int* buf_size, + int min_size) { + NOTREACHED(); + return true; + } + + virtual bool OnReadCompleted(int request_id, int* bytes_read) { + NOTREACHED(); + return true; + } + + virtual bool OnResponseCompleted(int request_id, + const URLRequestStatus& status, + const std::string& security_info) { + NOTREACHED(); + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(DummyResourceHandler); +}; + +ResourceDispatcherHostRequestInfo* GetRequestInfo(int request_id) { + return new ResourceDispatcherHostRequestInfo( + new DummyResourceHandler(), ChildProcessInfo::RENDER_PROCESS, 0, 0, + request_id, "null", "null", ResourceType::MAIN_FRAME, + 0, false, false, -1, -1); +} + +class BlacklistListenerTest + : public testing::Test, + public NotificationObserver { + public: + BlacklistListenerTest() + : path_provider_(&profile_), + loop_(MessageLoop::TYPE_IO), + mock_ui_thread_(ChromeThread::UI, MessageLoop::current()), + mock_file_thread_(ChromeThread::FILE, MessageLoop::current()), + mock_io_thread_(ChromeThread::IO, MessageLoop::current()) { + } + + virtual void SetUp() { + blacklist_manager_ = new BlacklistManager(&profile_, &path_provider_); + blacklist_listener_ = new BlacklistListener(&resource_queue_); + + profile_.set_blacklist_manager(blacklist_manager_.get()); + + ResourceQueue::DelegateSet delegates; + delegates.insert(blacklist_listener_.get()); + resource_queue_.Initialize(delegates); + } + + virtual void TearDown() { + resource_queue_.Shutdown(); + blacklist_listener_ = NULL; + blacklist_manager_ = NULL; + loop_.RunAllPending(); + } + + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + MessageLoop::current()->Quit(); + } + + protected: + void WaitForBlacklistUpdate() { + NotificationRegistrar registrar; + registrar.Add(this, + NotificationType::BLACKLIST_MANAGER_BLACKLIST_READ_FINISHED, + Source<Profile>(&profile_)); + MessageLoop::current()->Run(); + } + + TestURLRequest* StartTestRequest(URLRequest::Delegate* delegate) { + TestURLRequest* request = new TestURLRequest(GURL(kTestUrl), delegate); + BlacklistRequestInfo* request_info = + new BlacklistRequestInfo(request->url(), ResourceType::MAIN_FRAME, + blacklist_manager_.get()); + request->SetUserData(&BlacklistRequestInfo::kURLRequestDataKey, + request_info); + scoped_ptr<ResourceDispatcherHostRequestInfo> rdh_info(GetRequestInfo(0)); + resource_queue_.AddRequest(request, *rdh_info.get()); + return request; + } + + BlacklistTestingProfile profile_; + + TestBlacklistPathProvider path_provider_; + + scoped_refptr<BlacklistManager> blacklist_manager_; + + scoped_refptr<BlacklistListener> blacklist_listener_; + + private: + MessageLoop loop_; + + ChromeThread mock_ui_thread_; + ChromeThread mock_file_thread_; + ChromeThread mock_io_thread_; + + ResourceQueue resource_queue_; +}; + +TEST_F(BlacklistListenerTest, Delay) { + blacklist_manager_->Initialize(); + + TestDelegate delegate; + scoped_ptr<TestURLRequest> request(StartTestRequest(&delegate)); + + // The request should get delayed, because the BlacklistManager is not yet + // ready. When we run pending tasks, it should initialize itself, notify + // the BlacklistListener, and start the request. + ASSERT_FALSE(request->is_pending()); + + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("Hello World!", delegate.data_received()); +} + +TEST_F(BlacklistListenerTest, NoDelay) { + blacklist_manager_->Initialize(); + + // Make sure that the BlacklistManager is ready before we start the request. + WaitForBlacklistUpdate(); + + TestDelegate delegate; + scoped_ptr<TestURLRequest> request(StartTestRequest(&delegate)); + + // The request should be started immediately. + ASSERT_TRUE(request->is_pending()); + + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("Hello World!", delegate.data_received()); +} + +} // namespace diff --git a/chrome/browser/privacy_blacklist/blacklist_manager.cc b/chrome/browser/privacy_blacklist/blacklist_manager.cc index ca8dc0b..c2253ef 100644 --- a/chrome/browser/privacy_blacklist/blacklist_manager.cc +++ b/chrome/browser/privacy_blacklist/blacklist_manager.cc @@ -8,6 +8,7 @@ #include "base/string_util.h" #include "base/task.h" #include "base/thread.h" +#include "base/utf_string_conversions.h" #include "chrome/browser/privacy_blacklist/blacklist.h" #include "chrome/browser/privacy_blacklist/blacklist_io.h" #include "chrome/browser/profile.h" @@ -89,6 +90,14 @@ void BlacklistManager::CompileBlacklist() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); DCHECK(path_provider_->AreBlacklistPathsReady()); + // The compiled blacklist is going to change. Make sure our clients don't use + // the old one and wait for the update instead by indicating that the compiled + // blacklist is not ready. + ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &BlacklistManager::ResetPublishedCompiledBlacklist)); + + // Schedule actual compilation on the background thread. ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, NewRunnableMethod(this, &BlacklistManager::DoCompileBlacklist, path_provider_->GetPersistentBlacklistPaths())); @@ -98,22 +107,28 @@ void BlacklistManager::DoCompileBlacklist( const std::vector<FilePath>& source_blacklists) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - bool success = true; Blacklist blacklist; std::string error_string; + std::vector<string16> errors; for (std::vector<FilePath>::const_iterator i = source_blacklists.begin(); i != source_blacklists.end(); ++i) { + std::string error_string; if (!BlacklistIO::ReadText(&blacklist, *i, &error_string)) { - success = false; - break; + string16 path = WideToUTF16(i->ToWStringHack()); + errors.push_back(path + ASCIIToUTF16(": " + error_string)); } } - // Only overwrite the current compiled blacklist if we read all source - // files successfully. - if (success) - success = BlacklistIO::WriteBinary(&blacklist, compiled_blacklist_path_); + if (!errors.empty()) { + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &BlacklistManager::OnBlacklistCompilationReadErrors, + errors)); + } + // Write the new compiled blacklist based on the data we could read + // successfully. + bool success = BlacklistIO::WriteBinary(&blacklist, compiled_blacklist_path_); ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, NewRunnableMethod(this, &BlacklistManager::OnBlacklistCompilationFinished, success)); @@ -133,6 +148,21 @@ void BlacklistManager::OnBlacklistCompilationFinished(bool success) { } } +void BlacklistManager::OnBlacklistCompilationReadErrors( + const std::vector<string16>& errors) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + string16 error_message(ASCIIToUTF16("Blacklist compilation failed.\n")); + for (std::vector<string16>::const_iterator i = errors.begin(); + i != errors.end(); ++i) { + error_message += *i + ASCIIToUTF16("\n"); + } + NotificationService::current()->Notify( + NotificationType::BLACKLIST_MANAGER_ERROR, + Source<Profile>(profile_), + Details<string16>(&error_message)); +} + void BlacklistManager::ReadBlacklist() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); DCHECK(path_provider_->AreBlacklistPathsReady()); @@ -197,3 +227,8 @@ void BlacklistManager::OnBlacklistReadFinished(bool success) { } first_read_finished_ = true; } + +void BlacklistManager::ResetPublishedCompiledBlacklist() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + compiled_blacklist_.reset(); +} diff --git a/chrome/browser/privacy_blacklist/blacklist_manager.h b/chrome/browser/privacy_blacklist/blacklist_manager.h index 5d6e97b..1ababd6 100644 --- a/chrome/browser/privacy_blacklist/blacklist_manager.h +++ b/chrome/browser/privacy_blacklist/blacklist_manager.h @@ -70,6 +70,7 @@ class BlacklistManager // Compile all persistent blacklists to one binary blacklist stored on disk. void CompileBlacklist(); void DoCompileBlacklist(const std::vector<FilePath>& source_blacklists); + void OnBlacklistCompilationReadErrors(const std::vector<string16>& errors); void OnBlacklistCompilationFinished(bool success); // Read all blacklists from disk (the compiled one and also the transient @@ -80,6 +81,10 @@ class BlacklistManager void UpdatePublishedCompiledBlacklist(Blacklist* blacklist); void OnBlacklistReadFinished(bool success); + // Sets the |compiled_blacklist_| to NULL to indicate that the blacklist is + // not ready. + void ResetPublishedCompiledBlacklist(); + // True after the first blacklist read has finished (regardless of success). // Used to avoid an infinite loop. bool first_read_finished_; diff --git a/chrome/browser/privacy_blacklist/blacklist_manager_browsertest.cc b/chrome/browser/privacy_blacklist/blacklist_manager_browsertest.cc index 46bba29..8bbd8ac 100644 --- a/chrome/browser/privacy_blacklist/blacklist_manager_browsertest.cc +++ b/chrome/browser/privacy_blacklist/blacklist_manager_browsertest.cc @@ -4,6 +4,7 @@ #include "chrome/browser/privacy_blacklist/blacklist_manager.h" +#include "app/l10n_util.h" #include "base/command_line.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_process.h" @@ -13,10 +14,10 @@ #include "chrome/browser/privacy_blacklist/blacklist_manager.h" #include "chrome/browser/profile.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/notification_registrar.h" -#include "chrome/common/notification_source.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -45,34 +46,14 @@ class BlacklistManagerBrowserTest : public ExtensionBrowserTest { virtual void SetUpInProcessBrowserTestFixture() { ExtensionBrowserTest::SetUpInProcessBrowserTestFixture(); - received_blacklist_notification_ = false; host_resolver()->AddSimulatedFailure("www.example.com"); } - // NotificationObserver - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - if (type != NotificationType::BLACKLIST_MANAGER_ERROR && - type != NotificationType::BLACKLIST_MANAGER_BLACKLIST_READ_FINISHED) { - ExtensionBrowserTest::Observe(type, source, details); - return; - } - received_blacklist_notification_ = true; - MessageLoop::current()->Quit(); - } - protected: BlacklistManager* GetBlacklistManager() { return browser()->profile()->GetBlacklistManager(); } - bool GetAndResetReceivedBlacklistNotification() { - bool result = received_blacklist_notification_; - received_blacklist_notification_ = false; - return result; - } - bool BlacklistHasMatch(const std::string& url) { bool has_match = false; ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, @@ -83,30 +64,20 @@ class BlacklistManagerBrowserTest : public ExtensionBrowserTest { ui_test_utils::RunMessageLoop(); return has_match; } - - private: - bool received_blacklist_notification_; }; -IN_PROC_BROWSER_TEST_F(BlacklistManagerBrowserTest, FLAKY_Basic) { +IN_PROC_BROWSER_TEST_F(BlacklistManagerBrowserTest, Basic) { static const char kTestUrl[] = "http://www.example.com/annoying_ads/ad.jpg"; - NotificationRegistrar registrar; - registrar.Add(this, - NotificationType::BLACKLIST_MANAGER_BLACKLIST_READ_FINISHED, - Source<Profile>(browser()->profile())); - // Test loading an extension with blacklist. ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("common").AppendASCII("privacy_blacklist"))); - // Wait until the blacklist is loaded and ready. - if (!GetAndResetReceivedBlacklistNotification()) - ui_test_utils::RunMessageLoop(); - - // The blacklist should block our test URL. - EXPECT_TRUE(BlacklistHasMatch(kTestUrl)); - - // TODO(phajdan.jr): Verify that we really blocked the request etc. + // Navigate to a blacklisted URL. The request should be blocked. ui_test_utils::NavigateToURL(browser(), GURL(kTestUrl)); + string16 expected_title(l10n_util::GetStringUTF16(IDS_BLACKLIST_TITLE)); + string16 tab_title; + ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title)); + EXPECT_EQ(expected_title, tab_title); + EXPECT_TRUE(BlacklistHasMatch(kTestUrl)); } diff --git a/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc b/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc index 2b48b5c..a2b0a17 100644 --- a/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc +++ b/chrome/browser/privacy_blacklist/blacklist_manager_unittest.cc @@ -6,100 +6,18 @@ #include "base/message_loop.h" #include "base/path_service.h" -#include "base/scoped_temp_dir.h" #include "base/thread.h" -#include "base/values.h" #include "chrome/browser/privacy_blacklist/blacklist.h" +#include "chrome/browser/privacy_blacklist/blacklist_test_util.h" #include "chrome/common/chrome_paths.h" -#include "chrome/common/extensions/extension.h" -#include "chrome/common/extensions/extension_constants.h" -#include "chrome/common/notification_service.h" -#include "chrome/test/testing_profile.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.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 bool AreBlacklistPathsReady() const { - return true; - } - - virtual std::vector<FilePath> GetPersistentBlacklistPaths() { - return persistent_paths_; - } - - virtual std::vector<FilePath> GetTransientBlacklistPaths() { - return transient_paths_; - } - - void AddPersistentPath(const FilePath& path) { - persistent_paths_.push_back(path); - SendUpdateNotification(); - } - - void AddTransientPath(const FilePath& path) { - transient_paths_.push_back(path); - SendUpdateNotification(); - } - - void clear() { - persistent_paths_.clear(); - transient_paths_.clear(); - SendUpdateNotification(); - } - - private: - void SendUpdateNotification() { - ListValue* privacy_blacklists = new ListValue; - privacy_blacklists->Append(new StringValue("dummy.pbl")); - - DictionaryValue manifest; - manifest.SetString(extension_manifest_keys::kVersion, "1.0"); - manifest.SetString(extension_manifest_keys::kName, "test"); - manifest.Set(extension_manifest_keys::kPrivacyBlacklists, - privacy_blacklists); - -#if defined(OS_WIN) - FilePath path(FILE_PATH_LITERAL("c:\\foo")); -#elif defined(OS_POSIX) - FilePath path(FILE_PATH_LITERAL("/foo")); -#endif - Extension extension(path); - std::string error; - ASSERT_TRUE(extension.InitFromValue(manifest, false, &error)); - ASSERT_TRUE(error.empty()); - - NotificationService::current()->Notify( - NotificationType::EXTENSION_LOADED, - Source<Profile>(profile_), - Details<Extension>(&extension)); - } - - Profile* profile_; - - std::vector<FilePath> persistent_paths_; - std::vector<FilePath> transient_paths_; - - DISALLOW_COPY_AND_ASSIGN(TestBlacklistPathProvider); -}; - class BlacklistManagerTest : public testing::Test, public NotificationObserver { public: BlacklistManagerTest() @@ -146,7 +64,7 @@ class BlacklistManagerTest : public testing::Test, public NotificationObserver { FilePath test_data_dir_; - MyTestingProfile profile_; + BlacklistTestingProfile profile_; TestBlacklistPathProvider path_provider_; @@ -199,7 +117,6 @@ TEST_F(BlacklistManagerTest, BlacklistPathProvider) { const Blacklist* blacklist2 = manager->GetCompiledBlacklist(); // Added a real blacklist, the manager should recompile. - EXPECT_NE(blacklist1, blacklist2); EXPECT_TRUE(BlacklistHasMatch(blacklist2, "http://host/annoying_ads/ad.jpg")); EXPECT_FALSE(BlacklistHasMatch(blacklist2, "http://host/other_ads/ad.jpg")); @@ -238,7 +155,7 @@ TEST_F(BlacklistManagerTest, BlacklistPathReadError) { FilePath bogus_path(test_data_dir_.AppendASCII("does_not_exist_randomness")); ASSERT_FALSE(file_util::PathExists(bogus_path)); path_provider_.AddPersistentPath(bogus_path); - WaitForBlacklistError(); + WaitForBlacklistUpdate(); const Blacklist* blacklist = manager->GetCompiledBlacklist(); EXPECT_TRUE(blacklist); diff --git a/chrome/browser/privacy_blacklist/blacklist_request_info.cc b/chrome/browser/privacy_blacklist/blacklist_request_info.cc new file mode 100644 index 0000000..b5ecfb5 --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_request_info.cc @@ -0,0 +1,29 @@ +// 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_request_info.h" + +#include "chrome/browser/privacy_blacklist/blacklist_manager.h" + +// static +const void* const BlacklistRequestInfo::kURLRequestDataKey = 0; + +BlacklistRequestInfo::BlacklistRequestInfo(const GURL& url, + ResourceType::Type resource_type, + BlacklistManager* blacklist_manager) + : url_(url), + resource_type_(resource_type), + blacklist_manager_(blacklist_manager) { +} + +BlacklistRequestInfo::~BlacklistRequestInfo() { +} + +// static +BlacklistRequestInfo* BlacklistRequestInfo::FromURLRequest( + const URLRequest* request) { + URLRequest::UserData* user_data = + request->GetUserData(&kURLRequestDataKey); + return (user_data ? static_cast<BlacklistRequestInfo*>(user_data) : NULL); +} diff --git a/chrome/browser/privacy_blacklist/blacklist_request_info.h b/chrome/browser/privacy_blacklist/blacklist_request_info.h new file mode 100644 index 0000000..84a74d1 --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_request_info.h @@ -0,0 +1,47 @@ +// 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_REQUEST_INFO_H_ +#define CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_REQUEST_INFO_H_ + +#include "chrome/browser/privacy_blacklist/blacklist.h" +#include "googleurl/src/gurl.h" +#include "net/url_request/url_request.h" +#include "webkit/glue/resource_type.h" + +class BlacklistManager; + +// Privacy blacklist-related information attached to each request. +class BlacklistRequestInfo : public URLRequest::UserData { + public: + // Key used to access data attached to URLRequest objects. + static const void* const kURLRequestDataKey; + + BlacklistRequestInfo(const GURL& url, ResourceType::Type resource_type, + BlacklistManager* blacklist_manager); + ~BlacklistRequestInfo(); + + ResourceType::Type resource_type() const { return resource_type_; } + const BlacklistManager* GetBlacklistManager() const { + return blacklist_manager_.get(); + } + + // Get the blacklist request info stored in |request|, or NULL if there is no + // one. The object is owned by |request|. + static BlacklistRequestInfo* FromURLRequest(const URLRequest* request); + + private: + // URL of the request. + const GURL url_; + + // Type of the requested resource (main frame, image, etc). + const ResourceType::Type resource_type_; + + // BlacklistManager used for the request. + scoped_refptr<BlacklistManager> blacklist_manager_; + + DISALLOW_COPY_AND_ASSIGN(BlacklistRequestInfo); +}; + +#endif // CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_REQUEST_INFO_H_ diff --git a/chrome/browser/privacy_blacklist/blacklist_test_util.cc b/chrome/browser/privacy_blacklist/blacklist_test_util.cc new file mode 100644 index 0000000..da4fdc9 --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_test_util.cc @@ -0,0 +1,76 @@ +// 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_test_util.h" + +#include "base/file_path.h" +#include "base/values.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/notification_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +BlacklistTestingProfile::BlacklistTestingProfile() { + EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); + path_ = temp_dir_.path(); +} + +TestBlacklistPathProvider::TestBlacklistPathProvider(Profile* profile) + : profile_(profile) { +} + +bool TestBlacklistPathProvider::AreBlacklistPathsReady() const { + return true; +} + +std::vector<FilePath> TestBlacklistPathProvider::GetPersistentBlacklistPaths() { + return persistent_paths_; +} + +std::vector<FilePath> TestBlacklistPathProvider::GetTransientBlacklistPaths() { + return transient_paths_; +} + +void TestBlacklistPathProvider::AddPersistentPath(const FilePath& path) { + persistent_paths_.push_back(path); + SendUpdateNotification(); +} + +void TestBlacklistPathProvider::AddTransientPath(const FilePath& path) { + transient_paths_.push_back(path); + SendUpdateNotification(); +} + +void TestBlacklistPathProvider::clear() { + persistent_paths_.clear(); + transient_paths_.clear(); + SendUpdateNotification(); +} + +void TestBlacklistPathProvider::SendUpdateNotification() { + ListValue* privacy_blacklists = new ListValue; + privacy_blacklists->Append(new StringValue("dummy.pbl")); + + DictionaryValue manifest; + manifest.SetString(extension_manifest_keys::kVersion, "1.0"); + manifest.SetString(extension_manifest_keys::kName, "test"); + manifest.Set(extension_manifest_keys::kPrivacyBlacklists, + privacy_blacklists); + + // Create an extension with dummy path. +#if defined(OS_WIN) + FilePath path(FILE_PATH_LITERAL("c:\\foo")); +#elif defined(OS_POSIX) + FilePath path(FILE_PATH_LITERAL("/foo")); +#endif + Extension extension(path); + std::string error; + ASSERT_TRUE(extension.InitFromValue(manifest, false, &error)); + ASSERT_TRUE(error.empty()); + + NotificationService::current()->Notify( + NotificationType::EXTENSION_LOADED, + Source<Profile>(profile_), + Details<Extension>(&extension)); +} diff --git a/chrome/browser/privacy_blacklist/blacklist_test_util.h b/chrome/browser/privacy_blacklist/blacklist_test_util.h new file mode 100644 index 0000000..1b79c3d --- /dev/null +++ b/chrome/browser/privacy_blacklist/blacklist_test_util.h @@ -0,0 +1,64 @@ +// 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_TEST_UTIL_H_ +#define CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_TEST_UTIL_H_ + +#include <vector> + +#include "base/scoped_temp_dir.h" +#include "chrome/browser/privacy_blacklist/blacklist_manager.h" +#include "chrome/test/testing_profile.h" + +class FilePath; + +// Testing profile which uses a temporary directory. +class BlacklistTestingProfile : public TestingProfile { + public: + BlacklistTestingProfile(); + + BlacklistManager* GetBlacklistManager() { return blacklist_manager_; } + void set_blacklist_manager(BlacklistManager* manager) { + blacklist_manager_ = manager; + } + + private: + ScopedTempDir temp_dir_; + + BlacklistManager* blacklist_manager_; + + DISALLOW_COPY_AND_ASSIGN(BlacklistTestingProfile); +}; + +// Path provider which allows easy updates from the outside and sends +// notifications for each change. +class TestBlacklistPathProvider : public BlacklistPathProvider { + public: + explicit TestBlacklistPathProvider(Profile* profile); + + // BlacklistPathProvider: + virtual bool AreBlacklistPathsReady() const; + virtual std::vector<FilePath> GetPersistentBlacklistPaths(); + virtual std::vector<FilePath> GetTransientBlacklistPaths(); + + // Adds a path to the provder and sends an update notification. + void AddPersistentPath(const FilePath& path); + void AddTransientPath(const FilePath& path); + + // Removes all paths from the provider and send an update notification. + void clear(); + + private: + void SendUpdateNotification(); + + Profile* profile_; + + // Keep track of added paths. + std::vector<FilePath> persistent_paths_; + std::vector<FilePath> transient_paths_; + + DISALLOW_COPY_AND_ASSIGN(TestBlacklistPathProvider); +}; + +#endif // CHROME_BROWSER_PRIVACY_BLACKLIST_BLACKLIST_TEST_UTIL_H_ diff --git a/chrome/browser/privacy_blacklist/blacklist_ui.cc b/chrome/browser/privacy_blacklist/blacklist_ui.cc index 6d2327e..846ddb9 100644 --- a/chrome/browser/privacy_blacklist/blacklist_ui.cc +++ b/chrome/browser/privacy_blacklist/blacklist_ui.cc @@ -10,6 +10,8 @@ #include "chrome/browser/blocked_popup_container.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/privacy_blacklist/blacklist.h" +#include "chrome/browser/privacy_blacklist/blacklist_manager.h" +#include "chrome/browser/privacy_blacklist/blacklist_request_info.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" @@ -19,40 +21,42 @@ // Displays more info why some content has been blocked. class DisplayBlockedContentNoticeTask : public Task { public: - DisplayBlockedContentNoticeTask(const GURL& gurl, + DisplayBlockedContentNoticeTask(const GURL& url, const Blacklist::Match* match, const ResourceDispatcherHostRequestInfo* info) - : gurl_(gurl), - match_(match), + : url_(url), child_id_(info->child_id()), route_id_(info->route_id()) { - } - - virtual void Run() { - RenderViewHost* view = RenderViewHost::FromID(child_id_, route_id_); - if (!view) - return; // The view may be gone by the time we get here. - - string16 reason; - if (match_->attributes() & Blacklist::kDontStoreCookies) { + if (match->attributes() & Blacklist::kDontStoreCookies) { // No cookies stored. - reason = l10n_util::GetStringUTF16(IDS_BLACKLIST_BLOCKED_COOKIES); - } else if (match_->attributes() & Blacklist::kDontSendCookies) { + details_ = l10n_util::GetStringUTF16(IDS_BLACKLIST_BLOCKED_COOKIES); + } else if (match->attributes() & Blacklist::kDontSendCookies) { // No cookies sent. - reason = l10n_util::GetStringUTF16(IDS_BLACKLIST_BLOCKED_COOKIES); - } else if (match_->attributes() & Blacklist::kDontSendReferrer) { + details_ = l10n_util::GetStringUTF16(IDS_BLACKLIST_BLOCKED_COOKIES); + } else if (match->attributes() & Blacklist::kDontSendReferrer) { // No referrer sent. - reason = l10n_util::GetStringUTF16(IDS_BLACKLIST_BLOCKED_REFERRER); + details_ = l10n_util::GetStringUTF16(IDS_BLACKLIST_BLOCKED_REFERRER); } else { NOTREACHED(); } + } - view->delegate()->AddBlockedNotice(gurl_, reason); + virtual void Run() { + RenderViewHost* view = RenderViewHost::FromID(child_id_, route_id_); + if (!view) + return; // The view may be gone by the time we get here. + + view->delegate()->AddBlockedNotice(url_, details_); } private: - const GURL gurl_; - const Blacklist::Match* match_; + // URL for which we blocked content. + const GURL url_; + + // More detailed info what has been blocked. + string16 details_; + + // Information that allows us to identify the right tab to display the notice. const int child_id_; const int route_id_; @@ -63,15 +67,17 @@ class DisplayBlockedContentNoticeTask : public Task { void BlacklistUI::OnNonvisualContentBlocked(const URLRequest* request) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - const URLRequest::UserData* d = - request->GetUserData(&Blacklist::kRequestDataKey); - const Blacklist::Match* match = static_cast<const Blacklist::Match*>(d); + BlacklistRequestInfo* request_info = + BlacklistRequestInfo::FromURLRequest(request); + const BlacklistManager* blacklist_manager = + request_info->GetBlacklistManager(); + const Blacklist* blacklist = blacklist_manager->GetCompiledBlacklist(); + scoped_ptr<Blacklist::Match> match(blacklist->findMatch(request->url())); const ResourceDispatcherHostRequestInfo* info = ResourceDispatcherHost::InfoForRequest(request); - const GURL& gurl = request->url(); // Notify the UI that something non-visual has been blocked. ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, - new DisplayBlockedContentNoticeTask(gurl, match, info)); + new DisplayBlockedContentNoticeTask(request->url(), match.get(), info)); } diff --git a/chrome/browser/privacy_blacklist/blocked_response.cc b/chrome/browser/privacy_blacklist/blocked_response.cc deleted file mode 100644 index c0c00a9..0000000 --- a/chrome/browser/privacy_blacklist/blocked_response.cc +++ /dev/null @@ -1,104 +0,0 @@ -// 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/blocked_response.h" - -#include "app/l10n_util.h" -#include "app/resource_bundle.h" -#include "base/logging.h" -#include "base/string_util.h" -#include "base/values.h" -#include "chrome/browser/privacy_blacklist/blacklist.h" -#include "chrome/common/jstemplate_builder.h" -#include "chrome/common/url_constants.h" -#include "grit/browser_resources.h" -#include "grit/generated_resources.h" - -namespace { - -unsigned long Hash(std::set<std::string>::iterator i) { - return (unsigned long)(i.operator->()); -} - -std::string Dehash(unsigned long l) { - return *(std::string*)l; -} - -} // namespace - -namespace chrome { - -const char kUnblockScheme[] = "chrome-unblock"; - -const char kBlockScheme[] = "chrome-block"; - -std::string BlockedResponse::GetHTML(const std::string& url, - const Blacklist::Match* match) { - DictionaryValue strings; - strings.SetString(L"title", l10n_util::GetString(IDS_BLACKLIST_TITLE)); - strings.SetString(L"message", l10n_util::GetString(IDS_BLACKLIST_MESSAGE)); - strings.SetString(L"unblock", l10n_util::GetString(IDS_BLACKLIST_UNBLOCK)); - - // If kBlockAll is specified, assign blame to such an entry. - // Otherwise pick the first one. - const Blacklist::Entry* entry = NULL; - if (match->attributes() & Blacklist::kBlockAll) { - for (std::vector<const Blacklist::Entry*>::const_iterator i = - match->entries().begin(); i != match->entries().end(); ++i) { - if ((*i)->attributes() == Blacklist::kBlockAll) { - entry = *i; - break; - } - } - } else { - entry = match->entries().front(); - } - DCHECK(entry); - - strings.SetString(L"name", entry->provider()->name()); - strings.SetString(L"url", entry->provider()->url()); - strings.SetString(L"bypass", GetUnblockedURL(url)); - - const base::StringPiece html = - ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_BLACKLIST_HTML); - return jstemplate_builder::GetI18nTemplateHtml(html, &strings); -} - -std::string BlockedResponse::GetImage(const Blacklist::Match*) { - return ResourceBundle::GetSharedInstance(). - GetDataResource(IDR_BLACKLIST_IMAGE); -} - -std::string BlockedResponse::GetHeaders(const std::string& url) { - return - "HTTP/1.1 200 OK\nContent-Type: text/html\nlocation: " - + GetBlockedURL(url) + "\n" + "Cache-Control: no-store"; -} - -std::string BlockedResponse::GetBlockedURL(const std::string& url) { - return std::string(kBlockScheme) + "://" + url; -} - -std::string BlockedResponse::GetUnblockedURL(const std::string& url) { - std::set<std::string>::iterator i = blocked_.insert(blocked_.end(), url); - - char buf[64]; - base::snprintf(buf, 64, "%s://%lX", kUnblockScheme, Hash(i)); - return buf; -} - -std::string BlockedResponse::GetOriginalURL(const std::string& url) { - unsigned long l = 0; - - // Read the address of the url. - if (sscanf(url.c_str() + sizeof(kUnblockScheme) + 2, "%lX", &l)) { - std::size_t p = url.find('/', sizeof(kUnblockScheme) + 2); - if (p != std::string::npos) - return Dehash(l) + url.substr(p+1); - return Dehash(l); - } - return chrome::kAboutBlankURL; -} - -} // namespace chrome diff --git a/chrome/browser/privacy_blacklist/blocked_response.h b/chrome/browser/privacy_blacklist/blocked_response.h deleted file mode 100644 index 2d38b6e..0000000 --- a/chrome/browser/privacy_blacklist/blocked_response.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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_BLOCKED_RESPONSE_H_ -#define CHROME_BROWSER_PRIVACY_BLACKLIST_BLOCKED_RESPONSE_H_ - -#include <string> -#include <set> - -#include "chrome/browser/privacy_blacklist/blacklist.h" - -namespace chrome { - -extern const char kUnblockScheme[]; -extern const char kBlockScheme[]; - -// Generate localized responses to replace blacklisted resources. -// Blacklisted resources such as frames and iframes are replaced -// by HTML. Non visual resources such as Javascript and CSS are -// simply be cancelled so there is no blocked response for them. - -class BlockedResponse { - public: - BlockedResponse() {} - - // Returns the HTML document used as substituted content for blacklisted - // elements. - std::string GetHTML(const std::string& url, const Blacklist::Match* match); - - // Returns the image (as a string because that is what is expected by callers) - // used as substituted content for blacklisted elements. - std::string GetImage(const Blacklist::Match* match); - - // Returns HTTP headers for a blocked response replacing the given url. - std::string GetHeaders(const std::string& url); - - // Gets the original url of a blocked resource from its blocked url. - // The input must be a chome-unblock://XXX url. If the unblock url is - // not found, then about:blank is returned. - std::string GetOriginalURL(const std::string& url); - - private: - // Returns a chrome-block://XXX link for the given requested URL. - std::string GetBlockedURL(const std::string& url); - - // Returns a chrome-unblock://XXX link for the given chrome-block://YYY url. - std::string GetUnblockedURL(const std::string& url); - - std::set<std::string> blocked_; - - DISALLOW_COPY_AND_ASSIGN(BlockedResponse); -}; - -} - -#endif // CHROME_BROWSER_PRIVACY_BLACKLIST_BLOCKED_RESPONSE_H_ |