OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/client_side_detection_service.h" | 5 #include "chrome/browser/safe_browsing/client_side_detection_service.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/time.h" | 9 #include "base/time.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 scoped_ptr<ClientReportPhishingRequestCallback> callback; | 56 scoped_ptr<ClientReportPhishingRequestCallback> callback; |
57 GURL phishing_url; | 57 GURL phishing_url; |
58 }; | 58 }; |
59 | 59 |
60 ClientSideDetectionService::CacheState::CacheState(bool phish, base::Time time) | 60 ClientSideDetectionService::CacheState::CacheState(bool phish, base::Time time) |
61 : is_phishing(phish), | 61 : is_phishing(phish), |
62 timestamp(time) {} | 62 timestamp(time) {} |
63 | 63 |
64 ClientSideDetectionService::ClientSideDetectionService( | 64 ClientSideDetectionService::ClientSideDetectionService( |
65 net::URLRequestContextGetter* request_context_getter) | 65 net::URLRequestContextGetter* request_context_getter) |
66 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), | 66 : enabled_(false), |
67 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), | |
67 request_context_getter_(request_context_getter) { | 68 request_context_getter_(request_context_getter) { |
68 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 69 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
69 NotificationService::AllSources()); | 70 NotificationService::AllSources()); |
70 } | 71 } |
71 | 72 |
72 ClientSideDetectionService::~ClientSideDetectionService() { | 73 ClientSideDetectionService::~ClientSideDetectionService() { |
73 method_factory_.RevokeAll(); | 74 method_factory_.RevokeAll(); |
74 STLDeleteContainerPairPointers(client_phishing_reports_.begin(), | 75 STLDeleteContainerPairPointers(client_phishing_reports_.begin(), |
75 client_phishing_reports_.end()); | 76 client_phishing_reports_.end()); |
76 client_phishing_reports_.clear(); | 77 client_phishing_reports_.clear(); |
77 } | 78 } |
78 | 79 |
79 // static | 80 // static |
80 ClientSideDetectionService* ClientSideDetectionService::Create( | 81 ClientSideDetectionService* ClientSideDetectionService::Create( |
81 net::URLRequestContextGetter* request_context_getter) { | 82 net::URLRequestContextGetter* request_context_getter) { |
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
83 scoped_ptr<ClientSideDetectionService> service( | 84 scoped_ptr<ClientSideDetectionService> service( |
84 new ClientSideDetectionService(request_context_getter)); | 85 new ClientSideDetectionService(request_context_getter)); |
85 if (!service->InitializePrivateNetworks()) { | 86 if (!service->InitializePrivateNetworks()) { |
86 UMA_HISTOGRAM_COUNTS("SBClientPhishing.InitPrivateNetworksFailed", 1); | 87 UMA_HISTOGRAM_COUNTS("SBClientPhishing.InitPrivateNetworksFailed", 1); |
87 return NULL; | 88 return NULL; |
88 } | 89 } |
89 // We fetch the model at every browser restart. In a lot of cases the model | |
90 // will be in the cache so it won't actually be fetched from the network. | |
91 // We delay the first model fetch to avoid slowing down browser startup. | |
92 MessageLoop::current()->PostDelayedTask( | |
93 FROM_HERE, | |
94 service->method_factory_.NewRunnableMethod( | |
95 &ClientSideDetectionService::StartFetchModel), | |
96 kInitialClientModelFetchDelayMs); | |
97 return service.release(); | 90 return service.release(); |
98 } | 91 } |
99 | 92 |
93 void ClientSideDetectionService::SetEnabled(bool enabled) { | |
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
95 if (enabled == enabled_) | |
96 return; | |
97 enabled_ = enabled; | |
98 if (enabled_) { | |
99 // Refresh the model when the service is enabled. This can happen when the | |
100 // preference is toggled, or early during startup if the preference is | |
101 // already enabled. In a lot of cases the model will be in the cache so it | |
102 // won't actually be fetched from the network. | |
103 // We delay the first model fetch to avoid slowing down browser startup. | |
104 ScheduleFetchModel(kInitialClientModelFetchDelayMs); | |
105 } else { | |
106 // Cancel pending requests. | |
107 model_fetcher_.reset(); | |
108 cache_.clear(); | |
109 // Any pending |client_phishing_reports_| will eventually call back into | |
110 // |OnURLFetchComplete|. Those requests aren't cancelled here, because | |
111 // we have to invoke the callback. | |
mattm
2011/08/08 21:59:46
Hm, are you sure this can't use the same clean-up
Joao da Silva
2011/08/09 09:16:12
It can, but deleting the URLFetchers will cancel t
mattm
2011/08/10 23:38:26
With the current implementation it wouldn't care,
Joao da Silva
2011/08/11 11:51:50
Agree, done.
| |
112 } | |
113 } | |
114 | |
100 void ClientSideDetectionService::SendClientReportPhishingRequest( | 115 void ClientSideDetectionService::SendClientReportPhishingRequest( |
101 ClientPhishingRequest* verdict, | 116 ClientPhishingRequest* verdict, |
102 ClientReportPhishingRequestCallback* callback) { | 117 ClientReportPhishingRequestCallback* callback) { |
103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
104 MessageLoop::current()->PostTask( | 119 MessageLoop::current()->PostTask( |
105 FROM_HERE, | 120 FROM_HERE, |
106 method_factory_.NewRunnableMethod( | 121 method_factory_.NewRunnableMethod( |
107 &ClientSideDetectionService::StartClientReportPhishingRequest, | 122 &ClientSideDetectionService::StartClientReportPhishingRequest, |
108 verdict, callback)); | 123 verdict, callback)); |
109 } | 124 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
191 process->Send(new SafeBrowsingMsg_SetPhishingModel(model_str_)); | 206 process->Send(new SafeBrowsingMsg_SetPhishingModel(model_str_)); |
192 } | 207 } |
193 | 208 |
194 void ClientSideDetectionService::SendModelToRenderers() { | 209 void ClientSideDetectionService::SendModelToRenderers() { |
195 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | 210 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |
196 !i.IsAtEnd(); i.Advance()) { | 211 !i.IsAtEnd(); i.Advance()) { |
197 SendModelToProcess(i.GetCurrentValue()); | 212 SendModelToProcess(i.GetCurrentValue()); |
198 } | 213 } |
199 } | 214 } |
200 | 215 |
216 void ClientSideDetectionService::ScheduleFetchModel(int64 delay_ms) { | |
217 MessageLoop::current()->PostDelayedTask( | |
218 FROM_HERE, | |
219 method_factory_.NewRunnableMethod( | |
220 &ClientSideDetectionService::StartFetchModel), | |
221 delay_ms); | |
222 } | |
223 | |
201 void ClientSideDetectionService::StartFetchModel() { | 224 void ClientSideDetectionService::StartFetchModel() { |
202 // Start fetching the model either from the cache or possibly from the | 225 if (enabled_) { |
203 // network if the model isn't in the cache. | 226 // Start fetching the model either from the cache or possibly from the |
204 model_fetcher_.reset(URLFetcher::Create(0 /* ID is not used */, | 227 // network if the model isn't in the cache. |
205 GURL(kClientModelUrl), | 228 model_fetcher_.reset(URLFetcher::Create(0 /* ID is not used */, |
206 URLFetcher::GET, | 229 GURL(kClientModelUrl), |
207 this)); | 230 URLFetcher::GET, |
208 model_fetcher_->set_request_context(request_context_getter_.get()); | 231 this)); |
209 model_fetcher_->Start(); | 232 model_fetcher_->set_request_context(request_context_getter_.get()); |
233 model_fetcher_->Start(); | |
234 } | |
210 } | 235 } |
211 | 236 |
212 void ClientSideDetectionService::EndFetchModel(ClientModelStatus status) { | 237 void ClientSideDetectionService::EndFetchModel(ClientModelStatus status) { |
213 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ClientModelStatus", | 238 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ClientModelStatus", |
214 status, | 239 status, |
215 MODEL_STATUS_MAX); | 240 MODEL_STATUS_MAX); |
216 if (status == MODEL_SUCCESS) { | 241 if (status == MODEL_SUCCESS) { |
217 SetBadSubnets(*model_, &bad_subnets_); | 242 SetBadSubnets(*model_, &bad_subnets_); |
218 SendModelToRenderers(); | 243 SendModelToRenderers(); |
219 } | 244 } |
220 int delay_ms = kClientModelFetchIntervalMs; | 245 int delay_ms = kClientModelFetchIntervalMs; |
221 // If the most recently fetched model had a valid max-age and the model was | 246 // If the most recently fetched model had a valid max-age and the model was |
222 // valid we're scheduling the next model update for after the max-age expired. | 247 // valid we're scheduling the next model update for after the max-age expired. |
223 if (model_max_age_.get() && | 248 if (model_max_age_.get() && |
224 (status == MODEL_SUCCESS || status == MODEL_NOT_CHANGED)) { | 249 (status == MODEL_SUCCESS || status == MODEL_NOT_CHANGED)) { |
225 // We're adding 60s of additional delay to make sure we're past | 250 // We're adding 60s of additional delay to make sure we're past |
226 // the model's age. | 251 // the model's age. |
227 *model_max_age_ += base::TimeDelta::FromMinutes(1); | 252 *model_max_age_ += base::TimeDelta::FromMinutes(1); |
228 delay_ms = model_max_age_->InMilliseconds(); | 253 delay_ms = model_max_age_->InMilliseconds(); |
229 } | 254 } |
230 model_max_age_.reset(); | 255 model_max_age_.reset(); |
231 | 256 |
232 // Schedule the next model reload. | 257 // Schedule the next model reload. |
233 MessageLoop::current()->PostDelayedTask( | 258 ScheduleFetchModel(delay_ms); |
234 FROM_HERE, | |
235 method_factory_.NewRunnableMethod( | |
236 &ClientSideDetectionService::StartFetchModel), | |
237 delay_ms); | |
238 } | 259 } |
239 | 260 |
240 void ClientSideDetectionService::StartClientReportPhishingRequest( | 261 void ClientSideDetectionService::StartClientReportPhishingRequest( |
241 ClientPhishingRequest* verdict, | 262 ClientPhishingRequest* verdict, |
242 ClientReportPhishingRequestCallback* callback) { | 263 ClientReportPhishingRequestCallback* callback) { |
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
244 scoped_ptr<ClientPhishingRequest> request(verdict); | 265 scoped_ptr<ClientPhishingRequest> request(verdict); |
245 scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); | 266 scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); |
246 | 267 |
268 if (!enabled_) { | |
269 if (cb.get()) | |
270 cb->Run(GURL(request->url()), false); | |
271 return; | |
272 } | |
273 | |
247 std::string request_data; | 274 std::string request_data; |
248 if (!request->SerializeToString(&request_data)) { | 275 if (!request->SerializeToString(&request_data)) { |
249 UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); | 276 UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); |
250 VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; | 277 VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; |
251 if (cb.get()) { | 278 if (cb.get()) { |
252 cb->Run(GURL(request->url()), false); | 279 cb->Run(GURL(request->url()), false); |
253 } | 280 } |
254 return; | 281 return; |
255 } | 282 } |
256 | 283 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 const GURL& url, | 347 const GURL& url, |
321 const net::URLRequestStatus& status, | 348 const net::URLRequestStatus& status, |
322 int response_code, | 349 int response_code, |
323 const net::ResponseCookies& cookies, | 350 const net::ResponseCookies& cookies, |
324 const std::string& data) { | 351 const std::string& data) { |
325 ClientPhishingResponse response; | 352 ClientPhishingResponse response; |
326 scoped_ptr<ClientReportInfo> info(client_phishing_reports_[source]); | 353 scoped_ptr<ClientReportInfo> info(client_phishing_reports_[source]); |
327 bool is_phishing = false; | 354 bool is_phishing = false; |
328 if (status.is_success() && RC_REQUEST_OK == response_code && | 355 if (status.is_success() && RC_REQUEST_OK == response_code && |
329 response.ParseFromString(data)) { | 356 response.ParseFromString(data)) { |
330 // Cache response, possibly flushing an old one. | 357 // The service could have been disabled while this request was in flight. |
331 cache_[info->phishing_url] = | 358 // In that case, ignore the response and just report not phishing. |
332 make_linked_ptr(new CacheState(response.phishy(), base::Time::Now())); | 359 if (enabled_) { |
333 is_phishing = response.phishy(); | 360 // Cache response, possibly flushing an old one. |
361 cache_[info->phishing_url] = | |
362 make_linked_ptr(new CacheState(response.phishy(), base::Time::Now())); | |
363 is_phishing = response.phishy(); | |
364 } | |
334 } else { | 365 } else { |
335 DLOG(ERROR) << "Unable to get the server verdict for URL: " | 366 DLOG(ERROR) << "Unable to get the server verdict for URL: " |
336 << info->phishing_url << " status: " << status.status() << " " | 367 << info->phishing_url << " status: " << status.status() << " " |
337 << "response_code:" << response_code; | 368 << "response_code:" << response_code; |
338 } | 369 } |
339 if (info->callback.get()) { | 370 if (info->callback.get()) { |
340 info->callback->Run(info->phishing_url, is_phishing); | 371 info->callback->Run(info->phishing_url, is_phishing); |
341 } | 372 } |
342 client_phishing_reports_.erase(source); | 373 client_phishing_reports_.erase(source); |
343 delete source; | 374 delete source; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
480 } | 511 } |
481 } | 512 } |
482 for (int i = 0; i < model.page_word_size(); ++i) { | 513 for (int i = 0; i < model.page_word_size(); ++i) { |
483 if (model.page_word(i) < 0 || model.page_word(i) > max_index) { | 514 if (model.page_word(i) < 0 || model.page_word(i) > max_index) { |
484 return false; | 515 return false; |
485 } | 516 } |
486 } | 517 } |
487 return true; | 518 return true; |
488 } | 519 } |
489 } // namespace safe_browsing | 520 } // namespace safe_browsing |
OLD | NEW |