| 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/browser_feature_extractor.h" | 5 #include "chrome/browser/safe_browsing/browser_feature_extractor.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 ClientSideDetectionService* service) | 111 ClientSideDetectionService* service) |
| 112 : tab_(tab), | 112 : tab_(tab), |
| 113 service_(service), | 113 service_(service), |
| 114 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 114 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
| 115 DCHECK(tab); | 115 DCHECK(tab); |
| 116 } | 116 } |
| 117 | 117 |
| 118 BrowserFeatureExtractor::~BrowserFeatureExtractor() { | 118 BrowserFeatureExtractor::~BrowserFeatureExtractor() { |
| 119 weak_factory_.InvalidateWeakPtrs(); | 119 weak_factory_.InvalidateWeakPtrs(); |
| 120 // Delete all the pending extractions (delete callback and request objects). | 120 // Delete all the pending extractions (delete callback and request objects). |
| 121 STLDeleteContainerPairPointers(pending_extractions_.begin(), | 121 STLDeleteContainerPairFirstPointers(pending_extractions_.begin(), |
| 122 pending_extractions_.end()); | 122 pending_extractions_.end()); |
| 123 |
| 123 // Also cancel all the pending history service queries. | 124 // Also cancel all the pending history service queries. |
| 124 HistoryService* history; | 125 HistoryService* history; |
| 125 bool success = GetHistoryService(&history); | 126 bool success = GetHistoryService(&history); |
| 126 DCHECK(success || pending_queries_.size() == 0); | 127 DCHECK(success || pending_queries_.size() == 0); |
| 127 // Cancel all the pending history lookups and cleanup the memory. | 128 // Cancel all the pending history lookups and cleanup the memory. |
| 128 for (PendingQueriesMap::iterator it = pending_queries_.begin(); | 129 for (PendingQueriesMap::iterator it = pending_queries_.begin(); |
| 129 it != pending_queries_.end(); ++it) { | 130 it != pending_queries_.end(); ++it) { |
| 130 if (history) { | 131 if (history) { |
| 131 history->CancelRequest(it->first); | 132 history->CancelRequest(it->first); |
| 132 } | 133 } |
| 133 ExtractionData& extraction = it->second; | 134 ExtractionData& extraction = it->second; |
| 134 delete extraction.first; // delete request | 135 delete extraction.first; // delete request |
| 135 delete extraction.second; // delete callback | |
| 136 } | 136 } |
| 137 pending_queries_.clear(); | 137 pending_queries_.clear(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 void BrowserFeatureExtractor::ExtractFeatures(const BrowseInfo* info, | 140 void BrowserFeatureExtractor::ExtractFeatures(const BrowseInfo* info, |
| 141 ClientPhishingRequest* request, | 141 ClientPhishingRequest* request, |
| 142 DoneCallback* callback) { | 142 const DoneCallback& callback) { |
| 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 144 DCHECK(request); | 144 DCHECK(request); |
| 145 DCHECK(info); | 145 DCHECK(info); |
| 146 DCHECK_EQ(0U, request->url().find("http:")); | 146 DCHECK_EQ(0U, request->url().find("http:")); |
| 147 DCHECK(callback); | 147 DCHECK(!callback.is_null()); |
| 148 if (!callback) { | 148 if (callback.is_null()) { |
| 149 DLOG(ERROR) << "ExtractFeatures called without a callback object"; | 149 DLOG(ERROR) << "ExtractFeatures called without a callback object"; |
| 150 return; | 150 return; |
| 151 } | 151 } |
| 152 | 152 |
| 153 // Extract features pertaining to this navigation. | 153 // Extract features pertaining to this navigation. |
| 154 const NavigationController& controller = tab_->controller(); | 154 const NavigationController& controller = tab_->controller(); |
| 155 int url_index = -1; | 155 int url_index = -1; |
| 156 int first_host_index = -1; | 156 int first_host_index = -1; |
| 157 | 157 |
| 158 GURL request_url(request->url()); | 158 GURL request_url(request->url()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 } | 191 } |
| 192 if (first_host_index != -1) { | 192 if (first_host_index != -1) { |
| 193 AddNavigationFeatures(features::kHostPrefix, | 193 AddNavigationFeatures(features::kHostPrefix, |
| 194 controller, | 194 controller, |
| 195 first_host_index, | 195 first_host_index, |
| 196 info->host_redirects, | 196 info->host_redirects, |
| 197 request); | 197 request); |
| 198 } | 198 } |
| 199 | 199 |
| 200 ExtractBrowseInfoFeatures(*info, request); | 200 ExtractBrowseInfoFeatures(*info, request); |
| 201 pending_extractions_.insert(std::make_pair(request, callback)); | 201 pending_extractions_[request] = callback; |
| 202 MessageLoop::current()->PostTask( | 202 MessageLoop::current()->PostTask( |
| 203 FROM_HERE, | 203 FROM_HERE, |
| 204 base::Bind(&BrowserFeatureExtractor::StartExtractFeatures, | 204 base::Bind(&BrowserFeatureExtractor::StartExtractFeatures, |
| 205 weak_factory_.GetWeakPtr(), request, callback)); | 205 weak_factory_.GetWeakPtr(), request, callback)); |
| 206 } | 206 } |
| 207 | 207 |
| 208 void BrowserFeatureExtractor::ExtractBrowseInfoFeatures( | 208 void BrowserFeatureExtractor::ExtractBrowseInfoFeatures( |
| 209 const BrowseInfo& info, | 209 const BrowseInfo& info, |
| 210 ClientPhishingRequest* request) { | 210 ClientPhishingRequest* request) { |
| 211 if (service_) { | 211 if (service_) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 233 static_cast<double>(info.unsafe_resource->threat_type), | 233 static_cast<double>(info.unsafe_resource->threat_type), |
| 234 request); | 234 request); |
| 235 } | 235 } |
| 236 if (info.http_status_code != 0) { | 236 if (info.http_status_code != 0) { |
| 237 AddFeature(features::kHttpStatusCode, info.http_status_code, request); | 237 AddFeature(features::kHttpStatusCode, info.http_status_code, request); |
| 238 } | 238 } |
| 239 } | 239 } |
| 240 | 240 |
| 241 void BrowserFeatureExtractor::StartExtractFeatures( | 241 void BrowserFeatureExtractor::StartExtractFeatures( |
| 242 ClientPhishingRequest* request, | 242 ClientPhishingRequest* request, |
| 243 DoneCallback* callback) { | 243 const DoneCallback& callback) { |
| 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 245 ExtractionData extraction = std::make_pair(request, callback); | 245 size_t removed = pending_extractions_.erase(request); |
| 246 size_t removed = pending_extractions_.erase(extraction); | |
| 247 DCHECK_EQ(1U, removed); | 246 DCHECK_EQ(1U, removed); |
| 248 HistoryService* history; | 247 HistoryService* history; |
| 249 if (!request || !request->IsInitialized() || !GetHistoryService(&history)) { | 248 if (!request || !request->IsInitialized() || !GetHistoryService(&history)) { |
| 250 callback->Run(false, request); | 249 callback.Run(false, request); |
| 251 delete callback; | |
| 252 return; | 250 return; |
| 253 } | 251 } |
| 254 CancelableRequestProvider::Handle handle = history->QueryURL( | 252 CancelableRequestProvider::Handle handle = history->QueryURL( |
| 255 GURL(request->url()), | 253 GURL(request->url()), |
| 256 true /* wants_visits */, | 254 true /* wants_visits */, |
| 257 &request_consumer_, | 255 &request_consumer_, |
| 258 base::Bind(&BrowserFeatureExtractor::QueryUrlHistoryDone, | 256 base::Bind(&BrowserFeatureExtractor::QueryUrlHistoryDone, |
| 259 base::Unretained(this))); | 257 base::Unretained(this))); |
| 260 | 258 |
| 261 StorePendingQuery(handle, request, callback); | 259 StorePendingQuery(handle, request, callback); |
| 262 } | 260 } |
| 263 | 261 |
| 264 void BrowserFeatureExtractor::QueryUrlHistoryDone( | 262 void BrowserFeatureExtractor::QueryUrlHistoryDone( |
| 265 CancelableRequestProvider::Handle handle, | 263 CancelableRequestProvider::Handle handle, |
| 266 bool success, | 264 bool success, |
| 267 const history::URLRow* row, | 265 const history::URLRow* row, |
| 268 history::VisitVector* visits) { | 266 history::VisitVector* visits) { |
| 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 270 ClientPhishingRequest* request; | 268 ClientPhishingRequest* request; |
| 271 DoneCallback* callback; | 269 DoneCallback callback; |
| 272 if (!GetPendingQuery(handle, &request, &callback)) { | 270 if (!GetPendingQuery(handle, &request, &callback)) { |
| 273 DLOG(FATAL) << "No pending history query found"; | 271 DLOG(FATAL) << "No pending history query found"; |
| 274 return; | 272 return; |
| 275 } | 273 } |
| 276 DCHECK(request); | 274 DCHECK(request); |
| 277 DCHECK(callback); | 275 DCHECK(!callback.is_null()); |
| 278 if (!success) { | 276 if (!success) { |
| 279 // URL is not found in the history. In practice this should not | 277 // URL is not found in the history. In practice this should not |
| 280 // happen (unless there is a real error) because we just visited | 278 // happen (unless there is a real error) because we just visited |
| 281 // that URL. | 279 // that URL. |
| 282 callback->Run(false, request); | 280 callback.Run(false, request); |
| 283 delete callback; | |
| 284 return; | 281 return; |
| 285 } | 282 } |
| 286 AddFeature(features::kUrlHistoryVisitCount, | 283 AddFeature(features::kUrlHistoryVisitCount, |
| 287 static_cast<double>(row->visit_count()), | 284 static_cast<double>(row->visit_count()), |
| 288 request); | 285 request); |
| 289 | 286 |
| 290 base::Time threshold = base::Time::Now() - base::TimeDelta::FromDays(1); | 287 base::Time threshold = base::Time::Now() - base::TimeDelta::FromDays(1); |
| 291 int num_visits_24h_ago = 0; | 288 int num_visits_24h_ago = 0; |
| 292 int num_visits_typed = 0; | 289 int num_visits_typed = 0; |
| 293 int num_visits_link = 0; | 290 int num_visits_link = 0; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 313 AddFeature(features::kUrlHistoryTypedCount, | 310 AddFeature(features::kUrlHistoryTypedCount, |
| 314 static_cast<double>(num_visits_typed), | 311 static_cast<double>(num_visits_typed), |
| 315 request); | 312 request); |
| 316 AddFeature(features::kUrlHistoryLinkCount, | 313 AddFeature(features::kUrlHistoryLinkCount, |
| 317 static_cast<double>(num_visits_link), | 314 static_cast<double>(num_visits_link), |
| 318 request); | 315 request); |
| 319 | 316 |
| 320 // Issue next history lookup for host visits. | 317 // Issue next history lookup for host visits. |
| 321 HistoryService* history; | 318 HistoryService* history; |
| 322 if (!GetHistoryService(&history)) { | 319 if (!GetHistoryService(&history)) { |
| 323 callback->Run(false, request); | 320 callback.Run(false, request); |
| 324 delete callback; | |
| 325 return; | 321 return; |
| 326 } | 322 } |
| 327 CancelableRequestProvider::Handle next_handle = | 323 CancelableRequestProvider::Handle next_handle = |
| 328 history->GetVisibleVisitCountToHost( | 324 history->GetVisibleVisitCountToHost( |
| 329 GURL(request->url()), | 325 GURL(request->url()), |
| 330 &request_consumer_, | 326 &request_consumer_, |
| 331 base::Bind(&BrowserFeatureExtractor::QueryHttpHostVisitsDone, | 327 base::Bind(&BrowserFeatureExtractor::QueryHttpHostVisitsDone, |
| 332 base::Unretained(this))); | 328 base::Unretained(this))); |
| 333 StorePendingQuery(next_handle, request, callback); | 329 StorePendingQuery(next_handle, request, callback); |
| 334 } | 330 } |
| 335 | 331 |
| 336 void BrowserFeatureExtractor::QueryHttpHostVisitsDone( | 332 void BrowserFeatureExtractor::QueryHttpHostVisitsDone( |
| 337 CancelableRequestProvider::Handle handle, | 333 CancelableRequestProvider::Handle handle, |
| 338 bool success, | 334 bool success, |
| 339 int num_visits, | 335 int num_visits, |
| 340 base::Time first_visit) { | 336 base::Time first_visit) { |
| 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 342 ClientPhishingRequest* request; | 338 ClientPhishingRequest* request; |
| 343 DoneCallback* callback; | 339 DoneCallback callback; |
| 344 if (!GetPendingQuery(handle, &request, &callback)) { | 340 if (!GetPendingQuery(handle, &request, &callback)) { |
| 345 DLOG(FATAL) << "No pending history query found"; | 341 DLOG(FATAL) << "No pending history query found"; |
| 346 return; | 342 return; |
| 347 } | 343 } |
| 348 DCHECK(request); | 344 DCHECK(request); |
| 349 DCHECK(callback); | 345 DCHECK(!callback.is_null()); |
| 350 if (!success) { | 346 if (!success) { |
| 351 callback->Run(false, request); | 347 callback.Run(false, request); |
| 352 delete callback; | |
| 353 return; | 348 return; |
| 354 } | 349 } |
| 355 SetHostVisitsFeatures(num_visits, first_visit, true, request); | 350 SetHostVisitsFeatures(num_visits, first_visit, true, request); |
| 356 | 351 |
| 357 // Same lookup but for the HTTPS URL. | 352 // Same lookup but for the HTTPS URL. |
| 358 HistoryService* history; | 353 HistoryService* history; |
| 359 if (!GetHistoryService(&history)) { | 354 if (!GetHistoryService(&history)) { |
| 360 callback->Run(false, request); | 355 callback.Run(false, request); |
| 361 delete callback; | |
| 362 return; | 356 return; |
| 363 } | 357 } |
| 364 std::string https_url = request->url(); | 358 std::string https_url = request->url(); |
| 365 CancelableRequestProvider::Handle next_handle = | 359 CancelableRequestProvider::Handle next_handle = |
| 366 history->GetVisibleVisitCountToHost( | 360 history->GetVisibleVisitCountToHost( |
| 367 GURL(https_url.replace(0, 5, "https:")), | 361 GURL(https_url.replace(0, 5, "https:")), |
| 368 &request_consumer_, | 362 &request_consumer_, |
| 369 base::Bind(&BrowserFeatureExtractor::QueryHttpsHostVisitsDone, | 363 base::Bind(&BrowserFeatureExtractor::QueryHttpsHostVisitsDone, |
| 370 base::Unretained(this))); | 364 base::Unretained(this))); |
| 371 StorePendingQuery(next_handle, request, callback); | 365 StorePendingQuery(next_handle, request, callback); |
| 372 } | 366 } |
| 373 | 367 |
| 374 void BrowserFeatureExtractor::QueryHttpsHostVisitsDone( | 368 void BrowserFeatureExtractor::QueryHttpsHostVisitsDone( |
| 375 CancelableRequestProvider::Handle handle, | 369 CancelableRequestProvider::Handle handle, |
| 376 bool success, | 370 bool success, |
| 377 int num_visits, | 371 int num_visits, |
| 378 base::Time first_visit) { | 372 base::Time first_visit) { |
| 379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 380 ClientPhishingRequest* request; | 374 ClientPhishingRequest* request; |
| 381 DoneCallback* callback; | 375 DoneCallback callback; |
| 382 if (!GetPendingQuery(handle, &request, &callback)) { | 376 if (!GetPendingQuery(handle, &request, &callback)) { |
| 383 DLOG(FATAL) << "No pending history query found"; | 377 DLOG(FATAL) << "No pending history query found"; |
| 384 return; | 378 return; |
| 385 } | 379 } |
| 386 DCHECK(request); | 380 DCHECK(request); |
| 387 DCHECK(callback); | 381 DCHECK(!callback.is_null()); |
| 388 if (!success) { | 382 if (!success) { |
| 389 callback->Run(false, request); | 383 callback.Run(false, request); |
| 390 delete callback; | |
| 391 return; | 384 return; |
| 392 } | 385 } |
| 393 SetHostVisitsFeatures(num_visits, first_visit, false, request); | 386 SetHostVisitsFeatures(num_visits, first_visit, false, request); |
| 394 callback->Run(true, request); // We're done with all the history lookups. | 387 callback.Run(true, request); // We're done with all the history lookups. |
| 395 delete callback; | |
| 396 } | 388 } |
| 397 | 389 |
| 398 void BrowserFeatureExtractor::SetHostVisitsFeatures( | 390 void BrowserFeatureExtractor::SetHostVisitsFeatures( |
| 399 int num_visits, | 391 int num_visits, |
| 400 base::Time first_visit, | 392 base::Time first_visit, |
| 401 bool is_http_query, | 393 bool is_http_query, |
| 402 ClientPhishingRequest* request) { | 394 ClientPhishingRequest* request) { |
| 403 DCHECK(request); | 395 DCHECK(request); |
| 404 AddFeature(is_http_query ? | 396 AddFeature(is_http_query ? |
| 405 features::kHttpHostVisitCount : features::kHttpsHostVisitCount, | 397 features::kHttpHostVisitCount : features::kHttpsHostVisitCount, |
| 406 static_cast<double>(num_visits), | 398 static_cast<double>(num_visits), |
| 407 request); | 399 request); |
| 408 if (num_visits > 0) { | 400 if (num_visits > 0) { |
| 409 AddFeature( | 401 AddFeature( |
| 410 is_http_query ? | 402 is_http_query ? |
| 411 features::kFirstHttpHostVisitMoreThan24hAgo : | 403 features::kFirstHttpHostVisitMoreThan24hAgo : |
| 412 features::kFirstHttpsHostVisitMoreThan24hAgo, | 404 features::kFirstHttpsHostVisitMoreThan24hAgo, |
| 413 (first_visit < (base::Time::Now() - base::TimeDelta::FromDays(1))) ? | 405 (first_visit < (base::Time::Now() - base::TimeDelta::FromDays(1))) ? |
| 414 1.0 : 0.0, | 406 1.0 : 0.0, |
| 415 request); | 407 request); |
| 416 } | 408 } |
| 417 } | 409 } |
| 418 | 410 |
| 419 void BrowserFeatureExtractor::StorePendingQuery( | 411 void BrowserFeatureExtractor::StorePendingQuery( |
| 420 CancelableRequestProvider::Handle handle, | 412 CancelableRequestProvider::Handle handle, |
| 421 ClientPhishingRequest* request, | 413 ClientPhishingRequest* request, |
| 422 DoneCallback* callback) { | 414 const DoneCallback& callback) { |
| 423 DCHECK_EQ(0U, pending_queries_.count(handle)); | 415 DCHECK_EQ(0U, pending_queries_.count(handle)); |
| 424 pending_queries_[handle] = std::make_pair(request, callback); | 416 pending_queries_[handle] = std::make_pair(request, callback); |
| 425 } | 417 } |
| 426 | 418 |
| 427 bool BrowserFeatureExtractor::GetPendingQuery( | 419 bool BrowserFeatureExtractor::GetPendingQuery( |
| 428 CancelableRequestProvider::Handle handle, | 420 CancelableRequestProvider::Handle handle, |
| 429 ClientPhishingRequest** request, | 421 ClientPhishingRequest** request, |
| 430 DoneCallback** callback) { | 422 DoneCallback* callback) { |
| 431 PendingQueriesMap::iterator it = pending_queries_.find(handle); | 423 PendingQueriesMap::iterator it = pending_queries_.find(handle); |
| 432 DCHECK(it != pending_queries_.end()); | 424 DCHECK(it != pending_queries_.end()); |
| 433 if (it != pending_queries_.end()) { | 425 if (it != pending_queries_.end()) { |
| 434 *request = it->second.first; | 426 *request = it->second.first; |
| 435 *callback = it->second.second; | 427 *callback = it->second.second; |
| 436 pending_queries_.erase(it); | 428 pending_queries_.erase(it); |
| 437 return true; | 429 return true; |
| 438 } | 430 } |
| 439 return false; | 431 return false; |
| 440 } | 432 } |
| 441 | 433 |
| 442 bool BrowserFeatureExtractor::GetHistoryService(HistoryService** history) { | 434 bool BrowserFeatureExtractor::GetHistoryService(HistoryService** history) { |
| 443 *history = NULL; | 435 *history = NULL; |
| 444 if (tab_ && tab_->browser_context()) { | 436 if (tab_ && tab_->browser_context()) { |
| 445 Profile* profile = Profile::FromBrowserContext(tab_->browser_context()); | 437 Profile* profile = Profile::FromBrowserContext(tab_->browser_context()); |
| 446 *history = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); | 438 *history = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 447 if (*history) { | 439 if (*history) { |
| 448 return true; | 440 return true; |
| 449 } | 441 } |
| 450 } | 442 } |
| 451 VLOG(2) << "Unable to query history. No history service available."; | 443 VLOG(2) << "Unable to query history. No history service available."; |
| 452 return false; | 444 return false; |
| 453 } | 445 } |
| 454 | 446 |
| 455 } // namespace safe_browsing | 447 } // namespace safe_browsing |
| OLD | NEW |