Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: components/password_manager/core/browser/password_form_manager.cc

Issue 866983003: GetLoginsRequest: Use ScopedVector to express ownership of forms (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@324291_scopedvector
Patch Set: Just rebased on mkwst's changes Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "components/password_manager/core/browser/password_form_manager.h" 5 #include "components/password_manager/core/browser/password_form_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 9
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 } 377 }
378 378
379 // Do not autofill on sign-up or change password forms (until we have some 379 // Do not autofill on sign-up or change password forms (until we have some
380 // working change password functionality). 380 // working change password functionality).
381 if (!observed_form_.new_password_element.empty()) { 381 if (!observed_form_.new_password_element.empty()) {
382 if (logger) 382 if (logger)
383 logger->LogMessage(Logger::STRING_FORM_NOT_AUTOFILLED); 383 logger->LogMessage(Logger::STRING_FORM_NOT_AUTOFILLED);
384 client_->AutofillResultsComputed(); 384 client_->AutofillResultsComputed();
385 // There is no point in looking for the credentials in the store when they 385 // There is no point in looking for the credentials in the store when they
386 // won't be autofilled, so pretend there were none. 386 // won't be autofilled, so pretend there were none.
387 std::vector<autofill::PasswordForm*> dummy_results; 387 OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm>());
388 OnGetPasswordStoreResults(dummy_results);
389 return; 388 return;
390 } 389 }
391 390
392 PasswordStore* password_store = client_->GetPasswordStore(); 391 PasswordStore* password_store = client_->GetPasswordStore();
393 if (!password_store) { 392 if (!password_store) {
394 if (logger) 393 if (logger)
395 logger->LogMessage(Logger::STRING_NO_STORE); 394 logger->LogMessage(Logger::STRING_NO_STORE);
396 NOTREACHED(); 395 NOTREACHED();
397 return; 396 return;
398 } 397 }
399 password_store->GetLogins(observed_form_, prompt_policy, this); 398 password_store->GetLogins(observed_form_, prompt_policy, this);
400 } 399 }
401 400
402 bool PasswordFormManager::HasCompletedMatching() const { 401 bool PasswordFormManager::HasCompletedMatching() const {
403 return state_ == POST_MATCHING_PHASE; 402 return state_ == POST_MATCHING_PHASE;
404 } 403 }
405 404
406 bool PasswordFormManager::IsIgnorableChangePasswordForm() const { 405 bool PasswordFormManager::IsIgnorableChangePasswordForm() const {
407 bool is_change_password_form = !observed_form_.new_password_element.empty() && 406 bool is_change_password_form = !observed_form_.new_password_element.empty() &&
408 !observed_form_.password_element.empty(); 407 !observed_form_.password_element.empty();
409 bool is_username_certainly_correct = observed_form_.username_marked_by_site; 408 bool is_username_certainly_correct = observed_form_.username_marked_by_site;
410 return is_change_password_form && !is_username_certainly_correct; 409 return is_change_password_form && !is_username_certainly_correct;
411 } 410 }
412 411
413 void PasswordFormManager::OnRequestDone( 412 void PasswordFormManager::OnRequestDone(
414 const std::vector<PasswordForm*>& logins_result) { 413 ScopedVector<PasswordForm> logins_result) {
415 // Note that the result gets deleted after this call completes, but we own 414 const size_t logins_result_size = logins_result.size();
416 // the PasswordForm objects pointed to by the result vector, thus we keep
417 // copies to a minimum here.
418 415
419 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 416 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
420 if (client_->IsLoggingActive()) { 417 if (client_->IsLoggingActive()) {
421 logger.reset(new BrowserSavePasswordProgressLogger(client_)); 418 logger.reset(new BrowserSavePasswordProgressLogger(client_));
422 logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD); 419 logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD);
423 } 420 }
424 421
425 int best_score = 0; 422 int best_score = 0;
426 // These credentials will be in the final result regardless of score. 423 // These credentials will be in the final result regardless of score.
427 std::vector<PasswordForm> credentials_to_keep; 424 ScopedVector<PasswordForm> credentials_to_keep;
428 for (size_t i = 0; i < logins_result.size(); i++) { 425 for (auto& login_ptr : logins_result) {
429 if (ShouldIgnoreResult(*logins_result[i])) { 426 scoped_ptr<PasswordForm> login(login_ptr);
430 delete logins_result[i]; 427 login_ptr = nullptr;
428 // A stable handle to the form while the owners change.
429 const PasswordForm& const_login(*login);
430
431 if (ShouldIgnoreResult(const_login))
431 continue; 432 continue;
432 } 433
433 // Score and update best matches. 434 // Score and update best matches.
434 int current_score = ScoreResult(*logins_result[i]); 435 int current_score = ScoreResult(const_login);
435 // This check is here so we can append empty path matches in the event
436 // they don't score as high as others and aren't added to best_matches_.
437 // This is most commonly imported firefox logins. We skip blacklisted
438 // ones because clearly we don't want to autofill them, and secondly
439 // because they only mean something when we have no other matches already
440 // saved in Chrome - in which case they'll make it through the regular
441 // scoring flow below by design. Note signon_realm == origin implies empty
442 // path logins_result, since signon_realm is a prefix of origin for HTML
443 // password forms.
444 // TODO(timsteele): Bug 1269400. We probably should do something more
445 // elegant for any shorter-path match instead of explicitly handling empty
446 // path matches.
447 if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) && 436 if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
448 (observed_form_.signon_realm == logins_result[i]->origin.spec()) && 437 (observed_form_.signon_realm == const_login.origin.spec()) &&
449 (current_score > 0) && (!logins_result[i]->blacklisted_by_user)) { 438 (current_score > 0) && (!const_login.blacklisted_by_user)) {
450 credentials_to_keep.push_back(*logins_result[i]); 439 // This check is here so we can append empty path matches in the event
440 // they don't score as high as others and aren't added to best_matches_.
441 // This is most commonly imported firefox logins. We skip blacklisted
442 // ones because clearly we don't want to autofill them, and secondly
443 // because they only mean something when we have no other matches already
444 // saved in Chrome - in which case they'll make it through the regular
445 // scoring flow below by design. Note signon_realm == origin implies empty
446 // path logins_result, since signon_realm is a prefix of origin for HTML
447 // password forms.
448 // TODO(timsteele): Bug 1269400. We probably should do something more
449 // elegant for any shorter-path match instead of explicitly handling empty
450 // path matches.
451 credentials_to_keep.push_back(login.release());
452 } else if (const_login.type == PasswordForm::TYPE_GENERATED) {
453 // Always keep generated passwords as part of the result set. If a user
454 // generates a password on a signup form, it should show on a login form
455 // even if they have a previous login saved.
456 // TODO(gcasto): We don't want to cut credentials that were saved on
457 // signup forms even if they weren't generated, but currently it's hard to
458 // distinguish between those forms and two different login forms on the
459 // same domain. Filed http://crbug.com/294468 to look into this.
460 credentials_to_keep.push_back(login.release());
451 } 461 }
452 462
453 // Always keep generated passwords as part of the result set. If a user 463 // End of exceptions, only interested in good-scoring candidates since now.
454 // generates a password on a signup form, it should show on a login form
455 // even if they have a previous login saved.
456 // TODO(gcasto): We don't want to cut credentials that were saved on signup
457 // forms even if they weren't generated, but currently it's hard to
458 // distinguish between those forms and two different login forms on the
459 // same domain. Filed http://crbug.com/294468 to look into this.
460 if (logins_result[i]->type == PasswordForm::TYPE_GENERATED)
461 credentials_to_keep.push_back(*logins_result[i]);
462
463 if (current_score < best_score) { 464 if (current_score < best_score) {
464 delete logins_result[i];
465 continue; 465 continue;
466 } else if (current_score == best_score) {
467 auto& best_match = best_matches_[const_login.username_value];
468 if (best_match == preferred_match_)
469 preferred_match_ = nullptr;
470 delete best_match;
471 best_match = login.release();
472 } else { // current_score > best_score
473 best_score = current_score;
474 preferred_match_ = nullptr; // Don't delete, its owned by best_matches_.
475 STLDeleteValues(&best_matches_); // |login| tops the previous matches.
476 best_matches_[const_login.username_value] = login.release();
466 } 477 }
467 if (current_score == best_score) { 478 preferred_match_ = const_login.preferred ? &const_login : preferred_match_;
vasilii 2015/02/09 10:08:35 What about DCHECK(!login) above because you save t
vabr (Chromium) 2015/02/09 11:36:06 Done.
468 PasswordForm* old_form = best_matches_[logins_result[i]->username_value];
469 if (old_form) {
470 if (preferred_match_ == old_form)
471 preferred_match_ = NULL;
472 delete old_form;
473 }
474 best_matches_[logins_result[i]->username_value] = logins_result[i];
475 } else if (current_score > best_score) {
476 best_score = current_score;
477 // This new login has a better score than all those up to this point
478 // Note 'this' owns all the PasswordForms in best_matches_.
479 STLDeleteValues(&best_matches_);
480 preferred_match_ = NULL; // Don't delete, its owned by best_matches_.
481 best_matches_[logins_result[i]->username_value] = logins_result[i];
482 }
483 preferred_match_ =
484 logins_result[i]->preferred ? logins_result[i] : preferred_match_;
485 } 479 }
480 logins_result.weak_clear(); // It contains just nulls, speed up destruction.
486 481
487 client_->AutofillResultsComputed(); 482 client_->AutofillResultsComputed();
488 483
489 // TODO(gcasto): Change this to check that best_matches_ is empty. This should 484 // TODO(gcasto): Change this to check that best_matches_ is empty. This should
490 // be equivalent for the moment, but it's less clear and may not be 485 // be equivalent for the moment, but it's less clear and may not be
491 // equivalent in the future. 486 // equivalent in the future.
492 if (best_score <= 0) { 487 if (best_score <= 0) {
493 if (logger) 488 if (logger)
494 logger->LogNumber(Logger::STRING_BEST_SCORE, best_score); 489 logger->LogNumber(Logger::STRING_BEST_SCORE, best_score);
495 return; 490 return;
496 } 491 }
497 492
498 for (std::vector<PasswordForm>::const_iterator it = 493 for (auto& form : credentials_to_keep) {
499 credentials_to_keep.begin();
500 it != credentials_to_keep.end(); ++it) {
501 // If we don't already have a result with the same username, add the 494 // If we don't already have a result with the same username, add the
502 // lower-scored match (if it had equal score it would already be in 495 // lower-scored match (if it had equal score it would already be in
503 // best_matches_). 496 // best_matches_).
504 if (best_matches_.find(it->username_value) == best_matches_.end()) 497 auto& corresponding_best_match = best_matches_[form->username_value];
505 best_matches_[it->username_value] = new PasswordForm(*it); 498 if (!corresponding_best_match) {
499 corresponding_best_match = form;
500 form = nullptr;
501 }
506 } 502 }
507 503
508 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown", 504 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
509 logins_result.size() - best_matches_.size()); 505 logins_result_size - best_matches_.size());
510 506
511 // It is possible we have at least one match but have no preferred_match_, 507 // It is possible we have at least one match but have no preferred_match_,
512 // because a user may have chosen to 'Forget' the preferred match. So we 508 // because a user may have chosen to 'Forget' the preferred match. So we
513 // just pick the first one and whichever the user selects for submit will 509 // just pick the first one and whichever the user selects for submit will
514 // be saved as preferred. 510 // be saved as preferred.
515 DCHECK(!best_matches_.empty()); 511 DCHECK(!best_matches_.empty());
516 if (!preferred_match_) 512 if (!preferred_match_)
517 preferred_match_ = best_matches_.begin()->second; 513 preferred_match_ = best_matches_.begin()->second;
518 514
519 // Check to see if the user told us to ignore this site in the past. 515 // Check to see if the user told us to ignore this site in the past.
(...skipping 29 matching lines...) Expand all
549 preferred_match_->IsPublicSuffixMatch(); 545 preferred_match_->IsPublicSuffixMatch();
550 if (wait_for_username) 546 if (wait_for_username)
551 manager_action_ = kManagerActionNone; 547 manager_action_ = kManagerActionNone;
552 else 548 else
553 manager_action_ = kManagerActionAutofilled; 549 manager_action_ = kManagerActionAutofilled;
554 password_manager_->Autofill(driver.get(), observed_form_, best_matches_, 550 password_manager_->Autofill(driver.get(), observed_form_, best_matches_,
555 *preferred_match_, wait_for_username); 551 *preferred_match_, wait_for_username);
556 } 552 }
557 553
558 void PasswordFormManager::OnGetPasswordStoreResults( 554 void PasswordFormManager::OnGetPasswordStoreResults(
559 const std::vector<autofill::PasswordForm*>& results) { 555 ScopedVector<PasswordForm> results) {
560 DCHECK_EQ(state_, MATCHING_PHASE); 556 DCHECK_EQ(state_, MATCHING_PHASE);
561 557
562 scoped_ptr<BrowserSavePasswordProgressLogger> logger; 558 scoped_ptr<BrowserSavePasswordProgressLogger> logger;
563 if (client_->IsLoggingActive()) { 559 if (client_->IsLoggingActive()) {
564 logger.reset(new BrowserSavePasswordProgressLogger(client_)); 560 logger.reset(new BrowserSavePasswordProgressLogger(client_));
565 logger->LogMessage(Logger::STRING_ON_GET_STORE_RESULTS_METHOD); 561 logger->LogMessage(Logger::STRING_ON_GET_STORE_RESULTS_METHOD);
566 logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size()); 562 logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size());
567 } 563 }
568 564
569 if (!results.empty()) 565 if (!results.empty())
570 OnRequestDone(results); 566 OnRequestDone(results.Pass());
571 state_ = POST_MATCHING_PHASE; 567 state_ = POST_MATCHING_PHASE;
572 568
573 if (manager_action_ != kManagerActionBlacklisted) { 569 if (manager_action_ != kManagerActionBlacklisted) {
574 for (auto const& driver : drivers_) 570 for (auto const& driver : drivers_)
575 ProcessFrame(driver); 571 ProcessFrame(driver);
576 } 572 }
577 drivers_.clear(); 573 drivers_.clear();
578 } 574 }
579 575
580 bool PasswordFormManager::ShouldIgnoreResult(const PasswordForm& form) const { 576 bool PasswordFormManager::ShouldIgnoreResult(const PasswordForm& form) const {
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED); 858 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED);
863 } 859 }
864 860
865 void PasswordFormManager::SubmitFailed() { 861 void PasswordFormManager::SubmitFailed() {
866 submit_result_ = kSubmitResultFailed; 862 submit_result_ = kSubmitResultFailed;
867 if (has_generated_password_) 863 if (has_generated_password_)
868 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED); 864 LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED);
869 } 865 }
870 866
871 } // namespace password_manager 867 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698