blob: 2dddb60660e21a5113d623f15624fbbef257880b [file] [log] [blame]
[email protected]4d9ae4a2009-10-01 17:59:381// Copyright (c) 2009 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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"
[email protected]51065cb2009-02-19 00:25:2317#include "chrome/browser/safe_browsing/protocol_manager.h"
[email protected]5b7c7d3c2009-02-19 00:06:2218#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
initial.commit09911bf2008-07-26 23:55:2919#include "chrome/browser/safe_browsing/safe_browsing_database.h"
[email protected]dfdb0de72009-02-19 21:58:1420#include "chrome/browser/tab_contents/navigation_entry.h"
[email protected]f3ec7742009-01-15 00:59:1621#include "chrome/browser/tab_contents/tab_util.h"
[email protected]57c6a652009-05-04 07:58:3422#include "chrome/browser/tab_contents/tab_contents.h"
initial.commit09911bf2008-07-26 23:55:2923#include "chrome/common/chrome_constants.h"
24#include "chrome/common/chrome_paths.h"
initial.commit09911bf2008-07-26 23:55:2925#include "chrome/common/pref_names.h"
26#include "chrome/common/pref_service.h"
[email protected]dcf7d352009-02-26 01:56:0227#include "chrome/common/url_constants.h"
initial.commit09911bf2008-07-26 23:55:2928#include "net/base/registry_controlled_domain.h"
29
[email protected]e1acf6f2008-10-27 20:43:3330using base::Time;
31using base::TimeDelta;
32
initial.commit09911bf2008-07-26 23:55:2933SafeBrowsingService::SafeBrowsingService()
[email protected]d83d03aa2009-11-02 21:44:3734 : database_(NULL),
initial.commit09911bf2008-07-26 23:55:2935 protocol_manager_(NULL),
36 enabled_(false),
[email protected]613a03b2008-10-24 23:02:0037 resetting_(false),
[email protected]57119c3f2008-12-04 00:33:0438 database_loaded_(false),
39 update_in_progress_(false) {
initial.commit09911bf2008-07-26 23:55:2940}
41
42SafeBrowsingService::~SafeBrowsingService() {
initial.commit09911bf2008-07-26 23:55:2943}
44
45// Only called on the UI thread.
[email protected]d83d03aa2009-11-02 21:44:3746void SafeBrowsingService::Initialize() {
initial.commit09911bf2008-07-26 23:55:2947 // Get the profile's preference for SafeBrowsing.
[email protected]c870c762009-01-28 05:47:1548 FilePath user_data_dir;
initial.commit09911bf2008-07-26 23:55:2949 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
50 ProfileManager* profile_manager = g_browser_process->profile_manager();
[email protected]f7011fcb2009-01-28 21:54:3251 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
initial.commit09911bf2008-07-26 23:55:2952 PrefService* pref_service = profile->GetPrefs();
53 if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled))
54 Start();
55}
56
57// Start up SafeBrowsing objects. This can be called at browser start, or when
58// the user checks the "Enable SafeBrowsing" option in the Advanced options UI.
59void SafeBrowsingService::Start() {
[email protected]f3724ea2009-05-08 22:09:5660 DCHECK(!safe_browsing_thread_.get());
61 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
62 if (!safe_browsing_thread_->Start())
initial.commit09911bf2008-07-26 23:55:2963 return;
64
initial.commit09911bf2008-07-26 23:55:2965 // Retrieve client MAC keys.
66 PrefService* local_state = g_browser_process->local_state();
67 std::string client_key, wrapped_key;
68 if (local_state) {
69 client_key =
70 WideToASCII(local_state->GetString(prefs::kSafeBrowsingClientKey));
71 wrapped_key =
72 WideToASCII(local_state->GetString(prefs::kSafeBrowsingWrappedKey));
73 }
74
[email protected]d83d03aa2009-11-02 21:44:3775 ChromeThread::PostTask(
76 ChromeThread::IO, FROM_HERE,
77 NewRunnableMethod(
78 this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key));
[email protected]2c2fb222008-12-17 02:35:4679
[email protected]f3724ea2009-05-08 22:09:5680 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]2c2fb222008-12-17 02:35:4681 this, &SafeBrowsingService::OnDBInitialize));
initial.commit09911bf2008-07-26 23:55:2982}
83
84void SafeBrowsingService::ShutDown() {
[email protected]d83d03aa2009-11-02 21:44:3785 ChromeThread::PostTask(
86 ChromeThread::IO, FROM_HERE,
87 NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown));
initial.commit09911bf2008-07-26 23:55:2988}
89
[email protected]d83d03aa2009-11-02 21:44:3790void SafeBrowsingService::OnIOInitialize(const std::string& client_key,
initial.commit09911bf2008-07-26 23:55:2991 const std::string& wrapped_key) {
[email protected]d83d03aa2009-11-02 21:44:3792 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:2993 enabled_ = true;
94 protocol_manager_ = new SafeBrowsingProtocolManager(this,
initial.commit09911bf2008-07-26 23:55:2995 client_key,
96 wrapped_key);
[email protected]613a03b2008-10-24 23:02:0097 // We want to initialize the protocol manager only after the database has
98 // loaded, which we'll receive asynchronously (DatabaseLoadComplete). If
99 // database_loaded_ isn't true, we'll wait for that notification to do the
100 // init.
101 if (database_loaded_)
102 protocol_manager_->Initialize();
initial.commit09911bf2008-07-26 23:55:29103}
104
105void SafeBrowsingService::OnDBInitialize() {
[email protected]f3724ea2009-05-08 22:09:56106 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29107 GetDatabase();
108}
109
110void SafeBrowsingService::OnIOShutdown() {
[email protected]d83d03aa2009-11-02 21:44:37111 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29112 if (!enabled_)
113 return;
114
115 enabled_ = false;
[email protected]fbb2b7a2008-11-18 22:54:04116 resetting_ = false;
initial.commit09911bf2008-07-26 23:55:29117
118 // This cancels all in-flight GetHash requests.
119 delete protocol_manager_;
[email protected]fbb2b7a2008-11-18 22:54:04120 protocol_manager_ = NULL;
initial.commit09911bf2008-07-26 23:55:29121
[email protected]f3724ea2009-05-08 22:09:56122 if (safe_browsing_thread_.get())
123 safe_browsing_thread_->message_loop()->DeleteSoon(FROM_HERE, database_);
initial.commit09911bf2008-07-26 23:55:29124
125 // Flush the database thread. Any in-progress database check results will be
126 // ignored and cleaned up below.
[email protected]f3724ea2009-05-08 22:09:56127 safe_browsing_thread_.reset(NULL);
initial.commit09911bf2008-07-26 23:55:29128
129 database_ = NULL;
[email protected]fbb2b7a2008-11-18 22:54:04130 database_loaded_ = false;
initial.commit09911bf2008-07-26 23:55:29131
[email protected]613a03b2008-10-24 23:02:00132 // Delete queued and pending checks once the database thread is done, calling
133 // back any clients with 'URL_SAFE'.
134 while (!queued_checks_.empty()) {
135 QueuedCheck check = queued_checks_.front();
136 if (check.client)
137 check.client->OnUrlCheckResult(check.url, URL_SAFE);
138 queued_checks_.pop_front();
139 }
140
initial.commit09911bf2008-07-26 23:55:29141 for (CurrentChecks::iterator it = checks_.begin();
142 it != checks_.end(); ++it) {
143 if ((*it)->client)
144 (*it)->client->OnUrlCheckResult((*it)->url, URL_SAFE);
145 delete *it;
146 }
147 checks_.clear();
148
149 gethash_requests_.clear();
150}
151
152// Runs on the UI thread.
153void SafeBrowsingService::OnEnable(bool enabled) {
154 if (enabled)
155 Start();
156 else
157 ShutDown();
158}
159
160bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
[email protected]dcf7d352009-02-26 01:56:02161 return url.SchemeIs(chrome::kHttpScheme) ||
162 url.SchemeIs(chrome::kHttpsScheme);
initial.commit09911bf2008-07-26 23:55:29163}
164
165bool SafeBrowsingService::CheckUrl(const GURL& url, Client* client) {
[email protected]d83d03aa2009-11-02 21:44:37166 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29167 if (!enabled_ || !database_)
168 return true;
169
[email protected]613a03b2008-10-24 23:02:00170 if (resetting_ || !database_loaded_) {
171 QueuedCheck check;
172 check.client = client;
173 check.url = url;
174 queued_checks_.push_back(check);
175 return false;
176 }
177
178 std::string list;
179 std::vector<SBPrefix> prefix_hits;
180 std::vector<SBFullHashResult> full_hits;
[email protected]22573822008-11-14 00:40:47181 base::Time check_start = base::Time::Now();
[email protected]c3ff89492008-11-11 02:17:51182 bool prefix_match = database_->ContainsUrl(url, &list, &prefix_hits,
183 &full_hits,
[email protected]613a03b2008-10-24 23:02:00184 protocol_manager_->last_update());
[email protected]f0a51fb52009-03-05 12:46:38185
[email protected]553dba62009-02-24 19:08:23186 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::Time::Now() - check_start);
[email protected]22573822008-11-14 00:40:47187
[email protected]613a03b2008-10-24 23:02:00188 if (!prefix_match)
189 return true; // URL is okay.
190
191 // Needs to be asynchronous, since we could be in the constructor of a
192 // ResourceDispatcherHost event handler which can't pause there.
193 SafeBrowsingCheck* check = new SafeBrowsingCheck();
194 check->url = url;
195 check->client = client;
196 check->result = URL_SAFE;
[email protected]613a03b2008-10-24 23:02:00197 check->need_get_hash = full_hits.empty();
198 check->prefix_hits.swap(prefix_hits);
199 check->full_hits.swap(full_hits);
200 checks_.insert(check);
201
[email protected]d83d03aa2009-11-02 21:44:37202 ChromeThread::PostTask(
203 ChromeThread::IO, FROM_HERE,
204 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
[email protected]613a03b2008-10-24 23:02:00205
initial.commit09911bf2008-07-26 23:55:29206 return false;
207}
208
209void SafeBrowsingService::DisplayBlockingPage(const GURL& url,
210 ResourceType::Type resource_type,
211 UrlCheckResult result,
212 Client* client,
213 MessageLoop* ui_loop,
214 int render_process_host_id,
215 int render_view_id) {
216 // Check if the user has already ignored our warning for this render_view
217 // and domain.
218 for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
219 const WhiteListedEntry& entry = white_listed_entries_[i];
220 if (entry.render_process_host_id == render_process_host_id &&
221 entry.render_view_id == render_view_id &&
222 entry.result == result &&
223 entry.domain ==
[email protected]8ac1a752008-07-31 19:40:37224 net::RegistryControlledDomainService::GetDomainAndRegistry(url)) {
initial.commit09911bf2008-07-26 23:55:29225 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
226 this, &SafeBrowsingService::NotifyClientBlockingComplete,
227 client, true));
228 return;
229 }
230 }
231
[email protected]1b277e72009-01-23 21:05:34232 UnsafeResource resource;
233 resource.url = url;
234 resource.resource_type = resource_type;
235 resource.threat_type= result;
236 resource.client = client;
237 resource.render_process_host_id = render_process_host_id;
238 resource.render_view_id = render_view_id;
[email protected]484c57a2009-03-21 01:24:01239
[email protected]cbab76d2008-10-13 22:42:47240 // The blocking page must be created from the UI thread.
241 ui_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
242 &SafeBrowsingService::DoDisplayBlockingPage,
[email protected]1b277e72009-01-23 21:05:34243 resource));
[email protected]cbab76d2008-10-13 22:42:47244}
245
246// Invoked on the UI thread.
247void SafeBrowsingService::DoDisplayBlockingPage(
[email protected]1b277e72009-01-23 21:05:34248 const UnsafeResource& resource) {
[email protected]a3a1d142008-12-19 00:42:30249 // The tab might have been closed.
[email protected]57c6a652009-05-04 07:58:34250 TabContents* wc =
251 tab_util::GetTabContentsByID(resource.render_process_host_id,
[email protected]dfdb0de72009-02-19 21:58:14252 resource.render_view_id);
253
254 if (!wc) {
[email protected]a3a1d142008-12-19 00:42:30255 // The tab is gone and we did not have a chance at showing the interstitial.
256 // Just act as "Don't Proceed" was chosen.
[email protected]1b277e72009-01-23 21:05:34257 std::vector<UnsafeResource> resources;
258 resources.push_back(resource);
[email protected]6fad2632009-11-02 05:59:37259 ChromeThread::PostTask(
260 ChromeThread::IO, FROM_HERE,
261 NewRunnableMethod(
262 this, &SafeBrowsingService::OnBlockingPageDone, resources, false));
[email protected]a3a1d142008-12-19 00:42:30263 return;
264 }
[email protected]dfdb0de72009-02-19 21:58:14265
266 // Report the malware sub-resource to the SafeBrowsing servers if we have a
267 // malware sub-resource on a safe page and only if the user has opted in to
268 // reporting statistics.
269 PrefService* prefs = g_browser_process->local_state();
270 DCHECK(prefs);
271 if (prefs && prefs->GetBoolean(prefs::kMetricsReportingEnabled) &&
272 resource.resource_type != ResourceType::MAIN_FRAME &&
273 resource.threat_type == SafeBrowsingService::URL_MALWARE) {
274 GURL page_url = wc->GetURL();
275 GURL referrer_url;
[email protected]ce3fa3c2009-04-20 19:55:57276 NavigationEntry* entry = wc->controller().GetActiveEntry();
277 if (entry)
278 referrer_url = entry->referrer();
[email protected]d83d03aa2009-11-02 21:44:37279 ChromeThread::PostTask(
280 ChromeThread::IO, FROM_HERE,
[email protected]dfdb0de72009-02-19 21:58:14281 NewRunnableMethod(this,
282 &SafeBrowsingService::ReportMalware,
283 resource.url,
284 page_url,
285 referrer_url));
286 }
287
[email protected]1b277e72009-01-23 21:05:34288 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
initial.commit09911bf2008-07-26 23:55:29289}
290
291void SafeBrowsingService::CancelCheck(Client* client) {
[email protected]d83d03aa2009-11-02 21:44:37292 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29293
294 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
295 if ((*i)->client == client)
296 (*i)->client = NULL;
297 }
[email protected]613a03b2008-10-24 23:02:00298
299 // Scan the queued clients store. Clients may be here if they requested a URL
300 // check before the database has finished loading or resetting.
301 if (!database_loaded_ || resetting_) {
302 std::deque<QueuedCheck>::iterator it = queued_checks_.begin();
303 for (; it != queued_checks_.end(); ++it) {
304 if (it->client == client)
305 it->client = NULL;
306 }
307 }
initial.commit09911bf2008-07-26 23:55:29308}
309
[email protected]613a03b2008-10-24 23:02:00310void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
[email protected]d83d03aa2009-11-02 21:44:37311 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29312
313 // If we've been shutdown during the database lookup, this check will already
314 // have been deleted (in OnIOShutdown).
[email protected]613a03b2008-10-24 23:02:00315 if (!enabled_ || checks_.find(check) == checks_.end())
initial.commit09911bf2008-07-26 23:55:29316 return;
317
[email protected]613a03b2008-10-24 23:02:00318 if (check->client && check->need_get_hash) {
initial.commit09911bf2008-07-26 23:55:29319 // We have a partial match so we need to query Google for the full hash.
320 // Clean up will happen in HandleGetHashResults.
321
322 // See if we have a GetHash request already in progress for this particular
323 // prefix. If so, we just append ourselves to the list of interested parties
324 // when the results arrive. We only do this for checks involving one prefix,
325 // since that is the common case (multiple prefixes will issue the request
326 // as normal).
[email protected]613a03b2008-10-24 23:02:00327 if (check->prefix_hits.size() == 1) {
328 SBPrefix prefix = check->prefix_hits[0];
initial.commit09911bf2008-07-26 23:55:29329 GetHashRequests::iterator it = gethash_requests_.find(prefix);
330 if (it != gethash_requests_.end()) {
331 // There's already a request in progress.
[email protected]613a03b2008-10-24 23:02:00332 it->second.push_back(check);
initial.commit09911bf2008-07-26 23:55:29333 return;
334 }
335
336 // No request in progress, so we're the first for this prefix.
337 GetHashRequestors requestors;
[email protected]613a03b2008-10-24 23:02:00338 requestors.push_back(check);
initial.commit09911bf2008-07-26 23:55:29339 gethash_requests_[prefix] = requestors;
340 }
341
342 // Reset the start time so that we can measure the network time without the
343 // database time.
[email protected]613a03b2008-10-24 23:02:00344 check->start = Time::Now();
345 protocol_manager_->GetFullHash(check, check->prefix_hits);
initial.commit09911bf2008-07-26 23:55:29346 } else {
347 // We may have cached results for previous GetHash queries.
[email protected]613a03b2008-10-24 23:02:00348 HandleOneCheck(check, check->full_hits);
initial.commit09911bf2008-07-26 23:55:29349 }
350}
351
352SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
[email protected]f3724ea2009-05-08 22:09:56353 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29354 if (database_)
355 return database_;
356
[email protected]c870c762009-01-28 05:47:15357 FilePath path;
initial.commit09911bf2008-07-26 23:55:29358 bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
359 DCHECK(result);
[email protected]c870c762009-01-28 05:47:15360 path = path.Append(chrome::kSafeBrowsingFilename);
initial.commit09911bf2008-07-26 23:55:29361
362 Time before = Time::Now();
[email protected]54d80bb02008-09-20 02:03:08363 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create();
[email protected]613a03b2008-10-24 23:02:00364 Callback0::Type* chunk_callback =
initial.commit09911bf2008-07-26 23:55:29365 NewCallback(this, &SafeBrowsingService::ChunkInserted);
[email protected]93e6efa32009-10-12 21:43:37366 database->Init(path, chunk_callback);
367 database_ = database;
[email protected]613a03b2008-10-24 23:02:00368
[email protected]d83d03aa2009-11-02 21:44:37369 ChromeThread::PostTask(
370 ChromeThread::IO, FROM_HERE,
371 NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete));
initial.commit09911bf2008-07-26 23:55:29372
373 TimeDelta open_time = Time::Now() - before;
374 SB_DLOG(INFO) << "SafeBrowsing database open took " <<
375 open_time.InMilliseconds() << " ms.";
376
377 return database_;
378}
379
380// Public API called only on the IO thread.
381// The SafeBrowsingProtocolManager has received the full hash results for
382// prefix hits detected in the database.
383void SafeBrowsingService::HandleGetHashResults(
384 SafeBrowsingCheck* check,
[email protected]200abc32008-09-05 01:44:33385 const std::vector<SBFullHashResult>& full_hashes,
386 bool can_cache) {
initial.commit09911bf2008-07-26 23:55:29387 if (checks_.find(check) == checks_.end())
388 return;
389
390 DCHECK(enabled_);
391
[email protected]484c57a2009-03-21 01:24:01392 UMA_HISTOGRAM_LONG_TIMES("SB2.Network", Time::Now() - check->start);
[email protected]22573822008-11-14 00:40:47393
[email protected]200abc32008-09-05 01:44:33394 std::vector<SBPrefix> prefixes = check->prefix_hits;
initial.commit09911bf2008-07-26 23:55:29395 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
396
[email protected]484c57a2009-03-21 01:24:01397 if (can_cache && database_) {
398 // Cache the GetHash results in memory:
399 database_->CacheHashResults(prefixes, full_hashes);
[email protected]613a03b2008-10-24 23:02:00400 }
initial.commit09911bf2008-07-26 23:55:29401}
402
403void SafeBrowsingService::OnHandleGetHashResults(
404 SafeBrowsingCheck* check,
405 const std::vector<SBFullHashResult>& full_hashes) {
406 SBPrefix prefix = check->prefix_hits[0];
407 GetHashRequests::iterator it = gethash_requests_.find(prefix);
408 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
409 HandleOneCheck(check, full_hashes);
410 return;
411 }
412
413 // Call back all interested parties.
414 GetHashRequestors& requestors = it->second;
415 for (GetHashRequestors::iterator r = requestors.begin();
416 r != requestors.end(); ++r) {
417 HandleOneCheck(*r, full_hashes);
418 }
419
420 gethash_requests_.erase(it);
421}
422
423void SafeBrowsingService::HandleOneCheck(
424 SafeBrowsingCheck* check,
425 const std::vector<SBFullHashResult>& full_hashes) {
426 if (check->client) {
427 UrlCheckResult result = URL_SAFE;
428 int index = safe_browsing_util::CompareFullHashes(check->url, full_hashes);
[email protected]09d985f2009-05-11 21:59:58429 if (index != -1) {
initial.commit09911bf2008-07-26 23:55:29430 result = GetResultFromListname(full_hashes[index].list_name);
[email protected]09d985f2009-05-11 21:59:58431 } else {
432 // Log the case where the SafeBrowsing servers return full hashes in the
433 // GetHash response that match the prefix we're looking up, but don't
434 // match the full hash of the URL.
435 if (!full_hashes.empty())
436 UMA_HISTOGRAM_COUNTS("SB2.GetHashServerMiss", 1);
437 }
initial.commit09911bf2008-07-26 23:55:29438
439 // Let the client continue handling the original request.
440 check->client->OnUrlCheckResult(check->url, result);
441 }
442
443 checks_.erase(check);
444 delete check;
445}
446
[email protected]57119c3f2008-12-04 00:33:04447void SafeBrowsingService::UpdateStarted() {
[email protected]d83d03aa2009-11-02 21:44:37448 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29449 DCHECK(enabled_);
[email protected]57119c3f2008-12-04 00:33:04450 DCHECK(!update_in_progress_);
451 update_in_progress_ = true;
[email protected]f3724ea2009-05-08 22:09:56452 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29453 this, &SafeBrowsingService::GetAllChunksFromDatabase));
454}
455
[email protected]613a03b2008-10-24 23:02:00456void SafeBrowsingService::UpdateFinished(bool update_succeeded) {
[email protected]d83d03aa2009-11-02 21:44:37457 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]aad08752008-10-02 22:13:41458 DCHECK(enabled_);
[email protected]57119c3f2008-12-04 00:33:04459 if (update_in_progress_) {
460 update_in_progress_ = false;
[email protected]f3724ea2009-05-08 22:09:56461 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
462 NewRunnableMethod(this,
463 &SafeBrowsingService::DatabaseUpdateFinished,
464 update_succeeded));
[email protected]57119c3f2008-12-04 00:33:04465 }
[email protected]aad08752008-10-02 22:13:41466}
467
[email protected]613a03b2008-10-24 23:02:00468void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
[email protected]f3724ea2009-05-08 22:09:56469 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]aad08752008-10-02 22:13:41470 if (GetDatabase())
[email protected]613a03b2008-10-24 23:02:00471 GetDatabase()->UpdateFinished(update_succeeded);
[email protected]aad08752008-10-02 22:13:41472}
473
[email protected]1b277e72009-01-23 21:05:34474void SafeBrowsingService::OnBlockingPageDone(
475 const std::vector<UnsafeResource>& resources,
476 bool proceed) {
477 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
478 iter != resources.end(); ++iter) {
479 const UnsafeResource& resource = *iter;
480 NotifyClientBlockingComplete(resource.client, proceed);
initial.commit09911bf2008-07-26 23:55:29481
[email protected]1b277e72009-01-23 21:05:34482 if (proceed) {
483 // Whitelist this domain and warning type for the given tab.
484 WhiteListedEntry entry;
485 entry.render_process_host_id = resource.render_process_host_id;
486 entry.render_view_id = resource.render_view_id;
487 entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry(
488 resource.url);
489 entry.result = resource.threat_type;
490 white_listed_entries_.push_back(entry);
491 }
initial.commit09911bf2008-07-26 23:55:29492 }
initial.commit09911bf2008-07-26 23:55:29493}
494
495void SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
496 bool proceed) {
497 client->OnBlockingPageComplete(proceed);
498}
499
500// This method runs on the UI loop to access the prefs.
501void SafeBrowsingService::OnNewMacKeys(const std::string& client_key,
502 const std::string& wrapped_key) {
503 PrefService* prefs = g_browser_process->local_state();
504 if (prefs) {
505 prefs->SetString(prefs::kSafeBrowsingClientKey, ASCIIToWide(client_key));
506 prefs->SetString(prefs::kSafeBrowsingWrappedKey, ASCIIToWide(wrapped_key));
507 }
508}
509
510void SafeBrowsingService::ChunkInserted() {
[email protected]f3724ea2009-05-08 22:09:56511 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]d83d03aa2009-11-02 21:44:37512 ChromeThread::PostTask(
513 ChromeThread::IO, FROM_HERE,
514 NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted));
initial.commit09911bf2008-07-26 23:55:29515}
516
517void SafeBrowsingService::OnChunkInserted() {
[email protected]d83d03aa2009-11-02 21:44:37518 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04519 if (enabled_)
520 protocol_manager_->OnChunkInserted();
initial.commit09911bf2008-07-26 23:55:29521}
522
[email protected]93e6efa32009-10-12 21:43:37523void SafeBrowsingService::DatabaseLoadComplete() {
[email protected]d83d03aa2009-11-02 21:44:37524 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04525 if (!enabled_)
526 return;
[email protected]613a03b2008-10-24 23:02:00527
528 database_loaded_ = true;
529
[email protected]93e6efa32009-10-12 21:43:37530 if (protocol_manager_)
[email protected]613a03b2008-10-24 23:02:00531 protocol_manager_->Initialize();
532
533 // If we have any queued requests, we can now check them.
534 if (!resetting_)
535 RunQueuedClients();
536}
537
initial.commit09911bf2008-07-26 23:55:29538// static
[email protected]919d77f02009-01-06 19:48:35539void SafeBrowsingService::RegisterPrefs(PrefService* prefs) {
initial.commit09911bf2008-07-26 23:55:29540 prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, L"");
541 prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, L"");
542}
543
544void SafeBrowsingService::ResetDatabase() {
[email protected]d83d03aa2009-11-02 21:44:37545 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29546 resetting_ = true;
[email protected]f3724ea2009-05-08 22:09:56547 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29548 this, &SafeBrowsingService::OnResetDatabase));
549}
550
551void SafeBrowsingService::OnResetDatabase() {
[email protected]f3724ea2009-05-08 22:09:56552 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29553 GetDatabase()->ResetDatabase();
[email protected]d83d03aa2009-11-02 21:44:37554 ChromeThread::PostTask(
555 ChromeThread::IO, FROM_HERE,
556 NewRunnableMethod(this, &SafeBrowsingService::OnResetComplete));
initial.commit09911bf2008-07-26 23:55:29557}
558
559void SafeBrowsingService::OnResetComplete() {
[email protected]d83d03aa2009-11-02 21:44:37560 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04561 if (enabled_) {
562 resetting_ = false;
563 database_loaded_ = true;
564 RunQueuedClients();
565 }
initial.commit09911bf2008-07-26 23:55:29566}
567
568void SafeBrowsingService::HandleChunk(const std::string& list,
569 std::deque<SBChunk>* chunks) {
[email protected]d83d03aa2009-11-02 21:44:37570 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29571 DCHECK(enabled_);
[email protected]f3724ea2009-05-08 22:09:56572 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29573 this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks));
574}
575
576void SafeBrowsingService::HandleChunkForDatabase(
577 const std::string& list_name,
578 std::deque<SBChunk>* chunks) {
[email protected]f3724ea2009-05-08 22:09:56579 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29580
581 GetDatabase()->InsertChunks(list_name, chunks);
582}
583
584void SafeBrowsingService::HandleChunkDelete(
585 std::vector<SBChunkDelete>* chunk_deletes) {
[email protected]d83d03aa2009-11-02 21:44:37586 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29587 DCHECK(enabled_);
[email protected]f3724ea2009-05-08 22:09:56588 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29589 this, &SafeBrowsingService::DeleteChunks, chunk_deletes));
590}
591
592void SafeBrowsingService::DeleteChunks(
593 std::vector<SBChunkDelete>* chunk_deletes) {
[email protected]f3724ea2009-05-08 22:09:56594 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29595
596 GetDatabase()->DeleteChunks(chunk_deletes);
597}
598
599// Database worker function.
600void SafeBrowsingService::GetAllChunksFromDatabase() {
[email protected]f3724ea2009-05-08 22:09:56601 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]a5a37522008-11-11 21:49:56602 bool database_error = true;
initial.commit09911bf2008-07-26 23:55:29603 std::vector<SBListChunkRanges> lists;
[email protected]53ad8572008-11-13 21:50:34604 if (GetDatabase()) {
605 if (GetDatabase()->UpdateStarted()) {
606 GetDatabase()->GetListsInfo(&lists);
607 database_error = false;
608 } else {
609 GetDatabase()->UpdateFinished(false);
610 }
initial.commit09911bf2008-07-26 23:55:29611 }
612
[email protected]d83d03aa2009-11-02 21:44:37613 ChromeThread::PostTask(
614 ChromeThread::IO, FROM_HERE,
615 NewRunnableMethod(
616 this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists,
617 database_error));
initial.commit09911bf2008-07-26 23:55:29618}
619
620// Called on the io thread with the results of all chunks.
621void SafeBrowsingService::OnGetAllChunksFromDatabase(
622 const std::vector<SBListChunkRanges>& lists, bool database_error) {
[email protected]d83d03aa2009-11-02 21:44:37623 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04624 if (enabled_)
625 protocol_manager_->OnGetChunksComplete(lists, database_error);
initial.commit09911bf2008-07-26 23:55:29626}
627
628SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
629 const std::string& list_name) {
630 if (safe_browsing_util::IsPhishingList(list_name)) {
631 return URL_PHISHING;
632 }
633
634 if (safe_browsing_util::IsMalwareList(list_name)) {
635 return URL_MALWARE;
636 }
637
638 SB_DLOG(INFO) << "Unknown safe browsing list " << list_name;
639 return URL_SAFE;
640}
641
initial.commit09911bf2008-07-26 23:55:29642void SafeBrowsingService::LogPauseDelay(TimeDelta time) {
[email protected]484c57a2009-03-21 01:24:01643 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
initial.commit09911bf2008-07-26 23:55:29644}
645
646void SafeBrowsingService::CacheHashResults(
[email protected]200abc32008-09-05 01:44:33647 const std::vector<SBPrefix>& prefixes,
initial.commit09911bf2008-07-26 23:55:29648 const std::vector<SBFullHashResult>& full_hashes) {
[email protected]f3724ea2009-05-08 22:09:56649 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]200abc32008-09-05 01:44:33650 GetDatabase()->CacheHashResults(prefixes, full_hashes);
initial.commit09911bf2008-07-26 23:55:29651}
652
[email protected]613a03b2008-10-24 23:02:00653void SafeBrowsingService::RunQueuedClients() {
[email protected]d83d03aa2009-11-02 21:44:37654 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]553dba62009-02-24 19:08:23655 HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
[email protected]613a03b2008-10-24 23:02:00656 while (!queued_checks_.empty()) {
657 QueuedCheck check = queued_checks_.front();
[email protected]553dba62009-02-24 19:08:23658 HISTOGRAM_TIMES("SB.QueueDelay", Time::Now() - check.start);
[email protected]613a03b2008-10-24 23:02:00659 CheckUrl(check.url, check.client);
660 queued_checks_.pop_front();
661 }
662}
663
[email protected]dfdb0de72009-02-19 21:58:14664void SafeBrowsingService::ReportMalware(const GURL& malware_url,
665 const GURL& page_url,
666 const GURL& referrer_url) {
[email protected]d83d03aa2009-11-02 21:44:37667 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]dfdb0de72009-02-19 21:58:14668
[email protected]484c57a2009-03-21 01:24:01669 if (!enabled_ || !database_)
[email protected]dfdb0de72009-02-19 21:58:14670 return;
671
672 // Check if 'page_url' is already blacklisted (exists in our cache). Only
673 // report if it's not there.
674 std::string list;
675 std::vector<SBPrefix> prefix_hits;
676 std::vector<SBFullHashResult> full_hits;
677 database_->ContainsUrl(page_url, &list, &prefix_hits, &full_hits,
678 protocol_manager_->last_update());
679
680 if (full_hits.empty())
681 protocol_manager_->ReportMalware(malware_url, page_url, referrer_url);
682}