blob: 14f31bc4927c045bc00be2a91c436798e39435f9 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294//
5
6#include "chrome/browser/safe_browsing/safe_browsing_service.h"
7
[email protected]613a03b2008-10-24 23:02:008#include "base/command_line.h"
initial.commit09911bf2008-07-26 23:55:299#include "base/histogram.h"
10#include "base/logging.h"
11#include "base/message_loop.h"
12#include "base/path_service.h"
13#include "base/string_util.h"
14#include "chrome/browser/browser_process.h"
[email protected]0a3076572008-12-13 20:48:3615#include "chrome/browser/chrome_thread.h"
initial.commit09911bf2008-07-26 23:55:2916#include "chrome/browser/profile_manager.h"
17#include "chrome/browser/safe_browsing/protocol_manager.h"
18#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
19#include "chrome/browser/safe_browsing/safe_browsing_database.h"
[email protected]f3ec7742009-01-15 00:59:1620#include "chrome/browser/tab_contents/tab_util.h"
initial.commit09911bf2008-07-26 23:55:2921#include "chrome/common/chrome_constants.h"
22#include "chrome/common/chrome_paths.h"
[email protected]613a03b2008-10-24 23:02:0023#include "chrome/common/chrome_switches.h"
initial.commit09911bf2008-07-26 23:55:2924#include "chrome/common/pref_names.h"
25#include "chrome/common/pref_service.h"
26#include "net/base/registry_controlled_domain.h"
27
[email protected]e1acf6f2008-10-27 20:43:3328using base::Time;
29using base::TimeDelta;
30
initial.commit09911bf2008-07-26 23:55:2931SafeBrowsingService::SafeBrowsingService()
32 : io_loop_(NULL),
33 database_(NULL),
34 protocol_manager_(NULL),
35 enabled_(false),
[email protected]613a03b2008-10-24 23:02:0036 resetting_(false),
[email protected]57119c3f2008-12-04 00:33:0437 database_loaded_(false),
38 update_in_progress_(false) {
[email protected]bb975362009-01-21 01:00:2239 new_safe_browsing_ = !CommandLine::ForCurrentProcess()->HasSwitch(
40 switches::kUseOldSafeBrowsing);
[email protected]0a3076572008-12-13 20:48:3641 base::SystemMonitor* monitor = base::SystemMonitor::Get();
42 DCHECK(monitor);
43 if (monitor)
44 monitor->AddObserver(this);
initial.commit09911bf2008-07-26 23:55:2945}
46
47SafeBrowsingService::~SafeBrowsingService() {
[email protected]0a3076572008-12-13 20:48:3648 base::SystemMonitor* monitor = base::SystemMonitor::Get();
49 if (monitor)
50 monitor->RemoveObserver(this);
initial.commit09911bf2008-07-26 23:55:2951}
52
53// Only called on the UI thread.
54void SafeBrowsingService::Initialize(MessageLoop* io_loop) {
55 io_loop_ = io_loop;
56
57 // Get the profile's preference for SafeBrowsing.
58 std::wstring user_data_dir;
59 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
60 ProfileManager* profile_manager = g_browser_process->profile_manager();
61 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
62 PrefService* pref_service = profile->GetPrefs();
63 if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled))
64 Start();
65}
66
67// Start up SafeBrowsing objects. This can be called at browser start, or when
68// the user checks the "Enable SafeBrowsing" option in the Advanced options UI.
69void SafeBrowsingService::Start() {
70 DCHECK(!db_thread_.get());
[email protected]ab820df2008-08-26 05:55:1071 db_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
initial.commit09911bf2008-07-26 23:55:2972 if (!db_thread_->Start())
73 return;
74
initial.commit09911bf2008-07-26 23:55:2975 // Retrieve client MAC keys.
76 PrefService* local_state = g_browser_process->local_state();
77 std::string client_key, wrapped_key;
78 if (local_state) {
79 client_key =
80 WideToASCII(local_state->GetString(prefs::kSafeBrowsingClientKey));
81 wrapped_key =
82 WideToASCII(local_state->GetString(prefs::kSafeBrowsingWrappedKey));
83 }
84
85 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
86 this, &SafeBrowsingService::OnIOInitialize, MessageLoop::current(),
87 client_key, wrapped_key));
[email protected]2c2fb222008-12-17 02:35:4688
89 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
90 this, &SafeBrowsingService::OnDBInitialize));
initial.commit09911bf2008-07-26 23:55:2991}
92
93void SafeBrowsingService::ShutDown() {
94 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
95 this, &SafeBrowsingService::OnIOShutdown));
96}
97
98void SafeBrowsingService::OnIOInitialize(MessageLoop* notify_loop,
99 const std::string& client_key,
100 const std::string& wrapped_key) {
101 DCHECK(MessageLoop::current() == io_loop_);
102 enabled_ = true;
103 protocol_manager_ = new SafeBrowsingProtocolManager(this,
104 notify_loop,
105 client_key,
106 wrapped_key);
[email protected]613a03b2008-10-24 23:02:00107 // We want to initialize the protocol manager only after the database has
108 // loaded, which we'll receive asynchronously (DatabaseLoadComplete). If
109 // database_loaded_ isn't true, we'll wait for that notification to do the
110 // init.
111 if (database_loaded_)
112 protocol_manager_->Initialize();
initial.commit09911bf2008-07-26 23:55:29113}
114
115void SafeBrowsingService::OnDBInitialize() {
116 DCHECK(MessageLoop::current() == db_thread_->message_loop());
117 GetDatabase();
118}
119
120void SafeBrowsingService::OnIOShutdown() {
121 DCHECK(MessageLoop::current() == io_loop_);
122 if (!enabled_)
123 return;
124
125 enabled_ = false;
[email protected]fbb2b7a2008-11-18 22:54:04126 resetting_ = false;
initial.commit09911bf2008-07-26 23:55:29127
128 // This cancels all in-flight GetHash requests.
129 delete protocol_manager_;
[email protected]fbb2b7a2008-11-18 22:54:04130 protocol_manager_ = NULL;
initial.commit09911bf2008-07-26 23:55:29131
132 if (db_thread_.get())
133 db_thread_->message_loop()->DeleteSoon(FROM_HERE, database_);
134
135 // Flush the database thread. Any in-progress database check results will be
136 // ignored and cleaned up below.
137 db_thread_.reset(NULL);
138
139 database_ = NULL;
[email protected]fbb2b7a2008-11-18 22:54:04140 database_loaded_ = false;
initial.commit09911bf2008-07-26 23:55:29141
[email protected]613a03b2008-10-24 23:02:00142 // Delete queued and pending checks once the database thread is done, calling
143 // back any clients with 'URL_SAFE'.
144 while (!queued_checks_.empty()) {
145 QueuedCheck check = queued_checks_.front();
146 if (check.client)
147 check.client->OnUrlCheckResult(check.url, URL_SAFE);
148 queued_checks_.pop_front();
149 }
150
initial.commit09911bf2008-07-26 23:55:29151 for (CurrentChecks::iterator it = checks_.begin();
152 it != checks_.end(); ++it) {
153 if ((*it)->client)
154 (*it)->client->OnUrlCheckResult((*it)->url, URL_SAFE);
155 delete *it;
156 }
157 checks_.clear();
158
159 gethash_requests_.clear();
160}
161
162// Runs on the UI thread.
163void SafeBrowsingService::OnEnable(bool enabled) {
164 if (enabled)
165 Start();
166 else
167 ShutDown();
168}
169
170bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
171 return url.SchemeIs("http") || url.SchemeIs("https");
172}
173
174bool SafeBrowsingService::CheckUrl(const GURL& url, Client* client) {
175 DCHECK(MessageLoop::current() == io_loop_);
initial.commit09911bf2008-07-26 23:55:29176 if (!enabled_ || !database_)
177 return true;
178
[email protected]613a03b2008-10-24 23:02:00179 if (new_safe_browsing_)
180 return CheckUrlNew(url, client);
181
initial.commit09911bf2008-07-26 23:55:29182 if (!resetting_) {
183 Time start_time = Time::Now();
184 bool need_check = database_->NeedToCheckUrl(url);
185 UMA_HISTOGRAM_TIMES(L"SB.BloomFilter", Time::Now() - start_time);
186 if (!need_check)
187 return true; // The url is definitely safe.
188 }
189
190 // The url may or may not be safe, need to go to the database to be sure.
191 SafeBrowsingCheck* check = new SafeBrowsingCheck();
192 check->url = url;
193 check->client = client;
194 check->result = URL_SAFE;
195 check->need_get_hash = false;
196 check->start = Time::Now();
197 checks_.insert(check);
198
[email protected]613a03b2008-10-24 23:02:00199 // Old school SafeBrowsing does an asynchronous database check.
initial.commit09911bf2008-07-26 23:55:29200 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
201 this, &SafeBrowsingService::CheckDatabase,
202 check, protocol_manager_->last_update()));
[email protected]613a03b2008-10-24 23:02:00203
204 return false;
205}
206
207bool SafeBrowsingService::CheckUrlNew(const GURL& url, Client* client) {
208 if (resetting_ || !database_loaded_) {
209 QueuedCheck check;
210 check.client = client;
211 check.url = url;
212 queued_checks_.push_back(check);
213 return false;
214 }
215
216 std::string list;
217 std::vector<SBPrefix> prefix_hits;
218 std::vector<SBFullHashResult> full_hits;
[email protected]22573822008-11-14 00:40:47219 base::Time check_start = base::Time::Now();
[email protected]c3ff89492008-11-11 02:17:51220 bool prefix_match = database_->ContainsUrl(url, &list, &prefix_hits,
221 &full_hits,
[email protected]613a03b2008-10-24 23:02:00222 protocol_manager_->last_update());
[email protected]22573822008-11-14 00:40:47223
224 UMA_HISTOGRAM_TIMES(L"SB2.FilterCheck", base::Time::Now() - check_start);
225
[email protected]613a03b2008-10-24 23:02:00226 if (!prefix_match)
227 return true; // URL is okay.
228
229 // Needs to be asynchronous, since we could be in the constructor of a
230 // ResourceDispatcherHost event handler which can't pause there.
231 SafeBrowsingCheck* check = new SafeBrowsingCheck();
232 check->url = url;
233 check->client = client;
234 check->result = URL_SAFE;
235 check->start = Time::Now();
236 check->need_get_hash = full_hits.empty();
237 check->prefix_hits.swap(prefix_hits);
238 check->full_hits.swap(full_hits);
239 checks_.insert(check);
240
241 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
242 this, &SafeBrowsingService::OnCheckDone, check));
243
initial.commit09911bf2008-07-26 23:55:29244 return false;
245}
246
247void SafeBrowsingService::DisplayBlockingPage(const GURL& url,
248 ResourceType::Type resource_type,
249 UrlCheckResult result,
250 Client* client,
251 MessageLoop* ui_loop,
252 int render_process_host_id,
253 int render_view_id) {
254 // Check if the user has already ignored our warning for this render_view
255 // and domain.
256 for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
257 const WhiteListedEntry& entry = white_listed_entries_[i];
258 if (entry.render_process_host_id == render_process_host_id &&
259 entry.render_view_id == render_view_id &&
260 entry.result == result &&
261 entry.domain ==
[email protected]8ac1a752008-07-31 19:40:37262 net::RegistryControlledDomainService::GetDomainAndRegistry(url)) {
initial.commit09911bf2008-07-26 23:55:29263 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
264 this, &SafeBrowsingService::NotifyClientBlockingComplete,
265 client, true));
266 return;
267 }
268 }
269
[email protected]cbab76d2008-10-13 22:42:47270 BlockingPageParam param;
271 param.url = url;
272 param.resource_type = resource_type;
273 param.result = result;
274 param.client = client;
275 param.render_process_host_id = render_process_host_id;
276 param.render_view_id = render_view_id;
277 // The blocking page must be created from the UI thread.
278 ui_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
279 &SafeBrowsingService::DoDisplayBlockingPage,
280 param));
281}
282
283// Invoked on the UI thread.
284void SafeBrowsingService::DoDisplayBlockingPage(
285 const BlockingPageParam& param) {
[email protected]a3a1d142008-12-19 00:42:30286 // The tab might have been closed.
287 if (!tab_util::GetWebContentsByID(param.render_process_host_id,
288 param.render_view_id)) {
289 // The tab is gone and we did not have a chance at showing the interstitial.
290 // Just act as "Don't Proceed" was chosen.
291 base::Thread* io_thread = g_browser_process->io_thread();
292 if (!io_thread)
293 return;
294 BlockingPageParam response_param = param;
295 response_param.proceed = false;
296 io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
297 this, &SafeBrowsingService::OnBlockingPageDone, response_param));
298 return;
299 }
[email protected]cbab76d2008-10-13 22:42:47300 SafeBrowsingBlockingPage* blocking_page = new SafeBrowsingBlockingPage(this,
301 param);
302 blocking_page->Show();
initial.commit09911bf2008-07-26 23:55:29303}
304
305void SafeBrowsingService::CancelCheck(Client* client) {
306 DCHECK(MessageLoop::current() == io_loop_);
307
308 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
309 if ((*i)->client == client)
310 (*i)->client = NULL;
311 }
[email protected]613a03b2008-10-24 23:02:00312
313 // Scan the queued clients store. Clients may be here if they requested a URL
314 // check before the database has finished loading or resetting.
315 if (!database_loaded_ || resetting_) {
316 std::deque<QueuedCheck>::iterator it = queued_checks_.begin();
317 for (; it != queued_checks_.end(); ++it) {
318 if (it->client == client)
319 it->client = NULL;
320 }
321 }
initial.commit09911bf2008-07-26 23:55:29322}
323
324void SafeBrowsingService::CheckDatabase(SafeBrowsingCheck* info,
325 Time last_update) {
326 DCHECK(MessageLoop::current() == db_thread_->message_loop());
327 // If client == NULL it means it was cancelled, no need for db lookup.
328 if (info->client && GetDatabase()) {
329 Time now = Time::Now();
330 std::string list;
331 if (GetDatabase()->ContainsUrl(info->url,
332 &list,
333 &info->prefix_hits,
334 &info->full_hits,
335 last_update)) {
336 if (info->prefix_hits.empty()) {
337 info->result = GetResultFromListname(list);
338 } else {
339 if (info->full_hits.empty())
340 info->need_get_hash = true;
341 }
342 }
343 info->db_time = Time::Now() - now;
344 }
345
346 if (io_loop_)
347 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
348 this, &SafeBrowsingService::OnCheckDone, info));
349}
350
[email protected]613a03b2008-10-24 23:02:00351void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
initial.commit09911bf2008-07-26 23:55:29352 DCHECK(MessageLoop::current() == io_loop_);
353
354 // If we've been shutdown during the database lookup, this check will already
355 // have been deleted (in OnIOShutdown).
[email protected]613a03b2008-10-24 23:02:00356 if (!enabled_ || checks_.find(check) == checks_.end())
initial.commit09911bf2008-07-26 23:55:29357 return;
358
[email protected]613a03b2008-10-24 23:02:00359 UMA_HISTOGRAM_TIMES(L"SB.Database", Time::Now() - check->start);
360 if (check->client && check->need_get_hash) {
initial.commit09911bf2008-07-26 23:55:29361 // We have a partial match so we need to query Google for the full hash.
362 // Clean up will happen in HandleGetHashResults.
363
364 // See if we have a GetHash request already in progress for this particular
365 // prefix. If so, we just append ourselves to the list of interested parties
366 // when the results arrive. We only do this for checks involving one prefix,
367 // since that is the common case (multiple prefixes will issue the request
368 // as normal).
[email protected]613a03b2008-10-24 23:02:00369 if (check->prefix_hits.size() == 1) {
370 SBPrefix prefix = check->prefix_hits[0];
initial.commit09911bf2008-07-26 23:55:29371 GetHashRequests::iterator it = gethash_requests_.find(prefix);
372 if (it != gethash_requests_.end()) {
373 // There's already a request in progress.
[email protected]613a03b2008-10-24 23:02:00374 it->second.push_back(check);
initial.commit09911bf2008-07-26 23:55:29375 return;
376 }
377
378 // No request in progress, so we're the first for this prefix.
379 GetHashRequestors requestors;
[email protected]613a03b2008-10-24 23:02:00380 requestors.push_back(check);
initial.commit09911bf2008-07-26 23:55:29381 gethash_requests_[prefix] = requestors;
382 }
383
384 // Reset the start time so that we can measure the network time without the
385 // database time.
[email protected]613a03b2008-10-24 23:02:00386 check->start = Time::Now();
387 protocol_manager_->GetFullHash(check, check->prefix_hits);
initial.commit09911bf2008-07-26 23:55:29388 } else {
389 // We may have cached results for previous GetHash queries.
[email protected]613a03b2008-10-24 23:02:00390 HandleOneCheck(check, check->full_hits);
initial.commit09911bf2008-07-26 23:55:29391 }
392}
393
394SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
395 DCHECK(MessageLoop::current() == db_thread_->message_loop());
396 if (database_)
397 return database_;
398
399 std::wstring path;
400 bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
401 DCHECK(result);
402
403 path.append(L"\\");
404 path.append(chrome::kSafeBrowsingFilename);
405
406 Time before = Time::Now();
[email protected]54d80bb02008-09-20 02:03:08407 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create();
[email protected]613a03b2008-10-24 23:02:00408 Callback0::Type* chunk_callback =
initial.commit09911bf2008-07-26 23:55:29409 NewCallback(this, &SafeBrowsingService::ChunkInserted);
[email protected]613a03b2008-10-24 23:02:00410 bool init_success = database->Init(path, chunk_callback);
411
412 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
413 this, &SafeBrowsingService::DatabaseLoadComplete, !init_success));
414
415 if (!init_success) {
initial.commit09911bf2008-07-26 23:55:29416 NOTREACHED();
417 return NULL;
418 }
419
420 database_ = database;
421
422 TimeDelta open_time = Time::Now() - before;
423 SB_DLOG(INFO) << "SafeBrowsing database open took " <<
424 open_time.InMilliseconds() << " ms.";
425
426 return database_;
427}
428
429// Public API called only on the IO thread.
430// The SafeBrowsingProtocolManager has received the full hash results for
431// prefix hits detected in the database.
432void SafeBrowsingService::HandleGetHashResults(
433 SafeBrowsingCheck* check,
[email protected]200abc32008-09-05 01:44:33434 const std::vector<SBFullHashResult>& full_hashes,
435 bool can_cache) {
initial.commit09911bf2008-07-26 23:55:29436 if (checks_.find(check) == checks_.end())
437 return;
438
439 DCHECK(enabled_);
440
[email protected]22573822008-11-14 00:40:47441 if (new_safe_browsing_)
442 UMA_HISTOGRAM_LONG_TIMES(L"SB2.Network", Time::Now() - check->start);
443 else
444 UMA_HISTOGRAM_LONG_TIMES(L"SB.Network", Time::Now() - check->start);
445
[email protected]200abc32008-09-05 01:44:33446 std::vector<SBPrefix> prefixes = check->prefix_hits;
initial.commit09911bf2008-07-26 23:55:29447 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
448
[email protected]613a03b2008-10-24 23:02:00449 if (can_cache) {
450 if (!new_safe_browsing_) {
451 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
452 this, &SafeBrowsingService::CacheHashResults, prefixes, full_hashes));
453 } else if (database_) {
[email protected]c3ff89492008-11-11 02:17:51454 // Cache the GetHash results in memory:
[email protected]613a03b2008-10-24 23:02:00455 database_->CacheHashResults(prefixes, full_hashes);
456 }
457 }
initial.commit09911bf2008-07-26 23:55:29458}
459
460void SafeBrowsingService::OnHandleGetHashResults(
461 SafeBrowsingCheck* check,
462 const std::vector<SBFullHashResult>& full_hashes) {
463 SBPrefix prefix = check->prefix_hits[0];
464 GetHashRequests::iterator it = gethash_requests_.find(prefix);
465 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
466 HandleOneCheck(check, full_hashes);
467 return;
468 }
469
470 // Call back all interested parties.
471 GetHashRequestors& requestors = it->second;
472 for (GetHashRequestors::iterator r = requestors.begin();
473 r != requestors.end(); ++r) {
474 HandleOneCheck(*r, full_hashes);
475 }
476
477 gethash_requests_.erase(it);
478}
479
480void SafeBrowsingService::HandleOneCheck(
481 SafeBrowsingCheck* check,
482 const std::vector<SBFullHashResult>& full_hashes) {
483 if (check->client) {
484 UrlCheckResult result = URL_SAFE;
485 int index = safe_browsing_util::CompareFullHashes(check->url, full_hashes);
486 if (index != -1)
487 result = GetResultFromListname(full_hashes[index].list_name);
488
489 // Let the client continue handling the original request.
490 check->client->OnUrlCheckResult(check->url, result);
491 }
492
493 checks_.erase(check);
494 delete check;
495}
496
[email protected]57119c3f2008-12-04 00:33:04497void SafeBrowsingService::UpdateStarted() {
initial.commit09911bf2008-07-26 23:55:29498 DCHECK(MessageLoop::current() == io_loop_);
499 DCHECK(enabled_);
[email protected]57119c3f2008-12-04 00:33:04500 DCHECK(!update_in_progress_);
501 update_in_progress_ = true;
initial.commit09911bf2008-07-26 23:55:29502 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
503 this, &SafeBrowsingService::GetAllChunksFromDatabase));
504}
505
[email protected]613a03b2008-10-24 23:02:00506void SafeBrowsingService::UpdateFinished(bool update_succeeded) {
[email protected]aad08752008-10-02 22:13:41507 DCHECK(MessageLoop::current() == io_loop_);
508 DCHECK(enabled_);
[email protected]57119c3f2008-12-04 00:33:04509 if (update_in_progress_) {
510 update_in_progress_ = false;
511 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
512 this, &SafeBrowsingService::DatabaseUpdateFinished, update_succeeded));
513 }
[email protected]aad08752008-10-02 22:13:41514}
515
[email protected]613a03b2008-10-24 23:02:00516void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
[email protected]aad08752008-10-02 22:13:41517 DCHECK(MessageLoop::current() == db_thread_->message_loop());
518 if (GetDatabase())
[email protected]613a03b2008-10-24 23:02:00519 GetDatabase()->UpdateFinished(update_succeeded);
[email protected]aad08752008-10-02 22:13:41520}
521
[email protected]cbab76d2008-10-13 22:42:47522void SafeBrowsingService::OnBlockingPageDone(const BlockingPageParam& param) {
523 NotifyClientBlockingComplete(param.client, param.proceed);
initial.commit09911bf2008-07-26 23:55:29524
[email protected]cbab76d2008-10-13 22:42:47525 if (param.proceed) {
initial.commit09911bf2008-07-26 23:55:29526 // Whitelist this domain and warning type for the given tab.
527 WhiteListedEntry entry;
[email protected]cbab76d2008-10-13 22:42:47528 entry.render_process_host_id = param.render_process_host_id;
529 entry.render_view_id = param.render_view_id;
530 entry.domain =
531 net::RegistryControlledDomainService::GetDomainAndRegistry(param.url);
532 entry.result = param.result;
initial.commit09911bf2008-07-26 23:55:29533 white_listed_entries_.push_back(entry);
534 }
initial.commit09911bf2008-07-26 23:55:29535}
536
537void SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
538 bool proceed) {
539 client->OnBlockingPageComplete(proceed);
540}
541
542// This method runs on the UI loop to access the prefs.
543void SafeBrowsingService::OnNewMacKeys(const std::string& client_key,
544 const std::string& wrapped_key) {
545 PrefService* prefs = g_browser_process->local_state();
546 if (prefs) {
547 prefs->SetString(prefs::kSafeBrowsingClientKey, ASCIIToWide(client_key));
548 prefs->SetString(prefs::kSafeBrowsingWrappedKey, ASCIIToWide(wrapped_key));
549 }
550}
551
552void SafeBrowsingService::ChunkInserted() {
[email protected]fbb2b7a2008-11-18 22:54:04553 DCHECK(MessageLoop::current() == db_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29554 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
555 this, &SafeBrowsingService::OnChunkInserted));
556}
557
558void SafeBrowsingService::OnChunkInserted() {
559 DCHECK(MessageLoop::current() == io_loop_);
[email protected]fbb2b7a2008-11-18 22:54:04560 if (enabled_)
561 protocol_manager_->OnChunkInserted();
initial.commit09911bf2008-07-26 23:55:29562}
563
[email protected]613a03b2008-10-24 23:02:00564void SafeBrowsingService::DatabaseLoadComplete(bool database_error) {
565 DCHECK(MessageLoop::current() == io_loop_);
[email protected]fbb2b7a2008-11-18 22:54:04566 if (!enabled_)
567 return;
[email protected]613a03b2008-10-24 23:02:00568
569 database_loaded_ = true;
570
571 // TODO(paulg): More robust database initialization error handling.
572 if (protocol_manager_ && !database_error)
573 protocol_manager_->Initialize();
574
575 // If we have any queued requests, we can now check them.
576 if (!resetting_)
577 RunQueuedClients();
578}
579
initial.commit09911bf2008-07-26 23:55:29580// static
[email protected]919d77f02009-01-06 19:48:35581void SafeBrowsingService::RegisterPrefs(PrefService* prefs) {
initial.commit09911bf2008-07-26 23:55:29582 prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, L"");
583 prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, L"");
584}
585
586void SafeBrowsingService::ResetDatabase() {
587 DCHECK(MessageLoop::current() == io_loop_);
588 resetting_ = true;
589 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
590 this, &SafeBrowsingService::OnResetDatabase));
591}
592
593void SafeBrowsingService::OnResetDatabase() {
594 DCHECK(MessageLoop::current() == db_thread_->message_loop());
595 GetDatabase()->ResetDatabase();
596 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
597 this, &SafeBrowsingService::OnResetComplete));
598}
599
600void SafeBrowsingService::OnResetComplete() {
601 DCHECK(MessageLoop::current() == io_loop_);
[email protected]fbb2b7a2008-11-18 22:54:04602 if (enabled_) {
603 resetting_ = false;
604 database_loaded_ = true;
605 RunQueuedClients();
606 }
initial.commit09911bf2008-07-26 23:55:29607}
608
609void SafeBrowsingService::HandleChunk(const std::string& list,
610 std::deque<SBChunk>* chunks) {
611 DCHECK(MessageLoop::current() == io_loop_);
612 DCHECK(enabled_);
613 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
614 this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks));
615}
616
617void SafeBrowsingService::HandleChunkForDatabase(
618 const std::string& list_name,
619 std::deque<SBChunk>* chunks) {
620 DCHECK(MessageLoop::current() == db_thread_->message_loop());
621
622 GetDatabase()->InsertChunks(list_name, chunks);
623}
624
625void SafeBrowsingService::HandleChunkDelete(
626 std::vector<SBChunkDelete>* chunk_deletes) {
627 DCHECK(MessageLoop::current() == io_loop_);
628 DCHECK(enabled_);
629 db_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
630 this, &SafeBrowsingService::DeleteChunks, chunk_deletes));
631}
632
633void SafeBrowsingService::DeleteChunks(
634 std::vector<SBChunkDelete>* chunk_deletes) {
635 DCHECK(MessageLoop::current() == db_thread_->message_loop());
636
637 GetDatabase()->DeleteChunks(chunk_deletes);
638}
639
640// Database worker function.
641void SafeBrowsingService::GetAllChunksFromDatabase() {
642 DCHECK(MessageLoop::current() == db_thread_->message_loop());
[email protected]a5a37522008-11-11 21:49:56643 bool database_error = true;
initial.commit09911bf2008-07-26 23:55:29644 std::vector<SBListChunkRanges> lists;
[email protected]53ad8572008-11-13 21:50:34645 if (GetDatabase()) {
646 if (GetDatabase()->UpdateStarted()) {
647 GetDatabase()->GetListsInfo(&lists);
648 database_error = false;
649 } else {
650 GetDatabase()->UpdateFinished(false);
651 }
initial.commit09911bf2008-07-26 23:55:29652 }
653
654 io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
655 this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists,
656 database_error));
657}
658
659// Called on the io thread with the results of all chunks.
660void SafeBrowsingService::OnGetAllChunksFromDatabase(
661 const std::vector<SBListChunkRanges>& lists, bool database_error) {
662 DCHECK(MessageLoop::current() == io_loop_);
[email protected]fbb2b7a2008-11-18 22:54:04663 if (enabled_)
664 protocol_manager_->OnGetChunksComplete(lists, database_error);
initial.commit09911bf2008-07-26 23:55:29665}
666
667SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
668 const std::string& list_name) {
669 if (safe_browsing_util::IsPhishingList(list_name)) {
670 return URL_PHISHING;
671 }
672
673 if (safe_browsing_util::IsMalwareList(list_name)) {
674 return URL_MALWARE;
675 }
676
677 SB_DLOG(INFO) << "Unknown safe browsing list " << list_name;
678 return URL_SAFE;
679}
680
initial.commit09911bf2008-07-26 23:55:29681void SafeBrowsingService::LogPauseDelay(TimeDelta time) {
[email protected]fc76de12008-11-14 01:51:18682 if (new_safe_browsing_)
683 UMA_HISTOGRAM_LONG_TIMES(L"SB2.Delay", time);
684 else
685 UMA_HISTOGRAM_LONG_TIMES(L"SB.Delay", time);
initial.commit09911bf2008-07-26 23:55:29686}
687
688void SafeBrowsingService::CacheHashResults(
[email protected]200abc32008-09-05 01:44:33689 const std::vector<SBPrefix>& prefixes,
initial.commit09911bf2008-07-26 23:55:29690 const std::vector<SBFullHashResult>& full_hashes) {
691 DCHECK(MessageLoop::current() == db_thread_->message_loop());
[email protected]200abc32008-09-05 01:44:33692 GetDatabase()->CacheHashResults(prefixes, full_hashes);
initial.commit09911bf2008-07-26 23:55:29693}
694
[email protected]0a3076572008-12-13 20:48:36695void SafeBrowsingService::OnSuspend(base::SystemMonitor*) {
initial.commit09911bf2008-07-26 23:55:29696}
697
698// Tell the SafeBrowsing database not to do expensive disk operations for a few
699// minutes after waking up. It's quite likely that the act of resuming from a
700// low power state will involve much disk activity, which we don't want to
701// exacerbate.
[email protected]0a3076572008-12-13 20:48:36702void SafeBrowsingService::OnResume(base::SystemMonitor*) {
initial.commit09911bf2008-07-26 23:55:29703 if (enabled_) {
[email protected]0a3076572008-12-13 20:48:36704 ChromeThread::GetMessageLoop(ChromeThread::DB)->PostTask(FROM_HERE,
705 NewRunnableMethod(this, &SafeBrowsingService::HandleResume));
initial.commit09911bf2008-07-26 23:55:29706 }
707}
708
709void SafeBrowsingService::HandleResume() {
710 DCHECK(MessageLoop::current() == db_thread_->message_loop());
[email protected]53ad8572008-11-13 21:50:34711 // We don't call GetDatabase() here, since we want to avoid unnecessary calls
712 // to Open, Reset, etc, or reload the bloom filter while we're coming out of
713 // a suspended state.
714 if (database_)
715 database_->HandleResume();
license.botbf09a502008-08-24 00:55:55716}
[email protected]613a03b2008-10-24 23:02:00717
718void SafeBrowsingService::RunQueuedClients() {
719 DCHECK(MessageLoop::current() == io_loop_);
720 HISTOGRAM_COUNTS(L"SB.QueueDepth", queued_checks_.size());
721 while (!queued_checks_.empty()) {
722 QueuedCheck check = queued_checks_.front();
723 HISTOGRAM_TIMES(L"SB.QueueDelay", Time::Now() - check.start);
724 CheckUrl(check.url, check.client);
725 queued_checks_.pop_front();
726 }
727}
728