Chromium Code Reviews| 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 |