| 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 // Invoke pending callbacks with a false verdict. |
| 109 for (std::map<const URLFetcher*, ClientReportInfo*>::iterator it = |
| 110 client_phishing_reports_.begin(); |
| 111 it != client_phishing_reports_.end(); ++it) { |
| 112 ClientReportInfo* info = it->second; |
| 113 if (info->callback.get()) |
| 114 info->callback->Run(info->phishing_url, false); |
| 115 } |
| 116 STLDeleteContainerPairPointers(client_phishing_reports_.begin(), |
| 117 client_phishing_reports_.end()); |
| 118 client_phishing_reports_.clear(); |
| 119 cache_.clear(); |
| 120 } |
| 121 } |
| 122 |
| 100 void ClientSideDetectionService::SendClientReportPhishingRequest( | 123 void ClientSideDetectionService::SendClientReportPhishingRequest( |
| 101 ClientPhishingRequest* verdict, | 124 ClientPhishingRequest* verdict, |
| 102 ClientReportPhishingRequestCallback* callback) { | 125 ClientReportPhishingRequestCallback* callback) { |
| 103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 104 MessageLoop::current()->PostTask( | 127 MessageLoop::current()->PostTask( |
| 105 FROM_HERE, | 128 FROM_HERE, |
| 106 method_factory_.NewRunnableMethod( | 129 method_factory_.NewRunnableMethod( |
| 107 &ClientSideDetectionService::StartClientReportPhishingRequest, | 130 &ClientSideDetectionService::StartClientReportPhishingRequest, |
| 108 verdict, callback)); | 131 verdict, callback)); |
| 109 } | 132 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 process->Send(new SafeBrowsingMsg_SetPhishingModel(model_str_)); | 214 process->Send(new SafeBrowsingMsg_SetPhishingModel(model_str_)); |
| 192 } | 215 } |
| 193 | 216 |
| 194 void ClientSideDetectionService::SendModelToRenderers() { | 217 void ClientSideDetectionService::SendModelToRenderers() { |
| 195 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | 218 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |
| 196 !i.IsAtEnd(); i.Advance()) { | 219 !i.IsAtEnd(); i.Advance()) { |
| 197 SendModelToProcess(i.GetCurrentValue()); | 220 SendModelToProcess(i.GetCurrentValue()); |
| 198 } | 221 } |
| 199 } | 222 } |
| 200 | 223 |
| 224 void ClientSideDetectionService::ScheduleFetchModel(int64 delay_ms) { |
| 225 MessageLoop::current()->PostDelayedTask( |
| 226 FROM_HERE, |
| 227 method_factory_.NewRunnableMethod( |
| 228 &ClientSideDetectionService::StartFetchModel), |
| 229 delay_ms); |
| 230 } |
| 231 |
| 201 void ClientSideDetectionService::StartFetchModel() { | 232 void ClientSideDetectionService::StartFetchModel() { |
| 202 // Start fetching the model either from the cache or possibly from the | 233 if (enabled_) { |
| 203 // network if the model isn't in the cache. | 234 // Start fetching the model either from the cache or possibly from the |
| 204 model_fetcher_.reset(URLFetcher::Create(0 /* ID is not used */, | 235 // network if the model isn't in the cache. |
| 205 GURL(kClientModelUrl), | 236 model_fetcher_.reset(URLFetcher::Create(0 /* ID is not used */, |
| 206 URLFetcher::GET, | 237 GURL(kClientModelUrl), |
| 207 this)); | 238 URLFetcher::GET, |
| 208 model_fetcher_->set_request_context(request_context_getter_.get()); | 239 this)); |
| 209 model_fetcher_->Start(); | 240 model_fetcher_->set_request_context(request_context_getter_.get()); |
| 241 model_fetcher_->Start(); |
| 242 } |
| 210 } | 243 } |
| 211 | 244 |
| 212 void ClientSideDetectionService::EndFetchModel(ClientModelStatus status) { | 245 void ClientSideDetectionService::EndFetchModel(ClientModelStatus status) { |
| 213 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ClientModelStatus", | 246 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ClientModelStatus", |
| 214 status, | 247 status, |
| 215 MODEL_STATUS_MAX); | 248 MODEL_STATUS_MAX); |
| 216 if (status == MODEL_SUCCESS) { | 249 if (status == MODEL_SUCCESS) { |
| 217 SetBadSubnets(*model_, &bad_subnets_); | 250 SetBadSubnets(*model_, &bad_subnets_); |
| 218 SendModelToRenderers(); | 251 SendModelToRenderers(); |
| 219 } | 252 } |
| 220 int delay_ms = kClientModelFetchIntervalMs; | 253 int delay_ms = kClientModelFetchIntervalMs; |
| 221 // If the most recently fetched model had a valid max-age and the model was | 254 // 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. | 255 // valid we're scheduling the next model update for after the max-age expired. |
| 223 if (model_max_age_.get() && | 256 if (model_max_age_.get() && |
| 224 (status == MODEL_SUCCESS || status == MODEL_NOT_CHANGED)) { | 257 (status == MODEL_SUCCESS || status == MODEL_NOT_CHANGED)) { |
| 225 // We're adding 60s of additional delay to make sure we're past | 258 // We're adding 60s of additional delay to make sure we're past |
| 226 // the model's age. | 259 // the model's age. |
| 227 *model_max_age_ += base::TimeDelta::FromMinutes(1); | 260 *model_max_age_ += base::TimeDelta::FromMinutes(1); |
| 228 delay_ms = model_max_age_->InMilliseconds(); | 261 delay_ms = model_max_age_->InMilliseconds(); |
| 229 } | 262 } |
| 230 model_max_age_.reset(); | 263 model_max_age_.reset(); |
| 231 | 264 |
| 232 // Schedule the next model reload. | 265 // Schedule the next model reload. |
| 233 MessageLoop::current()->PostDelayedTask( | 266 ScheduleFetchModel(delay_ms); |
| 234 FROM_HERE, | |
| 235 method_factory_.NewRunnableMethod( | |
| 236 &ClientSideDetectionService::StartFetchModel), | |
| 237 delay_ms); | |
| 238 } | 267 } |
| 239 | 268 |
| 240 void ClientSideDetectionService::StartClientReportPhishingRequest( | 269 void ClientSideDetectionService::StartClientReportPhishingRequest( |
| 241 ClientPhishingRequest* verdict, | 270 ClientPhishingRequest* verdict, |
| 242 ClientReportPhishingRequestCallback* callback) { | 271 ClientReportPhishingRequestCallback* callback) { |
| 243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 244 scoped_ptr<ClientPhishingRequest> request(verdict); | 273 scoped_ptr<ClientPhishingRequest> request(verdict); |
| 245 scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); | 274 scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); |
| 246 | 275 |
| 276 if (!enabled_) { |
| 277 if (cb.get()) |
| 278 cb->Run(GURL(request->url()), false); |
| 279 return; |
| 280 } |
| 281 |
| 247 std::string request_data; | 282 std::string request_data; |
| 248 if (!request->SerializeToString(&request_data)) { | 283 if (!request->SerializeToString(&request_data)) { |
| 249 UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); | 284 UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); |
| 250 VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; | 285 VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; |
| 251 if (cb.get()) { | 286 if (cb.get()) { |
| 252 cb->Run(GURL(request->url()), false); | 287 cb->Run(GURL(request->url()), false); |
| 253 } | 288 } |
| 254 return; | 289 return; |
| 255 } | 290 } |
| 256 | 291 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 } | 515 } |
| 481 } | 516 } |
| 482 for (int i = 0; i < model.page_word_size(); ++i) { | 517 for (int i = 0; i < model.page_word_size(); ++i) { |
| 483 if (model.page_word(i) < 0 || model.page_word(i) > max_index) { | 518 if (model.page_word(i) < 0 || model.page_word(i) > max_index) { |
| 484 return false; | 519 return false; |
| 485 } | 520 } |
| 486 } | 521 } |
| 487 return true; | 522 return true; |
| 488 } | 523 } |
| 489 } // namespace safe_browsing | 524 } // namespace safe_browsing |
| OLD | NEW |