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 |