blob: b527a54c4562fe68d5b70a192925fdf55911e0a5 [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"
[email protected]1a871512009-11-06 06:11:1828#if defined(OS_WIN)
29#include "chrome/installer/util/browser_distribution.h"
30#endif
initial.commit09911bf2008-07-26 23:55:2931#include "net/base/registry_controlled_domain.h"
32
[email protected]e1acf6f2008-10-27 20:43:3333using base::Time;
34using base::TimeDelta;
35
initial.commit09911bf2008-07-26 23:55:2936SafeBrowsingService::SafeBrowsingService()
[email protected]d83d03aa2009-11-02 21:44:3737 : database_(NULL),
initial.commit09911bf2008-07-26 23:55:2938 protocol_manager_(NULL),
39 enabled_(false),
[email protected]613a03b2008-10-24 23:02:0040 resetting_(false),
[email protected]57119c3f2008-12-04 00:33:0441 database_loaded_(false),
42 update_in_progress_(false) {
initial.commit09911bf2008-07-26 23:55:2943}
44
45SafeBrowsingService::~SafeBrowsingService() {
initial.commit09911bf2008-07-26 23:55:2946}
47
48// Only called on the UI thread.
[email protected]d83d03aa2009-11-02 21:44:3749void SafeBrowsingService::Initialize() {
initial.commit09911bf2008-07-26 23:55:2950 // Get the profile's preference for SafeBrowsing.
[email protected]c870c762009-01-28 05:47:1551 FilePath user_data_dir;
initial.commit09911bf2008-07-26 23:55:2952 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
53 ProfileManager* profile_manager = g_browser_process->profile_manager();
[email protected]f7011fcb2009-01-28 21:54:3254 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
initial.commit09911bf2008-07-26 23:55:2955 PrefService* pref_service = profile->GetPrefs();
56 if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled))
57 Start();
58}
59
60// Start up SafeBrowsing objects. This can be called at browser start, or when
61// the user checks the "Enable SafeBrowsing" option in the Advanced options UI.
62void SafeBrowsingService::Start() {
[email protected]f3724ea2009-05-08 22:09:5663 DCHECK(!safe_browsing_thread_.get());
64 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
65 if (!safe_browsing_thread_->Start())
initial.commit09911bf2008-07-26 23:55:2966 return;
67
initial.commit09911bf2008-07-26 23:55:2968 // Retrieve client MAC keys.
69 PrefService* local_state = g_browser_process->local_state();
70 std::string client_key, wrapped_key;
71 if (local_state) {
72 client_key =
73 WideToASCII(local_state->GetString(prefs::kSafeBrowsingClientKey));
74 wrapped_key =
75 WideToASCII(local_state->GetString(prefs::kSafeBrowsingWrappedKey));
76 }
77
[email protected]d83d03aa2009-11-02 21:44:3778 ChromeThread::PostTask(
79 ChromeThread::IO, FROM_HERE,
80 NewRunnableMethod(
81 this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key));
[email protected]2c2fb222008-12-17 02:35:4682
[email protected]f3724ea2009-05-08 22:09:5683 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]2c2fb222008-12-17 02:35:4684 this, &SafeBrowsingService::OnDBInitialize));
initial.commit09911bf2008-07-26 23:55:2985}
86
87void SafeBrowsingService::ShutDown() {
[email protected]d83d03aa2009-11-02 21:44:3788 ChromeThread::PostTask(
89 ChromeThread::IO, FROM_HERE,
90 NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown));
initial.commit09911bf2008-07-26 23:55:2991}
92
[email protected]d83d03aa2009-11-02 21:44:3793void SafeBrowsingService::OnIOInitialize(const std::string& client_key,
initial.commit09911bf2008-07-26 23:55:2994 const std::string& wrapped_key) {
[email protected]d83d03aa2009-11-02 21:44:3795 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:2996 enabled_ = true;
[email protected]1a871512009-11-06 06:11:1897
98 // On Windows, get the safe browsing client name from the browser
99 // distribution classes in installer util. These classes don't yet have
100 // an analog on non-Windows builds so just keep the name specified here.
101#if defined(OS_WIN)
102 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
103 std::string client_name(dist->GetSafeBrowsingName());
104#else
105#if defined(GOOGLE_CHROME_BUILD)
106 std::string client_name("googlechrome");
107#else
108 std::string client_name("chromium");
109#endif
110#endif
111
initial.commit09911bf2008-07-26 23:55:29112 protocol_manager_ = new SafeBrowsingProtocolManager(this,
[email protected]1a871512009-11-06 06:11:18113 client_name,
initial.commit09911bf2008-07-26 23:55:29114 client_key,
115 wrapped_key);
[email protected]613a03b2008-10-24 23:02:00116 // We want to initialize the protocol manager only after the database has
117 // loaded, which we'll receive asynchronously (DatabaseLoadComplete). If
118 // database_loaded_ isn't true, we'll wait for that notification to do the
119 // init.
120 if (database_loaded_)
121 protocol_manager_->Initialize();
initial.commit09911bf2008-07-26 23:55:29122}
123
124void SafeBrowsingService::OnDBInitialize() {
[email protected]f3724ea2009-05-08 22:09:56125 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29126 GetDatabase();
127}
128
129void SafeBrowsingService::OnIOShutdown() {
[email protected]d83d03aa2009-11-02 21:44:37130 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29131 if (!enabled_)
132 return;
133
134 enabled_ = false;
[email protected]fbb2b7a2008-11-18 22:54:04135 resetting_ = false;
initial.commit09911bf2008-07-26 23:55:29136
137 // This cancels all in-flight GetHash requests.
138 delete protocol_manager_;
[email protected]fbb2b7a2008-11-18 22:54:04139 protocol_manager_ = NULL;
initial.commit09911bf2008-07-26 23:55:29140
[email protected]f3724ea2009-05-08 22:09:56141 if (safe_browsing_thread_.get())
142 safe_browsing_thread_->message_loop()->DeleteSoon(FROM_HERE, database_);
initial.commit09911bf2008-07-26 23:55:29143
144 // Flush the database thread. Any in-progress database check results will be
145 // ignored and cleaned up below.
[email protected]f3724ea2009-05-08 22:09:56146 safe_browsing_thread_.reset(NULL);
initial.commit09911bf2008-07-26 23:55:29147
148 database_ = NULL;
[email protected]fbb2b7a2008-11-18 22:54:04149 database_loaded_ = false;
initial.commit09911bf2008-07-26 23:55:29150
[email protected]613a03b2008-10-24 23:02:00151 // Delete queued and pending checks once the database thread is done, calling
152 // back any clients with 'URL_SAFE'.
153 while (!queued_checks_.empty()) {
154 QueuedCheck check = queued_checks_.front();
155 if (check.client)
156 check.client->OnUrlCheckResult(check.url, URL_SAFE);
157 queued_checks_.pop_front();
158 }
159
initial.commit09911bf2008-07-26 23:55:29160 for (CurrentChecks::iterator it = checks_.begin();
161 it != checks_.end(); ++it) {
162 if ((*it)->client)
163 (*it)->client->OnUrlCheckResult((*it)->url, URL_SAFE);
164 delete *it;
165 }
166 checks_.clear();
167
168 gethash_requests_.clear();
169}
170
171// Runs on the UI thread.
172void SafeBrowsingService::OnEnable(bool enabled) {
173 if (enabled)
174 Start();
175 else
176 ShutDown();
177}
178
179bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
[email protected]dcf7d352009-02-26 01:56:02180 return url.SchemeIs(chrome::kHttpScheme) ||
181 url.SchemeIs(chrome::kHttpsScheme);
initial.commit09911bf2008-07-26 23:55:29182}
183
184bool SafeBrowsingService::CheckUrl(const GURL& url, Client* client) {
[email protected]d83d03aa2009-11-02 21:44:37185 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29186 if (!enabled_ || !database_)
187 return true;
188
[email protected]613a03b2008-10-24 23:02:00189 if (resetting_ || !database_loaded_) {
190 QueuedCheck check;
191 check.client = client;
192 check.url = url;
193 queued_checks_.push_back(check);
194 return false;
195 }
196
197 std::string list;
198 std::vector<SBPrefix> prefix_hits;
199 std::vector<SBFullHashResult> full_hits;
[email protected]22573822008-11-14 00:40:47200 base::Time check_start = base::Time::Now();
[email protected]c3ff89492008-11-11 02:17:51201 bool prefix_match = database_->ContainsUrl(url, &list, &prefix_hits,
202 &full_hits,
[email protected]613a03b2008-10-24 23:02:00203 protocol_manager_->last_update());
[email protected]f0a51fb52009-03-05 12:46:38204
[email protected]553dba62009-02-24 19:08:23205 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::Time::Now() - check_start);
[email protected]22573822008-11-14 00:40:47206
[email protected]613a03b2008-10-24 23:02:00207 if (!prefix_match)
208 return true; // URL is okay.
209
210 // Needs to be asynchronous, since we could be in the constructor of a
211 // ResourceDispatcherHost event handler which can't pause there.
212 SafeBrowsingCheck* check = new SafeBrowsingCheck();
213 check->url = url;
214 check->client = client;
215 check->result = URL_SAFE;
[email protected]613a03b2008-10-24 23:02:00216 check->need_get_hash = full_hits.empty();
217 check->prefix_hits.swap(prefix_hits);
218 check->full_hits.swap(full_hits);
219 checks_.insert(check);
220
[email protected]d83d03aa2009-11-02 21:44:37221 ChromeThread::PostTask(
222 ChromeThread::IO, FROM_HERE,
223 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
[email protected]613a03b2008-10-24 23:02:00224
initial.commit09911bf2008-07-26 23:55:29225 return false;
226}
227
228void SafeBrowsingService::DisplayBlockingPage(const GURL& url,
229 ResourceType::Type resource_type,
230 UrlCheckResult result,
231 Client* client,
initial.commit09911bf2008-07-26 23:55:29232 int render_process_host_id,
233 int render_view_id) {
234 // Check if the user has already ignored our warning for this render_view
235 // and domain.
236 for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
237 const WhiteListedEntry& entry = white_listed_entries_[i];
238 if (entry.render_process_host_id == render_process_host_id &&
239 entry.render_view_id == render_view_id &&
240 entry.result == result &&
241 entry.domain ==
[email protected]8ac1a752008-07-31 19:40:37242 net::RegistryControlledDomainService::GetDomainAndRegistry(url)) {
initial.commit09911bf2008-07-26 23:55:29243 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
244 this, &SafeBrowsingService::NotifyClientBlockingComplete,
245 client, true));
246 return;
247 }
248 }
249
[email protected]1b277e72009-01-23 21:05:34250 UnsafeResource resource;
251 resource.url = url;
252 resource.resource_type = resource_type;
253 resource.threat_type= result;
254 resource.client = client;
255 resource.render_process_host_id = render_process_host_id;
256 resource.render_view_id = render_view_id;
[email protected]484c57a2009-03-21 01:24:01257
[email protected]cbab76d2008-10-13 22:42:47258 // The blocking page must be created from the UI thread.
[email protected]79084c2d2009-11-03 23:12:42259 ChromeThread::PostTask(
260 ChromeThread::UI, FROM_HERE,
261 NewRunnableMethod(
262 this, &SafeBrowsingService::DoDisplayBlockingPage, resource));
[email protected]cbab76d2008-10-13 22:42:47263}
264
265// Invoked on the UI thread.
266void SafeBrowsingService::DoDisplayBlockingPage(
[email protected]1b277e72009-01-23 21:05:34267 const UnsafeResource& resource) {
[email protected]a3a1d142008-12-19 00:42:30268 // The tab might have been closed.
[email protected]57c6a652009-05-04 07:58:34269 TabContents* wc =
270 tab_util::GetTabContentsByID(resource.render_process_host_id,
[email protected]dfdb0de72009-02-19 21:58:14271 resource.render_view_id);
272
273 if (!wc) {
[email protected]a3a1d142008-12-19 00:42:30274 // The tab is gone and we did not have a chance at showing the interstitial.
275 // Just act as "Don't Proceed" was chosen.
[email protected]1b277e72009-01-23 21:05:34276 std::vector<UnsafeResource> resources;
277 resources.push_back(resource);
[email protected]6fad2632009-11-02 05:59:37278 ChromeThread::PostTask(
279 ChromeThread::IO, FROM_HERE,
280 NewRunnableMethod(
281 this, &SafeBrowsingService::OnBlockingPageDone, resources, false));
[email protected]a3a1d142008-12-19 00:42:30282 return;
283 }
[email protected]dfdb0de72009-02-19 21:58:14284
285 // Report the malware sub-resource to the SafeBrowsing servers if we have a
286 // malware sub-resource on a safe page and only if the user has opted in to
287 // reporting statistics.
288 PrefService* prefs = g_browser_process->local_state();
289 DCHECK(prefs);
290 if (prefs && prefs->GetBoolean(prefs::kMetricsReportingEnabled) &&
291 resource.resource_type != ResourceType::MAIN_FRAME &&
292 resource.threat_type == SafeBrowsingService::URL_MALWARE) {
293 GURL page_url = wc->GetURL();
294 GURL referrer_url;
[email protected]ce3fa3c2009-04-20 19:55:57295 NavigationEntry* entry = wc->controller().GetActiveEntry();
296 if (entry)
297 referrer_url = entry->referrer();
[email protected]d83d03aa2009-11-02 21:44:37298 ChromeThread::PostTask(
299 ChromeThread::IO, FROM_HERE,
[email protected]dfdb0de72009-02-19 21:58:14300 NewRunnableMethod(this,
301 &SafeBrowsingService::ReportMalware,
302 resource.url,
303 page_url,
304 referrer_url));
305 }
306
[email protected]1b277e72009-01-23 21:05:34307 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
initial.commit09911bf2008-07-26 23:55:29308}
309
310void SafeBrowsingService::CancelCheck(Client* client) {
[email protected]d83d03aa2009-11-02 21:44:37311 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29312
313 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
314 if ((*i)->client == client)
315 (*i)->client = NULL;
316 }
[email protected]613a03b2008-10-24 23:02:00317
318 // Scan the queued clients store. Clients may be here if they requested a URL
319 // check before the database has finished loading or resetting.
320 if (!database_loaded_ || resetting_) {
321 std::deque<QueuedCheck>::iterator it = queued_checks_.begin();
322 for (; it != queued_checks_.end(); ++it) {
323 if (it->client == client)
324 it->client = NULL;
325 }
326 }
initial.commit09911bf2008-07-26 23:55:29327}
328
[email protected]613a03b2008-10-24 23:02:00329void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
[email protected]d83d03aa2009-11-02 21:44:37330 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29331
332 // If we've been shutdown during the database lookup, this check will already
333 // have been deleted (in OnIOShutdown).
[email protected]613a03b2008-10-24 23:02:00334 if (!enabled_ || checks_.find(check) == checks_.end())
initial.commit09911bf2008-07-26 23:55:29335 return;
336
[email protected]613a03b2008-10-24 23:02:00337 if (check->client && check->need_get_hash) {
initial.commit09911bf2008-07-26 23:55:29338 // We have a partial match so we need to query Google for the full hash.
339 // Clean up will happen in HandleGetHashResults.
340
341 // See if we have a GetHash request already in progress for this particular
342 // prefix. If so, we just append ourselves to the list of interested parties
343 // when the results arrive. We only do this for checks involving one prefix,
344 // since that is the common case (multiple prefixes will issue the request
345 // as normal).
[email protected]613a03b2008-10-24 23:02:00346 if (check->prefix_hits.size() == 1) {
347 SBPrefix prefix = check->prefix_hits[0];
initial.commit09911bf2008-07-26 23:55:29348 GetHashRequests::iterator it = gethash_requests_.find(prefix);
349 if (it != gethash_requests_.end()) {
350 // There's already a request in progress.
[email protected]613a03b2008-10-24 23:02:00351 it->second.push_back(check);
initial.commit09911bf2008-07-26 23:55:29352 return;
353 }
354
355 // No request in progress, so we're the first for this prefix.
356 GetHashRequestors requestors;
[email protected]613a03b2008-10-24 23:02:00357 requestors.push_back(check);
initial.commit09911bf2008-07-26 23:55:29358 gethash_requests_[prefix] = requestors;
359 }
360
361 // Reset the start time so that we can measure the network time without the
362 // database time.
[email protected]613a03b2008-10-24 23:02:00363 check->start = Time::Now();
364 protocol_manager_->GetFullHash(check, check->prefix_hits);
initial.commit09911bf2008-07-26 23:55:29365 } else {
366 // We may have cached results for previous GetHash queries.
[email protected]613a03b2008-10-24 23:02:00367 HandleOneCheck(check, check->full_hits);
initial.commit09911bf2008-07-26 23:55:29368 }
369}
370
371SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
[email protected]f3724ea2009-05-08 22:09:56372 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29373 if (database_)
374 return database_;
375
[email protected]c870c762009-01-28 05:47:15376 FilePath path;
initial.commit09911bf2008-07-26 23:55:29377 bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
378 DCHECK(result);
[email protected]c870c762009-01-28 05:47:15379 path = path.Append(chrome::kSafeBrowsingFilename);
initial.commit09911bf2008-07-26 23:55:29380
381 Time before = Time::Now();
[email protected]54d80bb02008-09-20 02:03:08382 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create();
[email protected]613a03b2008-10-24 23:02:00383 Callback0::Type* chunk_callback =
initial.commit09911bf2008-07-26 23:55:29384 NewCallback(this, &SafeBrowsingService::ChunkInserted);
[email protected]93e6efa32009-10-12 21:43:37385 database->Init(path, chunk_callback);
386 database_ = database;
[email protected]613a03b2008-10-24 23:02:00387
[email protected]d83d03aa2009-11-02 21:44:37388 ChromeThread::PostTask(
389 ChromeThread::IO, FROM_HERE,
390 NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete));
initial.commit09911bf2008-07-26 23:55:29391
392 TimeDelta open_time = Time::Now() - before;
393 SB_DLOG(INFO) << "SafeBrowsing database open took " <<
394 open_time.InMilliseconds() << " ms.";
395
396 return database_;
397}
398
399// Public API called only on the IO thread.
400// The SafeBrowsingProtocolManager has received the full hash results for
401// prefix hits detected in the database.
402void SafeBrowsingService::HandleGetHashResults(
403 SafeBrowsingCheck* check,
[email protected]200abc32008-09-05 01:44:33404 const std::vector<SBFullHashResult>& full_hashes,
405 bool can_cache) {
initial.commit09911bf2008-07-26 23:55:29406 if (checks_.find(check) == checks_.end())
407 return;
408
409 DCHECK(enabled_);
410
[email protected]484c57a2009-03-21 01:24:01411 UMA_HISTOGRAM_LONG_TIMES("SB2.Network", Time::Now() - check->start);
[email protected]22573822008-11-14 00:40:47412
[email protected]200abc32008-09-05 01:44:33413 std::vector<SBPrefix> prefixes = check->prefix_hits;
initial.commit09911bf2008-07-26 23:55:29414 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
415
[email protected]484c57a2009-03-21 01:24:01416 if (can_cache && database_) {
417 // Cache the GetHash results in memory:
418 database_->CacheHashResults(prefixes, full_hashes);
[email protected]613a03b2008-10-24 23:02:00419 }
initial.commit09911bf2008-07-26 23:55:29420}
421
422void SafeBrowsingService::OnHandleGetHashResults(
423 SafeBrowsingCheck* check,
424 const std::vector<SBFullHashResult>& full_hashes) {
425 SBPrefix prefix = check->prefix_hits[0];
426 GetHashRequests::iterator it = gethash_requests_.find(prefix);
427 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
428 HandleOneCheck(check, full_hashes);
429 return;
430 }
431
432 // Call back all interested parties.
433 GetHashRequestors& requestors = it->second;
434 for (GetHashRequestors::iterator r = requestors.begin();
435 r != requestors.end(); ++r) {
436 HandleOneCheck(*r, full_hashes);
437 }
438
439 gethash_requests_.erase(it);
440}
441
442void SafeBrowsingService::HandleOneCheck(
443 SafeBrowsingCheck* check,
444 const std::vector<SBFullHashResult>& full_hashes) {
445 if (check->client) {
446 UrlCheckResult result = URL_SAFE;
447 int index = safe_browsing_util::CompareFullHashes(check->url, full_hashes);
[email protected]09d985f2009-05-11 21:59:58448 if (index != -1) {
initial.commit09911bf2008-07-26 23:55:29449 result = GetResultFromListname(full_hashes[index].list_name);
[email protected]09d985f2009-05-11 21:59:58450 } else {
451 // Log the case where the SafeBrowsing servers return full hashes in the
452 // GetHash response that match the prefix we're looking up, but don't
453 // match the full hash of the URL.
454 if (!full_hashes.empty())
455 UMA_HISTOGRAM_COUNTS("SB2.GetHashServerMiss", 1);
456 }
initial.commit09911bf2008-07-26 23:55:29457
458 // Let the client continue handling the original request.
459 check->client->OnUrlCheckResult(check->url, result);
460 }
461
462 checks_.erase(check);
463 delete check;
464}
465
[email protected]57119c3f2008-12-04 00:33:04466void SafeBrowsingService::UpdateStarted() {
[email protected]d83d03aa2009-11-02 21:44:37467 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29468 DCHECK(enabled_);
[email protected]57119c3f2008-12-04 00:33:04469 DCHECK(!update_in_progress_);
470 update_in_progress_ = true;
[email protected]f3724ea2009-05-08 22:09:56471 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29472 this, &SafeBrowsingService::GetAllChunksFromDatabase));
473}
474
[email protected]613a03b2008-10-24 23:02:00475void SafeBrowsingService::UpdateFinished(bool update_succeeded) {
[email protected]d83d03aa2009-11-02 21:44:37476 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]aad08752008-10-02 22:13:41477 DCHECK(enabled_);
[email protected]57119c3f2008-12-04 00:33:04478 if (update_in_progress_) {
479 update_in_progress_ = false;
[email protected]f3724ea2009-05-08 22:09:56480 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
481 NewRunnableMethod(this,
482 &SafeBrowsingService::DatabaseUpdateFinished,
483 update_succeeded));
[email protected]57119c3f2008-12-04 00:33:04484 }
[email protected]aad08752008-10-02 22:13:41485}
486
[email protected]613a03b2008-10-24 23:02:00487void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
[email protected]f3724ea2009-05-08 22:09:56488 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]aad08752008-10-02 22:13:41489 if (GetDatabase())
[email protected]613a03b2008-10-24 23:02:00490 GetDatabase()->UpdateFinished(update_succeeded);
[email protected]aad08752008-10-02 22:13:41491}
492
[email protected]1b277e72009-01-23 21:05:34493void SafeBrowsingService::OnBlockingPageDone(
494 const std::vector<UnsafeResource>& resources,
495 bool proceed) {
496 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
497 iter != resources.end(); ++iter) {
498 const UnsafeResource& resource = *iter;
499 NotifyClientBlockingComplete(resource.client, proceed);
initial.commit09911bf2008-07-26 23:55:29500
[email protected]1b277e72009-01-23 21:05:34501 if (proceed) {
502 // Whitelist this domain and warning type for the given tab.
503 WhiteListedEntry entry;
504 entry.render_process_host_id = resource.render_process_host_id;
505 entry.render_view_id = resource.render_view_id;
506 entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry(
507 resource.url);
508 entry.result = resource.threat_type;
509 white_listed_entries_.push_back(entry);
510 }
initial.commit09911bf2008-07-26 23:55:29511 }
initial.commit09911bf2008-07-26 23:55:29512}
513
514void SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
515 bool proceed) {
516 client->OnBlockingPageComplete(proceed);
517}
518
519// This method runs on the UI loop to access the prefs.
520void SafeBrowsingService::OnNewMacKeys(const std::string& client_key,
521 const std::string& wrapped_key) {
522 PrefService* prefs = g_browser_process->local_state();
523 if (prefs) {
524 prefs->SetString(prefs::kSafeBrowsingClientKey, ASCIIToWide(client_key));
525 prefs->SetString(prefs::kSafeBrowsingWrappedKey, ASCIIToWide(wrapped_key));
526 }
527}
528
529void SafeBrowsingService::ChunkInserted() {
[email protected]f3724ea2009-05-08 22:09:56530 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]d83d03aa2009-11-02 21:44:37531 ChromeThread::PostTask(
532 ChromeThread::IO, FROM_HERE,
533 NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted));
initial.commit09911bf2008-07-26 23:55:29534}
535
536void SafeBrowsingService::OnChunkInserted() {
[email protected]d83d03aa2009-11-02 21:44:37537 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04538 if (enabled_)
539 protocol_manager_->OnChunkInserted();
initial.commit09911bf2008-07-26 23:55:29540}
541
[email protected]93e6efa32009-10-12 21:43:37542void SafeBrowsingService::DatabaseLoadComplete() {
[email protected]d83d03aa2009-11-02 21:44:37543 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04544 if (!enabled_)
545 return;
[email protected]613a03b2008-10-24 23:02:00546
547 database_loaded_ = true;
548
[email protected]93e6efa32009-10-12 21:43:37549 if (protocol_manager_)
[email protected]613a03b2008-10-24 23:02:00550 protocol_manager_->Initialize();
551
552 // If we have any queued requests, we can now check them.
553 if (!resetting_)
554 RunQueuedClients();
555}
556
initial.commit09911bf2008-07-26 23:55:29557// static
[email protected]919d77f02009-01-06 19:48:35558void SafeBrowsingService::RegisterPrefs(PrefService* prefs) {
initial.commit09911bf2008-07-26 23:55:29559 prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, L"");
560 prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, L"");
561}
562
563void SafeBrowsingService::ResetDatabase() {
[email protected]d83d03aa2009-11-02 21:44:37564 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29565 resetting_ = true;
[email protected]f3724ea2009-05-08 22:09:56566 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29567 this, &SafeBrowsingService::OnResetDatabase));
568}
569
570void SafeBrowsingService::OnResetDatabase() {
[email protected]f3724ea2009-05-08 22:09:56571 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29572 GetDatabase()->ResetDatabase();
[email protected]d83d03aa2009-11-02 21:44:37573 ChromeThread::PostTask(
574 ChromeThread::IO, FROM_HERE,
575 NewRunnableMethod(this, &SafeBrowsingService::OnResetComplete));
initial.commit09911bf2008-07-26 23:55:29576}
577
578void SafeBrowsingService::OnResetComplete() {
[email protected]d83d03aa2009-11-02 21:44:37579 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04580 if (enabled_) {
581 resetting_ = false;
582 database_loaded_ = true;
583 RunQueuedClients();
584 }
initial.commit09911bf2008-07-26 23:55:29585}
586
587void SafeBrowsingService::HandleChunk(const std::string& list,
588 std::deque<SBChunk>* chunks) {
[email protected]d83d03aa2009-11-02 21:44:37589 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29590 DCHECK(enabled_);
[email protected]f3724ea2009-05-08 22:09:56591 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29592 this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks));
593}
594
595void SafeBrowsingService::HandleChunkForDatabase(
596 const std::string& list_name,
597 std::deque<SBChunk>* chunks) {
[email protected]f3724ea2009-05-08 22:09:56598 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29599
600 GetDatabase()->InsertChunks(list_name, chunks);
601}
602
603void SafeBrowsingService::HandleChunkDelete(
604 std::vector<SBChunkDelete>* chunk_deletes) {
[email protected]d83d03aa2009-11-02 21:44:37605 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29606 DCHECK(enabled_);
[email protected]f3724ea2009-05-08 22:09:56607 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
initial.commit09911bf2008-07-26 23:55:29608 this, &SafeBrowsingService::DeleteChunks, chunk_deletes));
609}
610
611void SafeBrowsingService::DeleteChunks(
612 std::vector<SBChunkDelete>* chunk_deletes) {
[email protected]f3724ea2009-05-08 22:09:56613 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
initial.commit09911bf2008-07-26 23:55:29614
615 GetDatabase()->DeleteChunks(chunk_deletes);
616}
617
618// Database worker function.
619void SafeBrowsingService::GetAllChunksFromDatabase() {
[email protected]f3724ea2009-05-08 22:09:56620 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]a5a37522008-11-11 21:49:56621 bool database_error = true;
initial.commit09911bf2008-07-26 23:55:29622 std::vector<SBListChunkRanges> lists;
[email protected]53ad8572008-11-13 21:50:34623 if (GetDatabase()) {
624 if (GetDatabase()->UpdateStarted()) {
625 GetDatabase()->GetListsInfo(&lists);
626 database_error = false;
627 } else {
628 GetDatabase()->UpdateFinished(false);
629 }
initial.commit09911bf2008-07-26 23:55:29630 }
631
[email protected]d83d03aa2009-11-02 21:44:37632 ChromeThread::PostTask(
633 ChromeThread::IO, FROM_HERE,
634 NewRunnableMethod(
635 this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists,
636 database_error));
initial.commit09911bf2008-07-26 23:55:29637}
638
639// Called on the io thread with the results of all chunks.
640void SafeBrowsingService::OnGetAllChunksFromDatabase(
641 const std::vector<SBListChunkRanges>& lists, bool database_error) {
[email protected]d83d03aa2009-11-02 21:44:37642 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fbb2b7a2008-11-18 22:54:04643 if (enabled_)
644 protocol_manager_->OnGetChunksComplete(lists, database_error);
initial.commit09911bf2008-07-26 23:55:29645}
646
647SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
648 const std::string& list_name) {
649 if (safe_browsing_util::IsPhishingList(list_name)) {
650 return URL_PHISHING;
651 }
652
653 if (safe_browsing_util::IsMalwareList(list_name)) {
654 return URL_MALWARE;
655 }
656
657 SB_DLOG(INFO) << "Unknown safe browsing list " << list_name;
658 return URL_SAFE;
659}
660
initial.commit09911bf2008-07-26 23:55:29661void SafeBrowsingService::LogPauseDelay(TimeDelta time) {
[email protected]484c57a2009-03-21 01:24:01662 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
initial.commit09911bf2008-07-26 23:55:29663}
664
665void SafeBrowsingService::CacheHashResults(
[email protected]200abc32008-09-05 01:44:33666 const std::vector<SBPrefix>& prefixes,
initial.commit09911bf2008-07-26 23:55:29667 const std::vector<SBFullHashResult>& full_hashes) {
[email protected]f3724ea2009-05-08 22:09:56668 DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
[email protected]200abc32008-09-05 01:44:33669 GetDatabase()->CacheHashResults(prefixes, full_hashes);
initial.commit09911bf2008-07-26 23:55:29670}
671
[email protected]613a03b2008-10-24 23:02:00672void SafeBrowsingService::RunQueuedClients() {
[email protected]d83d03aa2009-11-02 21:44:37673 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]553dba62009-02-24 19:08:23674 HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
[email protected]613a03b2008-10-24 23:02:00675 while (!queued_checks_.empty()) {
676 QueuedCheck check = queued_checks_.front();
[email protected]553dba62009-02-24 19:08:23677 HISTOGRAM_TIMES("SB.QueueDelay", Time::Now() - check.start);
[email protected]613a03b2008-10-24 23:02:00678 CheckUrl(check.url, check.client);
679 queued_checks_.pop_front();
680 }
681}
682
[email protected]dfdb0de72009-02-19 21:58:14683void SafeBrowsingService::ReportMalware(const GURL& malware_url,
684 const GURL& page_url,
685 const GURL& referrer_url) {
[email protected]d83d03aa2009-11-02 21:44:37686 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]dfdb0de72009-02-19 21:58:14687
[email protected]484c57a2009-03-21 01:24:01688 if (!enabled_ || !database_)
[email protected]dfdb0de72009-02-19 21:58:14689 return;
690
691 // Check if 'page_url' is already blacklisted (exists in our cache). Only
692 // report if it's not there.
693 std::string list;
694 std::vector<SBPrefix> prefix_hits;
695 std::vector<SBFullHashResult> full_hits;
696 database_->ContainsUrl(page_url, &list, &prefix_hits, &full_hits,
697 protocol_manager_->last_update());
698
699 if (full_hits.empty())
700 protocol_manager_->ReportMalware(malware_url, page_url, referrer_url);
701}