Index: components/password_manager/core/browser/password_form_manager.cc |
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc |
index e7a1ccda88dbcb6391debcf9860a3e91a33f78f6..d1f35e2b919dfc50bf189b55899d35c27e75c08a 100644 |
--- a/components/password_manager/core/browser/password_form_manager.cc |
+++ b/components/password_manager/core/browser/password_form_manager.cc |
@@ -10,10 +10,8 @@ |
#include <map> |
#include <utility> |
-#include "base/command_line.h" |
#include "base/feature_list.h" |
#include "base/memory/ptr_util.h" |
-#include "base/metrics/field_trial.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/metrics/user_metrics.h" |
#include "base/strings/string16.h" |
@@ -24,11 +22,9 @@ |
#include "components/autofill/core/browser/autofill_manager.h" |
#include "components/autofill/core/browser/proto/server.pb.h" |
#include "components/autofill/core/browser/validation.h" |
-#include "components/autofill/core/common/autofill_switches.h" |
#include "components/autofill/core/common/password_form.h" |
#include "components/password_manager/core/browser/affiliation_utils.h" |
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h" |
-#include "components/password_manager/core/browser/credentials_filter.h" |
#include "components/password_manager/core/browser/form_saver.h" |
#include "components/password_manager/core/browser/log_manager.h" |
#include "components/password_manager/core/browser/password_manager.h" |
@@ -90,23 +86,6 @@ bool IsProbablyNotUsername(const base::string16& s) { |
return !s.empty() && DoesStringContainOnlyDigits(s) && s.size() < 3; |
} |
-// Splits federated matches from |store_results| into a separate vector and |
-// returns that. |
-std::vector<std::unique_ptr<PasswordForm>> SplitFederatedMatches( |
- std::vector<std::unique_ptr<PasswordForm>>* store_results) { |
- auto first_federated = |
- std::partition(store_results->begin(), store_results->end(), |
- [](const std::unique_ptr<PasswordForm>& form) { |
- return form->federation_origin.unique(); |
- }); |
- |
- std::vector<std::unique_ptr<PasswordForm>> federated_matches( |
- store_results->end() - first_federated); |
- std::move(first_federated, store_results->end(), federated_matches.begin()); |
- store_results->erase(first_federated, store_results->end()); |
- return federated_matches; |
-} |
- |
bool ShouldShowInitialPasswordAccountSuggestions() { |
return base::FeatureList::IsEnabled( |
password_manager::features::kFillOnAccountSelect); |
@@ -198,19 +177,21 @@ PasswordFormManager::PasswordFormManager( |
is_ignorable_change_password_form_(false), |
is_possible_change_password_form_without_username_( |
observed_form.IsPossibleChangePasswordFormWithoutUsername()), |
- state_(State::NOT_WAITING), |
client_(client), |
manager_action_(kManagerActionNone), |
user_action_(kUserActionNone), |
submit_result_(kSubmitResultNotSubmitted), |
form_type_(kFormTypeUnspecified), |
need_to_refetch_(false), |
- form_saver_(std::move(form_saver)) { |
+ form_saver_(std::move(form_saver)), |
+ form_fetcher_impl_(client), |
+ form_fetcher_(&form_fetcher_impl_) { |
DCHECK_EQ(observed_form.scheme == PasswordForm::SCHEME_HTML, |
driver != nullptr); |
if (driver) |
drivers_.push_back(driver); |
FetchDataFromPasswordStore(); |
+ form_fetcher_->AddConsumer(this); |
} |
PasswordFormManager::~PasswordFormManager() { |
@@ -302,22 +283,23 @@ PasswordFormManager::MatchResultMask PasswordFormManager::DoesManage( |
} |
bool PasswordFormManager::IsBlacklisted() const { |
- DCHECK_EQ(State::NOT_WAITING, state_); |
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState()); |
return !blacklisted_matches_.empty(); |
} |
void PasswordFormManager::PermanentlyBlacklist() { |
- DCHECK_EQ(State::NOT_WAITING, state_); |
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState()); |
DCHECK(!client_->IsOffTheRecord()); |
- blacklisted_matches_owned_.push_back( |
- base::MakeUnique<PasswordForm>(observed_form_)); |
- blacklisted_matches_.push_back(blacklisted_matches_owned_.back().get()); |
- form_saver_->PermanentlyBlacklist(blacklisted_matches_owned_.back().get()); |
+ if (!new_blacklisted_) { |
+ new_blacklisted_ = base::MakeUnique<PasswordForm>(observed_form_); |
+ blacklisted_matches_.push_back(new_blacklisted_.get()); |
+ } |
+ form_saver_->PermanentlyBlacklist(new_blacklisted_.get()); |
} |
bool PasswordFormManager::IsNewLogin() const { |
- DCHECK_EQ(State::NOT_WAITING, state_); |
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState()); |
return is_new_login_; |
} |
@@ -348,7 +330,7 @@ void PasswordFormManager::ProvisionallySave( |
} |
void PasswordFormManager::Save() { |
- DCHECK_EQ(State::NOT_WAITING, state_); |
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState()); |
DCHECK(!client_->IsOffTheRecord()); |
if ((user_action_ == kUserActionNone) && |
@@ -405,7 +387,7 @@ void PasswordFormManager::Update( |
} |
void PasswordFormManager::FetchDataFromPasswordStore() { |
- if (state_ == State::WAITING) { |
+ if (form_fetcher_->GetState() == FormFetcher::State::WAITING) { |
// There is currently a password store query in progress, need to re-fetch |
// store results later. |
need_to_refetch_ = true; |
@@ -418,11 +400,11 @@ void PasswordFormManager::FetchDataFromPasswordStore() { |
new BrowserSavePasswordProgressLogger(client_->GetLogManager())); |
logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD); |
logger->LogNumber(Logger::STRING_FORM_MANAGER_STATE, |
- static_cast<int>(state_)); |
+ static_cast<int>(form_fetcher_->GetState())); |
} |
provisionally_saved_form_.reset(); |
- state_ = State::WAITING; |
+ form_fetcher_impl_.set_state(FormFetcher::State::WAITING); |
PasswordStore* password_store = client_->GetPasswordStore(); |
if (!password_store) { |
@@ -444,7 +426,7 @@ void PasswordFormManager::FetchDataFromPasswordStore() { |
} |
bool PasswordFormManager::HasCompletedMatching() const { |
- return state_ == State::NOT_WAITING; |
+ return form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING; |
} |
void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) { |
@@ -480,92 +462,102 @@ void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) { |
} |
} |
-void PasswordFormManager::OnRequestDone( |
- std::vector<std::unique_ptr<PasswordForm>> logins_result) { |
+void PasswordFormManager::ProcessMatches( |
+ const std::vector<const PasswordForm*>& non_federated, |
+ size_t filtered_count) { |
preferred_match_ = nullptr; |
best_matches_.clear(); |
- best_matches_owned_.clear(); |
not_best_matches_.clear(); |
- not_best_matches_owned_.clear(); |
blacklisted_matches_.clear(); |
- blacklisted_matches_owned_.clear(); |
- const size_t logins_result_size = logins_result.size(); |
+ new_blacklisted_.reset(); |
std::unique_ptr<BrowserSavePasswordProgressLogger> logger; |
if (password_manager_util::IsLoggingActive(client_)) { |
logger.reset( |
new BrowserSavePasswordProgressLogger(client_->GetLogManager())); |
- logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD); |
+ logger->LogMessage(Logger::STRING_PROCESS_MATCHES_METHOD); |
} |
- // Remove credentials which need to be ignored from |logins_result|. |
- logins_result = |
- client_->GetStoreResultFilter()->FilterResults(std::move(logins_result)); |
- |
- // Deal with blacklisted forms. |
- auto begin_blacklisted = |
- std::partition(logins_result.begin(), logins_result.end(), |
- [](const std::unique_ptr<PasswordForm>& form) { |
- return !form->blacklisted_by_user; |
- }); |
- for (auto it = begin_blacklisted; it != logins_result.end(); ++it) { |
- if (IsBlacklistMatch(**it)) { |
- blacklisted_matches_.push_back(it->get()); |
- blacklisted_matches_owned_.push_back(std::move(*it)); |
- } |
- } |
- logins_result.erase(begin_blacklisted, logins_result.end()); |
- if (logins_result.empty()) |
- return; |
+ // Create a copy of |non_federated| which we can reorder and prune. |
+ std::vector<const PasswordForm*> all_matches(non_federated); |
+ |
+ // The next step is to reorder |all_matches| into three consequent blocks: |
+ // (A) relevant blacklist entries |
+ // (B) non-relevant blacklist entries |
+ // (C) non-blacklisted matches |
+ |
+ auto begin_nonblacklisted = // start of block (C) |
+ std::partition( |
+ all_matches.begin(), all_matches.end(), |
+ [](const PasswordForm* form) { return form->blacklisted_by_user; }); |
- // Now compute scores for the remaining credentials in |login_result|. |
- std::vector<uint32_t> credential_scores; |
- credential_scores.reserve(logins_result.size()); |
+ auto begin_nonrelevant = // start of block (B) |
+ std::partition( |
+ all_matches.begin(), begin_nonblacklisted, |
+ [this](const PasswordForm* form) { return IsBlacklistMatch(*form); }); |
+ |
+ // Now compute scores for forms in block (C). |
+ const size_t non_blacklist_count = all_matches.end() - begin_nonblacklisted; |
+ std::vector<uint32_t> credential_scores; // scores for forms from (C) |
+ credential_scores.reserve(non_blacklist_count); |
uint32_t best_score = 0; |
- std::map<base::string16, uint32_t> best_scores; |
- for (const auto& login : logins_result) { |
- uint32_t current_score = ScoreResult(*login); |
+ std::map<base::string16, uint32_t> best_scores; // best scores for usernames |
+ for (auto it = begin_nonblacklisted; it != all_matches.end(); ++it) { |
+ const PasswordForm& login = **it; |
+ uint32_t current_score = ScoreResult(login); |
best_score = std::max(best_score, current_score); |
- best_scores[login->username_value] = |
- std::max(best_scores[login->username_value], current_score); |
+ best_scores[login.username_value] = |
+ std::max(best_scores[login.username_value], current_score); |
credential_scores.push_back(current_score); |
} |
+ not_best_matches_.reserve(non_blacklist_count - best_scores.size()); |
// Fill |best_matches_| with the best-scoring credentials for each username. |
- for (size_t i = 0; i < logins_result.size(); ++i) { |
- auto login = std::move(logins_result[i]); |
+ for (size_t i = 0; i < non_blacklist_count; ++i) { |
+ const PasswordForm* login = *(begin_nonblacklisted + i); |
DCHECK(!login->blacklisted_by_user); |
const base::string16& username = login->username_value; |
if (credential_scores[i] < best_scores[username]) { |
- not_best_matches_.push_back(login.get()); |
- not_best_matches_owned_.push_back(std::move(login)); |
+ not_best_matches_.push_back(login); |
continue; |
} |
if (!preferred_match_ && credential_scores[i] == best_score) |
- preferred_match_ = login.get(); |
+ preferred_match_ = login; |
// If there is another best-score match for the same username then leave it |
// and add the current form to |not_best_matches_|. |
auto best_match_username = best_matches_.find(username); |
if (best_match_username == best_matches_.end()) { |
- best_matches_.insert(std::make_pair(username, login.get())); |
- best_matches_owned_.push_back(std::move(login)); |
+ best_matches_.insert(std::make_pair(username, login)); |
} else { |
- not_best_matches_.push_back(login.get()); |
- not_best_matches_owned_.push_back(std::move(login)); |
+ not_best_matches_.push_back(login); |
} |
} |
- UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown", |
- logins_result_size - best_matches_.size()); |
+ all_matches.erase(begin_nonrelevant, all_matches.end()); |
+ blacklisted_matches_ = std::move(all_matches); |
+ |
+ UMA_HISTOGRAM_COUNTS( |
+ "PasswordManager.NumPasswordsNotShown", |
+ non_federated.size() + filtered_count - best_matches_.size()); |
+ |
+ // If password store was slow and provisionally saved form is already here |
+ // then create pending credentials (see http://crbug.com/470322). |
+ if (provisionally_saved_form_) |
+ CreatePendingCredentials(); |
+ |
+ for (auto const& driver : drivers_) |
+ ProcessFrameInternal(driver); |
+ if (observed_form_.scheme != PasswordForm::SCHEME_HTML) |
+ ProcessLoginPrompt(); |
} |
void PasswordFormManager::ProcessFrame( |
const base::WeakPtr<PasswordManagerDriver>& driver) { |
DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form_.scheme); |
- if (state_ == State::NOT_WAITING) |
+ if (form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING) |
ProcessFrameInternal(driver); |
for (auto const& old_driver : drivers_) { |
@@ -622,8 +614,8 @@ void PasswordFormManager::ProcessFrameInternal( |
// If fill-on-account-select is not enabled, continue with autofilling any |
// password forms as traditionally has been done. |
password_manager_->Autofill(driver.get(), observed_form_, best_matches_, |
- federated_matches_, *preferred_match_, |
- wait_for_username); |
+ form_fetcher_->GetFederatedMatches(), |
+ *preferred_match_, wait_for_username); |
} |
} |
@@ -638,11 +630,11 @@ void PasswordFormManager::ProcessLoginPrompt() { |
void PasswordFormManager::OnGetPasswordStoreResults( |
std::vector<std::unique_ptr<autofill::PasswordForm>> results) { |
- DCHECK_EQ(State::WAITING, state_); |
+ DCHECK_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState()); |
if (need_to_refetch_) { |
// The received results are no longer up to date, need to re-request. |
- state_ = State::NOT_WAITING; |
+ form_fetcher_impl_.set_state(FormFetcher::State::NOT_WAITING); |
FetchDataFromPasswordStore(); |
need_to_refetch_ = false; |
return; |
@@ -656,43 +648,18 @@ void PasswordFormManager::OnGetPasswordStoreResults( |
logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size()); |
} |
- federated_matches_owned_ = SplitFederatedMatches(&results); |
- federated_matches_.resize(federated_matches_owned_.size()); |
- std::transform( |
- federated_matches_owned_.begin(), federated_matches_owned_.end(), |
- federated_matches_.begin(), |
- [](const std::unique_ptr<PasswordForm>& form) { return form.get(); }); |
- |
- if (!results.empty()) |
- OnRequestDone(std::move(results)); |
- state_ = State::NOT_WAITING; |
- |
- // If password store was slow and provisionally saved form is already here |
- // then create pending credentials (see http://crbug.com/470322). |
- if (provisionally_saved_form_) |
- CreatePendingCredentials(); |
- |
- for (auto const& driver : drivers_) |
- ProcessFrameInternal(driver); |
- if (observed_form_.scheme != PasswordForm::SCHEME_HTML) |
- ProcessLoginPrompt(); |
+ form_fetcher_impl_.SetResults(std::move(results)); |
} |
void PasswordFormManager::OnGetSiteStatistics( |
std::vector<std::unique_ptr<InteractionsStats>> stats) { |
// On Windows the password request may be resolved after the statistics due to |
// importing from IE. |
- interactions_stats_owned_.swap(stats); |
- interactions_stats_.resize(interactions_stats_owned_.size()); |
- std::transform(interactions_stats_owned_.begin(), |
- interactions_stats_owned_.end(), interactions_stats_.begin(), |
- [](const std::unique_ptr<InteractionsStats>& stat) { |
- return stat.get(); |
- }); |
+ form_fetcher_impl_.SetStats(std::move(stats)); |
} |
void PasswordFormManager::ProcessUpdate() { |
- DCHECK_EQ(State::NOT_WAITING, state_); |
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState()); |
DCHECK(preferred_match_ || !pending_credentials_.federation_origin.unique()); |
// If we're doing an Update, we either autofilled correctly and need to |
// update the stats, or the user typed in a new password for autofilled |
@@ -1133,7 +1100,6 @@ void PasswordFormManager::CreatePendingCredentials() { |
} |
uint32_t PasswordFormManager::ScoreResult(const PasswordForm& candidate) const { |
- DCHECK_EQ(State::WAITING, state_); |
DCHECK(!candidate.blacklisted_by_user); |
// For scoring of candidate login data: |
// The most important element that should match is the signon_realm followed |
@@ -1229,9 +1195,9 @@ const PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword( |
if (password.empty()) |
return nullptr; |
- for (auto it = best_matches_.begin(); it != best_matches_.end(); ++it) { |
- if (it->second->password_value == password) |
- return it->second; |
+ for (const auto& key_value : best_matches_) { |
+ if (key_value.second->password_value == password) |
+ return key_value.second; |
} |
return nullptr; |
} |