| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/privacy_blacklist/blacklist_manager.h" | 5 #include "chrome/browser/privacy_blacklist/blacklist_manager.h" |
| 6 | 6 |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/string_util.h" |
| 8 #include "base/task.h" | 9 #include "base/task.h" |
| 9 #include "base/thread.h" | 10 #include "base/thread.h" |
| 10 #include "chrome/browser/privacy_blacklist/blacklist.h" | 11 #include "chrome/browser/privacy_blacklist/blacklist.h" |
| 11 #include "chrome/browser/privacy_blacklist/blacklist_io.h" | 12 #include "chrome/browser/privacy_blacklist/blacklist_io.h" |
| 12 #include "chrome/browser/profile.h" | 13 #include "chrome/browser/profile.h" |
| 13 #include "chrome/common/chrome_constants.h" | 14 #include "chrome/common/chrome_constants.h" |
| 15 #include "chrome/common/notification_service.h" |
| 14 #include "chrome/common/notification_source.h" | 16 #include "chrome/common/notification_source.h" |
| 15 #include "chrome/common/notification_type.h" | 17 #include "chrome/common/notification_type.h" |
| 16 | 18 |
| 17 // Base class for tasks that use BlacklistManager. It ensures that the | 19 // Base class for tasks that use BlacklistManager. It ensures that the |
| 18 // BlacklistManager won't get destroyed while we need it, and that it | 20 // BlacklistManager won't get destroyed while we need it, and that it |
| 19 // will be destroyed always on the same thread. That's why we use | 21 // will be destroyed always on the same thread. That's why we use |
| 20 // a custom Task instead of just NewRunnableMethod. | 22 // a custom Task instead of just NewRunnableMethod. |
| 21 class BlacklistManagerTask : public Task { | 23 class BlacklistManagerTask : public Task { |
| 22 public: | 24 public: |
| 23 explicit BlacklistManagerTask(BlacklistManager* manager) | 25 explicit BlacklistManagerTask(BlacklistManager* manager) |
| 24 : manager_(manager), | 26 : original_loop_(MessageLoop::current()), |
| 25 original_loop_(MessageLoop::current()) { | 27 manager_(manager) { |
| 26 DCHECK(original_loop_); | 28 DCHECK(original_loop_); |
| 27 manager->AddRef(); | 29 manager->AddRef(); |
| 28 } | 30 } |
| 29 | 31 |
| 30 ~BlacklistManagerTask() { | 32 ~BlacklistManagerTask() { |
| 31 original_loop_->ReleaseSoon(FROM_HERE, manager_); | 33 original_loop_->ReleaseSoon(FROM_HERE, manager_); |
| 32 } | 34 } |
| 33 | 35 |
| 34 protected: | 36 protected: |
| 35 BlacklistManager* blacklist_manager() const { return manager_; } | 37 BlacklistManager* blacklist_manager() const { return manager_; } |
| 38 |
| 39 MessageLoop* original_loop_; |
| 36 | 40 |
| 37 private: | 41 private: |
| 38 BlacklistManager* manager_; | 42 BlacklistManager* manager_; |
| 39 | 43 |
| 40 MessageLoop* original_loop_; | |
| 41 | |
| 42 DISALLOW_COPY_AND_ASSIGN(BlacklistManagerTask); | 44 DISALLOW_COPY_AND_ASSIGN(BlacklistManagerTask); |
| 43 }; | 45 }; |
| 44 | 46 |
| 45 BlacklistPathProvider::~BlacklistPathProvider() { | 47 BlacklistPathProvider::~BlacklistPathProvider() { |
| 46 } | 48 } |
| 47 | 49 |
| 48 class BlacklistManager::CompileBlacklistTask : public BlacklistManagerTask { | 50 class BlacklistManager::CompileBlacklistTask : public BlacklistManagerTask { |
| 49 public: | 51 public: |
| 50 CompileBlacklistTask(BlacklistManager* manager, | 52 CompileBlacklistTask(BlacklistManager* manager, |
| 51 const FilePath& destination_blacklist, | 53 const FilePath& destination_blacklist, |
| 52 const std::vector<FilePath>& source_blacklists) | 54 const std::vector<FilePath>& source_blacklists) |
| 53 : BlacklistManagerTask(manager), | 55 : BlacklistManagerTask(manager), |
| 54 destination_blacklist_(destination_blacklist), | 56 destination_blacklist_(destination_blacklist), |
| 55 source_blacklists_(source_blacklists) { | 57 source_blacklists_(source_blacklists) { |
| 56 } | 58 } |
| 57 | 59 |
| 58 virtual void Run() { | 60 virtual void Run() { |
| 59 BlacklistIO io; | |
| 60 bool success = true; | 61 bool success = true; |
| 62 |
| 63 Blacklist blacklist; |
| 64 std::string error_string; |
| 61 | 65 |
| 62 for (std::vector<FilePath>::const_iterator i = source_blacklists_.begin(); | 66 for (std::vector<FilePath>::const_iterator i = source_blacklists_.begin(); |
| 63 i != source_blacklists_.end(); ++i) { | 67 i != source_blacklists_.end(); ++i) { |
| 64 if (!io.Read(*i)) { | 68 if (!BlacklistIO::ReadText(&blacklist, *i, &error_string)) { |
| 65 success = false; | 69 success = false; |
| 66 break; | 70 break; |
| 67 } | 71 } |
| 68 } | 72 } |
| 69 | 73 |
| 70 // Only overwrite the current compiled blacklist if we read all source | 74 // Only overwrite the current compiled blacklist if we read all source |
| 71 // files successfully. | 75 // files successfully. |
| 72 if (success) | 76 if (success) |
| 73 success = io.Write(destination_blacklist_); | 77 success = BlacklistIO::WriteBinary(&blacklist, destination_blacklist_); |
| 74 | 78 |
| 75 blacklist_manager()->OnBlacklistCompilationFinished(success); | 79 original_loop_->PostTask( |
| 80 FROM_HERE, |
| 81 NewRunnableMethod(blacklist_manager(), |
| 82 &BlacklistManager::OnBlacklistCompilationFinished, |
| 83 success)); |
| 76 } | 84 } |
| 77 | 85 |
| 78 private: | 86 private: |
| 79 FilePath destination_blacklist_; | 87 FilePath destination_blacklist_; |
| 80 | 88 |
| 81 std::vector<FilePath> source_blacklists_; | 89 std::vector<FilePath> source_blacklists_; |
| 82 | 90 |
| 83 DISALLOW_COPY_AND_ASSIGN(CompileBlacklistTask); | 91 DISALLOW_COPY_AND_ASSIGN(CompileBlacklistTask); |
| 84 }; | 92 }; |
| 85 | 93 |
| 86 class BlacklistManager::ReadBlacklistTask : public BlacklistManagerTask { | 94 class BlacklistManager::ReadBlacklistTask : public BlacklistManagerTask { |
| 87 public: | 95 public: |
| 88 ReadBlacklistTask(BlacklistManager* manager, const FilePath& blacklist_path) | 96 ReadBlacklistTask(BlacklistManager* manager, |
| 97 const FilePath& compiled_blacklist, |
| 98 const std::vector<FilePath>& transient_blacklists) |
| 89 : BlacklistManagerTask(manager), | 99 : BlacklistManagerTask(manager), |
| 90 blacklist_path_(blacklist_path) { | 100 compiled_blacklist_(compiled_blacklist), |
| 101 transient_blacklists_(transient_blacklists) { |
| 91 } | 102 } |
| 92 | 103 |
| 93 virtual void Run() { | 104 virtual void Run() { |
| 94 Blacklist* blacklist = new Blacklist(blacklist_path_); | 105 scoped_ptr<Blacklist> blacklist(new Blacklist); |
| 95 blacklist_manager()->OnBlacklistReadFinished(blacklist); | 106 if (!BlacklistIO::ReadBinary(blacklist.get(), compiled_blacklist_)) { |
| 107 ReportReadResult(NULL); |
| 108 return; |
| 109 } |
| 110 |
| 111 std::string error_string; |
| 112 std::vector<FilePath>::const_iterator i; |
| 113 for (i = transient_blacklists_.begin(); |
| 114 i != transient_blacklists_.end(); ++i) { |
| 115 if (!BlacklistIO::ReadText(blacklist.get(), *i, &error_string)) { |
| 116 ReportReadResult(NULL); |
| 117 return; |
| 118 } |
| 119 } |
| 120 |
| 121 ReportReadResult(blacklist.release()); |
| 96 } | 122 } |
| 97 | 123 |
| 98 private: | 124 private: |
| 99 FilePath blacklist_path_; | 125 void ReportReadResult(Blacklist* blacklist) { |
| 126 original_loop_->PostTask( |
| 127 FROM_HERE, NewRunnableMethod(blacklist_manager(), |
| 128 &BlacklistManager::OnBlacklistReadFinished, |
| 129 blacklist)); |
| 130 } |
| 131 |
| 132 FilePath compiled_blacklist_; |
| 133 std::vector<FilePath> transient_blacklists_; |
| 100 | 134 |
| 101 DISALLOW_COPY_AND_ASSIGN(ReadBlacklistTask); | 135 DISALLOW_COPY_AND_ASSIGN(ReadBlacklistTask); |
| 102 }; | 136 }; |
| 103 | 137 |
| 104 BlacklistManager::BlacklistManager(Profile* profile, | 138 BlacklistManager::BlacklistManager(Profile* profile, |
| 139 BlacklistPathProvider* path_provider, |
| 105 base::Thread* backend_thread) | 140 base::Thread* backend_thread) |
| 106 : compiled_blacklist_path_( | 141 : first_read_finished_(false), |
| 142 profile_(profile), |
| 143 compiled_blacklist_path_( |
| 107 profile->GetPath().Append(chrome::kPrivacyBlacklistFileName)), | 144 profile->GetPath().Append(chrome::kPrivacyBlacklistFileName)), |
| 108 compiling_blacklist_(false), | 145 path_provider_(path_provider), |
| 109 backend_thread_(backend_thread) { | 146 backend_thread_(backend_thread) { |
| 110 registrar_.Add(this, | 147 registrar_.Add(this, |
| 111 NotificationType::PRIVACY_BLACKLIST_PATH_PROVIDER_UPDATED, | 148 NotificationType::BLACKLIST_PATH_PROVIDER_UPDATED, |
| 112 Source<Profile>(profile)); | 149 Source<Profile>(profile)); |
| 113 ReadBlacklist(); | 150 ReadBlacklist(); |
| 114 } | 151 } |
| 115 | 152 |
| 116 void BlacklistManager::RegisterBlacklistPathProvider( | |
| 117 BlacklistPathProvider* provider) { | |
| 118 DCHECK(providers_.find(provider) == providers_.end()); | |
| 119 providers_.insert(provider); | |
| 120 } | |
| 121 | |
| 122 void BlacklistManager::UnregisterBlacklistPathProvider( | |
| 123 BlacklistPathProvider* provider) { | |
| 124 DCHECK(providers_.find(provider) != providers_.end()); | |
| 125 providers_.erase(provider); | |
| 126 } | |
| 127 | |
| 128 void BlacklistManager::Observe(NotificationType type, | 153 void BlacklistManager::Observe(NotificationType type, |
| 129 const NotificationSource& source, | 154 const NotificationSource& source, |
| 130 const NotificationDetails& details) { | 155 const NotificationDetails& details) { |
| 131 DCHECK(type == NotificationType::PRIVACY_BLACKLIST_PATH_PROVIDER_UPDATED); | 156 DCHECK(type == NotificationType::BLACKLIST_PATH_PROVIDER_UPDATED); |
| 132 CompileBlacklist(); | 157 CompileBlacklist(); |
| 133 } | 158 } |
| 134 | 159 |
| 135 void BlacklistManager::CompileBlacklist() { | 160 void BlacklistManager::CompileBlacklist() { |
| 136 if (compiling_blacklist_) { | 161 DCHECK(CalledOnValidThread()); |
| 137 // If we end up here, that means that initial compile succeeded, | |
| 138 // but then we couldn't read back the resulting Blacklist. Return early | |
| 139 // to avoid a potential infinite loop. | |
| 140 // TODO(phajdan.jr): Report the error. | |
| 141 compiling_blacklist_ = false; | |
| 142 return; | |
| 143 } | |
| 144 | 162 |
| 145 compiling_blacklist_ = true; | 163 RunTaskOnBackendThread(new CompileBlacklistTask( |
| 146 | 164 this, compiled_blacklist_path_, |
| 147 std::vector<FilePath> source_blacklists; | 165 path_provider_->GetPersistentBlacklistPaths())); |
| 148 | |
| 149 for (ProvidersSet::iterator provider = providers_.begin(); | |
| 150 provider != providers_.end(); ++provider) { | |
| 151 std::vector<FilePath> provided_paths((*provider)->GetBlacklistPaths()); | |
| 152 source_blacklists.insert(source_blacklists.end(), | |
| 153 provided_paths.begin(), provided_paths.end()); | |
| 154 } | |
| 155 | |
| 156 RunTaskOnBackendThread(new CompileBlacklistTask(this, compiled_blacklist_path_
, | |
| 157 source_blacklists)); | |
| 158 } | 166 } |
| 159 | 167 |
| 160 void BlacklistManager::ReadBlacklist() { | 168 void BlacklistManager::ReadBlacklist() { |
| 161 RunTaskOnBackendThread(new ReadBlacklistTask(this, compiled_blacklist_path_)); | 169 DCHECK(CalledOnValidThread()); |
| 170 |
| 171 RunTaskOnBackendThread(new ReadBlacklistTask( |
| 172 this, compiled_blacklist_path_, |
| 173 path_provider_->GetTransientBlacklistPaths())); |
| 162 } | 174 } |
| 163 | 175 |
| 164 void BlacklistManager::OnBlacklistCompilationFinished(bool success) { | 176 void BlacklistManager::OnBlacklistCompilationFinished(bool success) { |
| 177 DCHECK(CalledOnValidThread()); |
| 178 |
| 165 if (success) { | 179 if (success) { |
| 166 ReadBlacklist(); | 180 ReadBlacklist(); |
| 167 } else { | 181 } else { |
| 168 // TODO(phajdan.jr): Report the error. | 182 string16 error_message(ASCIIToUTF16("Blacklist compilation failed.")); |
| 183 NotificationService::current()->Notify( |
| 184 NotificationType::BLACKLIST_MANAGER_ERROR, |
| 185 Source<Profile>(profile_), |
| 186 Details<string16>(&error_message)); |
| 169 } | 187 } |
| 170 } | 188 } |
| 171 | 189 |
| 172 void BlacklistManager::OnBlacklistReadFinished(Blacklist* blacklist) { | 190 void BlacklistManager::OnBlacklistReadFinished(Blacklist* blacklist) { |
| 173 if (blacklist->is_good()) { | 191 DCHECK(CalledOnValidThread()); |
| 174 compiled_blacklist_.reset(blacklist); | 192 |
| 175 compiling_blacklist_ = false; | 193 if (!blacklist) { |
| 176 } else { | 194 if (!first_read_finished_) { |
| 177 delete blacklist; | 195 // If we're loading for the first time, the compiled blacklist could |
| 178 CompileBlacklist(); | 196 // just not exist. Try compiling it once. |
| 197 first_read_finished_ = true; |
| 198 CompileBlacklist(); |
| 199 } else { |
| 200 string16 error_message(ASCIIToUTF16("Blacklist read failed.")); |
| 201 NotificationService::current()->Notify( |
| 202 NotificationType::BLACKLIST_MANAGER_ERROR, |
| 203 Source<Profile>(profile_), |
| 204 Details<string16>(&error_message)); |
| 205 } |
| 206 return; |
| 179 } | 207 } |
| 208 first_read_finished_ = true; |
| 209 compiled_blacklist_.reset(blacklist); |
| 210 |
| 211 NotificationService::current()->Notify( |
| 212 NotificationType::BLACKLIST_MANAGER_BLACKLIST_READ_FINISHED, |
| 213 Source<Profile>(profile_), |
| 214 Details<Blacklist>(blacklist)); |
| 180 } | 215 } |
| 181 | 216 |
| 182 void BlacklistManager::RunTaskOnBackendThread(Task* task) { | 217 void BlacklistManager::RunTaskOnBackendThread(Task* task) { |
| 183 if (backend_thread_) { | 218 if (backend_thread_) { |
| 184 backend_thread_->message_loop()->PostTask(FROM_HERE, task); | 219 backend_thread_->message_loop()->PostTask(FROM_HERE, task); |
| 185 } else { | 220 } else { |
| 186 task->Run(); | 221 task->Run(); |
| 187 delete task; | 222 delete task; |
| 188 } | 223 } |
| 189 } | 224 } |
| OLD | NEW |