diff options
Diffstat (limited to 'chromium/components/autofill/core/browser/autofill_manager.cc')
-rw-r--r-- | chromium/components/autofill/core/browser/autofill_manager.cc | 1114 |
1 files changed, 0 insertions, 1114 deletions
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc deleted file mode 100644 index edaa35e780f..00000000000 --- a/chromium/components/autofill/core/browser/autofill_manager.cc +++ /dev/null @@ -1,1114 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/autofill_manager.h" - -#include <stddef.h> - -#include <limits> -#include <map> -#include <set> -#include <utility> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/guid.h" -#include "base/logging.h" -#include "base/prefs/pref_service.h" -#include "base/strings/string16.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/sequenced_worker_pool.h" -#include "components/autofill/core/browser/autocomplete_history_manager.h" -#include "components/autofill/core/browser/autofill_data_model.h" -#include "components/autofill/core/browser/autofill_driver.h" -#include "components/autofill/core/browser/autofill_external_delegate.h" -#include "components/autofill/core/browser/autofill_field.h" -#include "components/autofill/core/browser/autofill_manager_delegate.h" -#include "components/autofill/core/browser/autofill_manager_test_delegate.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/autofill_type.h" -#include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/phone_number.h" -#include "components/autofill/core/browser/phone_number_i18n.h" -#include "components/autofill/core/common/autofill_pref_names.h" -#include "components/autofill/core/common/autofill_switches.h" -#include "components/autofill/core/common/form_data.h" -#include "components/autofill/core/common/form_data_predictions.h" -#include "components/autofill/core/common/form_field_data.h" -#include "components/autofill/core/common/password_form_fill_data.h" -#include "components/user_prefs/pref_registry_syncable.h" -#include "grit/component_strings.h" -#include "third_party/WebKit/public/web/WebAutofillClient.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/rect.h" -#include "url/gurl.h" - -namespace autofill { - -typedef PersonalDataManager::GUIDPair GUIDPair; - -using base::TimeTicks; - -namespace { - -// We only send a fraction of the forms to upload server. -// The rate for positive/negative matches potentially could be different. -const double kAutofillPositiveUploadRateDefaultValue = 0.20; -const double kAutofillNegativeUploadRateDefaultValue = 0.20; - -const size_t kMaxRecentFormSignaturesToRemember = 3; - -// Set a conservative upper bound on the number of forms we are willing to -// cache, simply to prevent unbounded memory consumption. -const size_t kMaxFormCacheSize = 100; - -// Removes duplicate suggestions whilst preserving their original order. -void RemoveDuplicateSuggestions(std::vector<base::string16>* values, - std::vector<base::string16>* labels, - std::vector<base::string16>* icons, - std::vector<int>* unique_ids) { - DCHECK_EQ(values->size(), labels->size()); - DCHECK_EQ(values->size(), icons->size()); - DCHECK_EQ(values->size(), unique_ids->size()); - - std::set<std::pair<base::string16, base::string16> > seen_suggestions; - std::vector<base::string16> values_copy; - std::vector<base::string16> labels_copy; - std::vector<base::string16> icons_copy; - std::vector<int> unique_ids_copy; - - for (size_t i = 0; i < values->size(); ++i) { - const std::pair<base::string16, base::string16> suggestion( - (*values)[i], (*labels)[i]); - if (seen_suggestions.insert(suggestion).second) { - values_copy.push_back((*values)[i]); - labels_copy.push_back((*labels)[i]); - icons_copy.push_back((*icons)[i]); - unique_ids_copy.push_back((*unique_ids)[i]); - } - } - - values->swap(values_copy); - labels->swap(labels_copy); - icons->swap(icons_copy); - unique_ids->swap(unique_ids_copy); -} - -// Precondition: |form_structure| and |form| should correspond to the same -// logical form. Returns true if any field in the given |section| within |form| -// is auto-filled. -bool SectionIsAutofilled(const FormStructure& form_structure, - const FormData& form, - const std::string& section) { - DCHECK_EQ(form_structure.field_count(), form.fields.size()); - for (size_t i = 0; i < form_structure.field_count(); ++i) { - if (form_structure.field(i)->section() == section && - form.fields[i].is_autofilled) { - return true; - } - } - - return false; -} - -bool FormIsHTTPS(const FormStructure& form) { - // TODO(blundell): Change this to use a constant once crbug.com/306258 is - // fixed. - return form.source_url().SchemeIs("https"); -} - -// Uses the existing personal data in |profiles| and |credit_cards| to determine -// possible field types for the |submitted_form|. This is potentially -// expensive -- on the order of 50ms even for a small set of |stored_data|. -// Hence, it should not run on the UI thread -- to avoid locking up the UI -- -// nor on the IO thread -- to avoid blocking IPC calls. -void DeterminePossibleFieldTypesForUpload( - const std::vector<AutofillProfile>& profiles, - const std::vector<CreditCard>& credit_cards, - const std::string& app_locale, - FormStructure* submitted_form) { - // For each field in the |submitted_form|, extract the value. Then for each - // profile or credit card, identify any stored types that match the value. - for (size_t i = 0; i < submitted_form->field_count(); ++i) { - AutofillField* field = submitted_form->field(i); - ServerFieldTypeSet matching_types; - - // If it's a password field, set the type directly. - if (field->form_control_type == "password") { - matching_types.insert(autofill::PASSWORD); - } else { - base::string16 value; - TrimWhitespace(field->value, TRIM_ALL, &value); - for (std::vector<AutofillProfile>::const_iterator it = profiles.begin(); - it != profiles.end(); ++it) { - it->GetMatchingTypes(value, app_locale, &matching_types); - } - for (std::vector<CreditCard>::const_iterator it = credit_cards.begin(); - it != credit_cards.end(); ++it) { - it->GetMatchingTypes(value, app_locale, &matching_types); - } - } - - if (matching_types.empty()) - matching_types.insert(UNKNOWN_TYPE); - - field->set_possible_types(matching_types); - } -} - -} // namespace - -AutofillManager::AutofillManager( - AutofillDriver* driver, - autofill::AutofillManagerDelegate* delegate, - const std::string& app_locale, - AutofillDownloadManagerState enable_download_manager) - : driver_(driver), - manager_delegate_(delegate), - app_locale_(app_locale), - personal_data_(delegate->GetPersonalDataManager()), - autocomplete_history_manager_( - new AutocompleteHistoryManager(driver, delegate)), - metric_logger_(new AutofillMetrics), - has_logged_autofill_enabled_(false), - has_logged_address_suggestions_count_(false), - did_show_suggestions_(false), - user_did_type_(false), - user_did_autofill_(false), - user_did_edit_autofilled_field_(false), - external_delegate_(NULL), - test_delegate_(NULL), - weak_ptr_factory_(this) { - if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) { - download_manager_.reset( - new AutofillDownloadManager(driver, - manager_delegate_->GetPrefs(), - this)); - } -} - -AutofillManager::~AutofillManager() {} - -// static -void AutofillManager::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterBooleanPref( - prefs::kAutofillEnabled, - true, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); -#if defined(OS_MACOSX) || defined(OS_ANDROID) - registry->RegisterBooleanPref( - prefs::kAutofillAuxiliaryProfilesEnabled, - true, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); -#else - registry->RegisterBooleanPref( - prefs::kAutofillAuxiliaryProfilesEnabled, - false, - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); -#endif - registry->RegisterDoublePref( - prefs::kAutofillPositiveUploadRate, - kAutofillPositiveUploadRateDefaultValue, - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); - registry->RegisterDoublePref( - prefs::kAutofillNegativeUploadRate, - kAutofillNegativeUploadRateDefaultValue, - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); -} - -void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) { - // TODO(jrg): consider passing delegate into the ctor. That won't - // work if the delegate has a pointer to the AutofillManager, but - // future directions may not need such a pointer. - external_delegate_ = delegate; - autocomplete_history_manager_->SetExternalDelegate(delegate); -} - -bool AutofillManager::OnFormSubmitted(const FormData& form, - const TimeTicks& timestamp) { - // Let Autocomplete know as well. - autocomplete_history_manager_->OnFormSubmitted(form); - - // Grab a copy of the form data. - scoped_ptr<FormStructure> submitted_form(new FormStructure(form)); - - if (!ShouldUploadForm(*submitted_form)) - return false; - - // Don't save data that was submitted through JavaScript. - if (!form.user_submitted) - return false; - - // Ignore forms not present in our cache. These are typically forms with - // wonky JavaScript that also makes them not auto-fillable. - FormStructure* cached_submitted_form; - if (!FindCachedForm(form, &cached_submitted_form)) - return false; - - submitted_form->UpdateFromCache(*cached_submitted_form); - if (submitted_form->IsAutofillable(true)) - ImportFormData(*submitted_form); - - // Only upload server statistics and UMA metrics if at least some local data - // is available to use as a baseline. - const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); - const std::vector<CreditCard*>& credit_cards = - personal_data_->GetCreditCards(); - if (!profiles.empty() || !credit_cards.empty()) { - // Copy the profile and credit card data, so that it can be accessed on a - // separate thread. - std::vector<AutofillProfile> copied_profiles; - copied_profiles.reserve(profiles.size()); - for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin(); - it != profiles.end(); ++it) { - copied_profiles.push_back(**it); - } - - std::vector<CreditCard> copied_credit_cards; - copied_credit_cards.reserve(credit_cards.size()); - for (std::vector<CreditCard*>::const_iterator it = credit_cards.begin(); - it != credit_cards.end(); ++it) { - copied_credit_cards.push_back(**it); - } - - // Note that ownership of |submitted_form| is passed to the second task, - // using |base::Owned|. - FormStructure* raw_submitted_form = submitted_form.get(); - driver_->GetBlockingPool()->PostTaskAndReply( - FROM_HERE, - base::Bind(&DeterminePossibleFieldTypesForUpload, - copied_profiles, - copied_credit_cards, - app_locale_, - raw_submitted_form), - base::Bind(&AutofillManager::UploadFormDataAsyncCallback, - weak_ptr_factory_.GetWeakPtr(), - base::Owned(submitted_form.release()), - forms_loaded_timestamp_, - initial_interaction_timestamp_, - timestamp)); - } - - return true; -} - -void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms, - const TimeTicks& timestamp, - autofill::FormsSeenState state) { - bool is_post_document_load = state == autofill::DYNAMIC_FORMS_SEEN; - // If new forms were added dynamically, treat as a new page. - if (is_post_document_load) - Reset(); - - if (!driver_->RendererIsAvailable()) - return; - - bool enabled = IsAutofillEnabled(); - if (!has_logged_autofill_enabled_) { - metric_logger_->LogIsAutofillEnabledAtPageLoad(enabled); - has_logged_autofill_enabled_ = true; - } - - if (!enabled) - return; - - forms_loaded_timestamp_ = timestamp; - ParseForms(forms); -} - -void AutofillManager::OnTextFieldDidChange(const FormData& form, - const FormFieldData& field, - const TimeTicks& timestamp) { - FormStructure* form_structure = NULL; - AutofillField* autofill_field = NULL; - if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field)) - return; - - if (!user_did_type_) { - user_did_type_ = true; - metric_logger_->LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE); - } - - if (autofill_field->is_autofilled) { - autofill_field->is_autofilled = false; - metric_logger_->LogUserHappinessMetric( - AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD); - - if (!user_did_edit_autofilled_field_) { - user_did_edit_autofilled_field_ = true; - metric_logger_->LogUserHappinessMetric( - AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE); - } - } - - UpdateInitialInteractionTimestamp(timestamp); -} - -void AutofillManager::OnQueryFormFieldAutofill(int query_id, - const FormData& form, - const FormFieldData& field, - const gfx::RectF& bounding_box, - bool display_warning) { - std::vector<base::string16> values; - std::vector<base::string16> labels; - std::vector<base::string16> icons; - std::vector<int> unique_ids; - - external_delegate_->OnQuery(query_id, - form, - field, - bounding_box, - display_warning); - FormStructure* form_structure = NULL; - AutofillField* autofill_field = NULL; - if (RefreshDataModels() && - driver_->RendererIsAvailable() && - GetCachedFormAndField(form, field, &form_structure, &autofill_field) && - // Don't send suggestions for forms that aren't auto-fillable. - form_structure->IsAutofillable(false)) { - AutofillType type = autofill_field->Type(); - bool is_filling_credit_card = (type.group() == CREDIT_CARD); - if (is_filling_credit_card) { - GetCreditCardSuggestions( - field, type, &values, &labels, &icons, &unique_ids); - } else { - GetProfileSuggestions( - form_structure, field, type, &values, &labels, &icons, &unique_ids); - } - - DCHECK_EQ(values.size(), labels.size()); - DCHECK_EQ(values.size(), icons.size()); - DCHECK_EQ(values.size(), unique_ids.size()); - - if (!values.empty()) { - // Don't provide Autofill suggestions when Autofill is disabled, and don't - // provide credit card suggestions for non-HTTPS pages. However, provide a - // warning to the user in these cases. - int warning = 0; - if (!form_structure->IsAutofillable(true)) - warning = IDS_AUTOFILL_WARNING_FORM_DISABLED; - else if (is_filling_credit_card && !FormIsHTTPS(*form_structure)) - warning = IDS_AUTOFILL_WARNING_INSECURE_CONNECTION; - if (warning) { - values.assign(1, l10n_util::GetStringUTF16(warning)); - labels.assign(1, base::string16()); - icons.assign(1, base::string16()); - unique_ids.assign(1, - blink::WebAutofillClient::MenuItemIDWarningMessage); - } else { - bool section_is_autofilled = - SectionIsAutofilled(*form_structure, form, - autofill_field->section()); - if (section_is_autofilled) { - // If the relevant section is auto-filled and the renderer is querying - // for suggestions, then the user is editing the value of a field. - // In this case, mimic autocomplete: don't display labels or icons, - // as that information is redundant. - labels.assign(labels.size(), base::string16()); - icons.assign(icons.size(), base::string16()); - } - - // When filling credit card suggestions, the values and labels are - // typically obfuscated, which makes detecting duplicates hard. Since - // duplicates only tend to be a problem when filling address forms - // anyway, only don't de-dup credit card suggestions. - if (!is_filling_credit_card) - RemoveDuplicateSuggestions(&values, &labels, &icons, &unique_ids); - - // The first time we show suggestions on this page, log the number of - // suggestions shown. - if (!has_logged_address_suggestions_count_ && !section_is_autofilled) { - metric_logger_->LogAddressSuggestionsCount(values.size()); - has_logged_address_suggestions_count_ = true; - } - } - } - } - - // Add the results from AutoComplete. They come back asynchronously, so we - // hand off what we generated and they will send the results back to the - // renderer. - autocomplete_history_manager_->OnGetAutocompleteSuggestions( - query_id, field.name, field.value, values, labels, icons, unique_ids); -} - -void AutofillManager::OnFillAutofillFormData(int query_id, - const FormData& form, - const FormFieldData& field, - int unique_id) { - const AutofillDataModel* data_model = NULL; - size_t variant = 0; - FormStructure* form_structure = NULL; - AutofillField* autofill_field = NULL; - // NOTE: RefreshDataModels may invalidate |data_model| because it causes the - // PersonalDataManager to reload Mac address book entries. Thus it must come - // before GetProfileOrCreditCard. - if (!RefreshDataModels() || - !driver_->RendererIsAvailable() || - !GetProfileOrCreditCard(unique_id, &data_model, &variant) || - !GetCachedFormAndField(form, field, &form_structure, &autofill_field)) - return; - - DCHECK(form_structure); - DCHECK(autofill_field); - - FormData result = form; - - // If the relevant section is auto-filled, we should fill |field| but not the - // rest of the form. - if (SectionIsAutofilled(*form_structure, form, autofill_field->section())) { - for (std::vector<FormFieldData>::iterator iter = result.fields.begin(); - iter != result.fields.end(); ++iter) { - if ((*iter) == field) { - base::string16 value = data_model->GetInfoForVariant( - autofill_field->Type(), variant, app_locale_); - AutofillField::FillFormField(*autofill_field, value, app_locale_, - &(*iter)); - // Mark the cached field as autofilled, so that we can detect when a - // user edits an autofilled field (for metrics). - autofill_field->is_autofilled = true; - break; - } - } - - driver_->SendFormDataToRenderer(query_id, result); - return; - } - - // Cache the field type for the field from which the user initiated autofill. - FieldTypeGroup initiating_group_type = autofill_field->Type().group(); - DCHECK_EQ(form_structure->field_count(), form.fields.size()); - for (size_t i = 0; i < form_structure->field_count(); ++i) { - if (form_structure->field(i)->section() != autofill_field->section()) - continue; - - DCHECK_EQ(*form_structure->field(i), result.fields[i]); - - const AutofillField* cached_field = form_structure->field(i); - FieldTypeGroup field_group_type = cached_field->Type().group(); - if (field_group_type != NO_GROUP) { - // If the field being filled is either - // (a) the field that the user initiated the fill from, or - // (b) part of the same logical unit, e.g. name or phone number, - // then take the multi-profile "variant" into account. - // Otherwise fill with the default (zeroth) variant. - size_t use_variant = 0; - if (result.fields[i] == field || - field_group_type == initiating_group_type) { - use_variant = variant; - } - base::string16 value = data_model->GetInfoForVariant( - cached_field->Type(), use_variant, app_locale_); - AutofillField::FillFormField(*cached_field, value, app_locale_, - &result.fields[i]); - // Mark the cached field as autofilled, so that we can detect when a user - // edits an autofilled field (for metrics). - form_structure->field(i)->is_autofilled = true; - } - } - - autofilled_form_signatures_.push_front(form_structure->FormSignature()); - // Only remember the last few forms that we've seen, both to avoid false - // positives and to avoid wasting memory. - if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember) - autofilled_form_signatures_.pop_back(); - - driver_->SendFormDataToRenderer(query_id, result); -} - -void AutofillManager::OnShowAutofillDialog() { - manager_delegate_->ShowAutofillSettings(); -} - -void AutofillManager::OnDidPreviewAutofillFormData() { - if (test_delegate_) - test_delegate_->DidPreviewFormData(); -} - -void AutofillManager::OnDidFillAutofillFormData(const TimeTicks& timestamp) { - if (test_delegate_) - test_delegate_->DidFillFormData(); - - metric_logger_->LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL); - if (!user_did_autofill_) { - user_did_autofill_ = true; - metric_logger_->LogUserHappinessMetric( - AutofillMetrics::USER_DID_AUTOFILL_ONCE); - } - - UpdateInitialInteractionTimestamp(timestamp); -} - -void AutofillManager::OnDidShowAutofillSuggestions(bool is_new_popup) { - if (test_delegate_) - test_delegate_->DidShowSuggestions(); - - if (is_new_popup) { - metric_logger_->LogUserHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN); - - if (!did_show_suggestions_) { - did_show_suggestions_ = true; - metric_logger_->LogUserHappinessMetric( - AutofillMetrics::SUGGESTIONS_SHOWN_ONCE); - } - } -} - -void AutofillManager::OnHideAutofillUI() { - if (!IsAutofillEnabled()) - return; - - manager_delegate_->HideAutofillPopup(); -} - -void AutofillManager::RemoveAutofillProfileOrCreditCard(int unique_id) { - const AutofillDataModel* data_model = NULL; - size_t variant = 0; - if (!GetProfileOrCreditCard(unique_id, &data_model, &variant)) { - NOTREACHED(); - return; - } - - // TODO(csharp): If we are dealing with a variant only the variant should - // be deleted, instead of doing nothing. - // http://crbug.com/124211 - if (variant != 0) - return; - - personal_data_->RemoveByGUID(data_model->guid()); -} - -void AutofillManager::RemoveAutocompleteEntry(const base::string16& name, - const base::string16& value) { - autocomplete_history_manager_->OnRemoveAutocompleteEntry(name, value); -} - -const std::vector<FormStructure*>& AutofillManager::GetFormStructures() { - return form_structures_.get(); -} - -void AutofillManager::SetTestDelegate( - autofill::AutofillManagerTestDelegate* delegate) { - test_delegate_ = delegate; -} - -void AutofillManager::OnAddPasswordFormMapping( - const FormFieldData& form, - const PasswordFormFillData& fill_data) { - external_delegate_->AddPasswordFormMapping(form, fill_data); -} - -void AutofillManager::OnShowPasswordSuggestions( - const FormFieldData& field, - const gfx::RectF& bounds, - const std::vector<base::string16>& suggestions, - const std::vector<base::string16>& realms) { - // Bail if the IPC message is corrupt. - if (suggestions.size() != realms.size()) - return; - - external_delegate_->OnShowPasswordSuggestions(suggestions, - realms, - field, - bounds); -} - -void AutofillManager::OnSetDataList(const std::vector<base::string16>& values, - const std::vector<base::string16>& labels) { - // Bail if the IPC message is corrupt. - if (values.size() != labels.size()) - return; - - external_delegate_->SetCurrentDataListValues(values, labels); -} - -void AutofillManager::OnLoadedServerPredictions( - const std::string& response_xml) { - // Parse and store the server predictions. - FormStructure::ParseQueryResponse(response_xml, - form_structures_.get(), - *metric_logger_); - - // Forward form structures to the password generation manager to detect - // account creation forms. - manager_delegate_->DetectAccountCreationForms(form_structures_.get()); - - // If the corresponding flag is set, annotate forms with the predicted types. - driver_->SendAutofillTypePredictionsToRenderer(form_structures_.get()); -} - -void AutofillManager::OnDidEndTextFieldEditing() { - external_delegate_->DidEndTextFieldEditing(); -} - -bool AutofillManager::IsAutofillEnabled() const { - return manager_delegate_->GetPrefs()->GetBoolean(prefs::kAutofillEnabled); -} - -void AutofillManager::ImportFormData(const FormStructure& submitted_form) { - scoped_ptr<CreditCard> imported_credit_card; - if (!personal_data_->ImportFormData(submitted_form, &imported_credit_card)) - return; - - // If credit card information was submitted, we need to confirm whether to - // save it. - if (imported_credit_card) { - manager_delegate_->ConfirmSaveCreditCard( - *metric_logger_, - base::Bind( - base::IgnoreResult(&PersonalDataManager::SaveImportedCreditCard), - base::Unretained(personal_data_), *imported_credit_card)); - } -} - -// Note that |submitted_form| is passed as a pointer rather than as a reference -// so that we can get memory management right across threads. Note also that we -// explicitly pass in all the time stamps of interest, as the cached ones might -// get reset before this method executes. -void AutofillManager::UploadFormDataAsyncCallback( - const FormStructure* submitted_form, - const TimeTicks& load_time, - const TimeTicks& interaction_time, - const TimeTicks& submission_time) { - submitted_form->LogQualityMetrics(*metric_logger_, - load_time, - interaction_time, - submission_time); - - if (submitted_form->ShouldBeCrowdsourced()) - UploadFormData(*submitted_form); -} - -void AutofillManager::UploadFormData(const FormStructure& submitted_form) { - if (!download_manager_) - return; - - // Check if the form is among the forms that were recently auto-filled. - bool was_autofilled = false; - std::string form_signature = submitted_form.FormSignature(); - for (std::list<std::string>::const_iterator it = - autofilled_form_signatures_.begin(); - it != autofilled_form_signatures_.end() && !was_autofilled; - ++it) { - if (*it == form_signature) - was_autofilled = true; - } - - ServerFieldTypeSet non_empty_types; - personal_data_->GetNonEmptyTypes(&non_empty_types); - // Always add PASSWORD to |non_empty_types| so that if |submitted_form| - // contains a password field it will be uploaded to the server. If - // |submitted_form| doesn't contain a password field, there is no side - // effect from adding PASSWORD to |non_empty_types|. - non_empty_types.insert(autofill::PASSWORD); - - download_manager_->StartUploadRequest(submitted_form, was_autofilled, - non_empty_types); -} - -bool AutofillManager::UploadPasswordGenerationForm(const FormData& form) { - FormStructure form_structure(form); - - if (!ShouldUploadForm(form_structure)) - return false; - - if (!form_structure.ShouldBeCrowdsourced()) - return false; - - // TODO(gcasto): Check that PasswordGeneration is enabled? - - // Find the first password field to label. We don't try to label anything - // else. - bool found_password_field = false; - for (size_t i = 0; i < form_structure.field_count(); ++i) { - AutofillField* field = form_structure.field(i); - - ServerFieldTypeSet types; - if (!found_password_field && field->form_control_type == "password") { - types.insert(ACCOUNT_CREATION_PASSWORD); - found_password_field = true; - } else { - types.insert(UNKNOWN_TYPE); - } - field->set_possible_types(types); - } - DCHECK(found_password_field); - - // Only one field type should be present. - ServerFieldTypeSet available_field_types; - available_field_types.insert(ACCOUNT_CREATION_PASSWORD); - - // Force uploading as these events are relatively rare and we want to make - // sure to receive them. It also makes testing easier if these requests - // always pass. - form_structure.set_upload_required(UPLOAD_REQUIRED); - - if (!download_manager_) - return false; - - return download_manager_->StartUploadRequest(form_structure, - false /* was_autofilled */, - available_field_types); -} - -void AutofillManager::Reset() { - form_structures_.clear(); - has_logged_autofill_enabled_ = false; - has_logged_address_suggestions_count_ = false; - did_show_suggestions_ = false; - user_did_type_ = false; - user_did_autofill_ = false; - user_did_edit_autofilled_field_ = false; - forms_loaded_timestamp_ = TimeTicks(); - initial_interaction_timestamp_ = TimeTicks(); - external_delegate_->Reset(); -} - -AutofillManager::AutofillManager(AutofillDriver* driver, - autofill::AutofillManagerDelegate* delegate, - PersonalDataManager* personal_data) - : driver_(driver), - manager_delegate_(delegate), - app_locale_("en-US"), - personal_data_(personal_data), - autocomplete_history_manager_( - new AutocompleteHistoryManager(driver, delegate)), - metric_logger_(new AutofillMetrics), - has_logged_autofill_enabled_(false), - has_logged_address_suggestions_count_(false), - did_show_suggestions_(false), - user_did_type_(false), - user_did_autofill_(false), - user_did_edit_autofilled_field_(false), - external_delegate_(NULL), - test_delegate_(NULL), - weak_ptr_factory_(this) { - DCHECK(driver_); - DCHECK(manager_delegate_); -} - -void AutofillManager::set_metric_logger(const AutofillMetrics* metric_logger) { - metric_logger_.reset(metric_logger); -} - -bool AutofillManager::RefreshDataModels() const { - if (!IsAutofillEnabled()) - return false; - - // No autofill data to return if the profiles are empty. - if (personal_data_->GetProfiles().empty() && - personal_data_->GetCreditCards().empty()) { - return false; - } - - return true; -} - -bool AutofillManager::GetProfileOrCreditCard( - int unique_id, - const AutofillDataModel** data_model, - size_t* variant) const { - // Unpack the |unique_id| into component parts. - GUIDPair credit_card_guid; - GUIDPair profile_guid; - UnpackGUIDs(unique_id, &credit_card_guid, &profile_guid); - DCHECK(!base::IsValidGUID(credit_card_guid.first) || - !base::IsValidGUID(profile_guid.first)); - - // Find the profile that matches the |profile_guid|, if one is specified. - // Otherwise find the credit card that matches the |credit_card_guid|, - // if specified. - if (base::IsValidGUID(profile_guid.first)) { - *data_model = personal_data_->GetProfileByGUID(profile_guid.first); - *variant = profile_guid.second; - } else if (base::IsValidGUID(credit_card_guid.first)) { - *data_model = personal_data_->GetCreditCardByGUID(credit_card_guid.first); - *variant = credit_card_guid.second; - } - - return !!*data_model; -} - -bool AutofillManager::FindCachedForm(const FormData& form, - FormStructure** form_structure) const { - // Find the FormStructure that corresponds to |form|. - // Scan backward through the cached |form_structures_|, as updated versions of - // forms are added to the back of the list, whereas original versions of these - // forms might appear toward the beginning of the list. The communication - // protocol with the crowdsourcing server does not permit us to discard the - // original versions of the forms. - *form_structure = NULL; - for (std::vector<FormStructure*>::const_reverse_iterator iter = - form_structures_.rbegin(); - iter != form_structures_.rend(); ++iter) { - if (**iter == form) { - *form_structure = *iter; - - // The same form might be cached with multiple field counts: in some - // cases, non-autofillable fields are filtered out, whereas in other cases - // they are not. To avoid thrashing the cache, keep scanning until we - // find a cached version with the same number of fields, if there is one. - if ((*iter)->field_count() == form.fields.size()) - break; - } - } - - if (!(*form_structure)) - return false; - - return true; -} - -bool AutofillManager::GetCachedFormAndField(const FormData& form, - const FormFieldData& field, - FormStructure** form_structure, - AutofillField** autofill_field) { - // Find the FormStructure that corresponds to |form|. - // If we do not have this form in our cache but it is parseable, we'll add it - // in the call to |UpdateCachedForm()|. - if (!FindCachedForm(form, form_structure) && - !FormStructure(form).ShouldBeParsed(false)) { - return false; - } - - // Update the cached form to reflect any dynamic changes to the form data, if - // necessary. - if (!UpdateCachedForm(form, *form_structure, form_structure)) - return false; - - // No data to return if there are no auto-fillable fields. - if (!(*form_structure)->autofill_count()) - return false; - - // Find the AutofillField that corresponds to |field|. - *autofill_field = NULL; - for (std::vector<AutofillField*>::const_iterator iter = - (*form_structure)->begin(); - iter != (*form_structure)->end(); ++iter) { - if ((**iter) == field) { - *autofill_field = *iter; - break; - } - } - - // Even though we always update the cache, the field might not exist if the - // website disables autocomplete while the user is interacting with the form. - // See http://crbug.com/160476 - return *autofill_field != NULL; -} - -bool AutofillManager::UpdateCachedForm(const FormData& live_form, - const FormStructure* cached_form, - FormStructure** updated_form) { - bool needs_update = - (!cached_form || - live_form.fields.size() != cached_form->field_count()); - for (size_t i = 0; !needs_update && i < cached_form->field_count(); ++i) { - needs_update = *cached_form->field(i) != live_form.fields[i]; - } - - if (!needs_update) - return true; - - if (form_structures_.size() >= kMaxFormCacheSize) - return false; - - // Add the new or updated form to our cache. - form_structures_.push_back(new FormStructure(live_form)); - *updated_form = *form_structures_.rbegin(); - (*updated_form)->DetermineHeuristicTypes(*metric_logger_); - - // If we have cached data, propagate it to the updated form. - if (cached_form) { - std::map<base::string16, const AutofillField*> cached_fields; - for (size_t i = 0; i < cached_form->field_count(); ++i) { - const AutofillField* field = cached_form->field(i); - cached_fields[field->unique_name()] = field; - } - - for (size_t i = 0; i < (*updated_form)->field_count(); ++i) { - AutofillField* field = (*updated_form)->field(i); - std::map<base::string16, const AutofillField*>::iterator cached_field = - cached_fields.find(field->unique_name()); - if (cached_field != cached_fields.end()) { - field->set_server_type(cached_field->second->server_type()); - field->is_autofilled = cached_field->second->is_autofilled; - } - } - - // Note: We _must not_ remove the original version of the cached form from - // the list of |form_structures_|. Otherwise, we break parsing of the - // crowdsourcing server's response to our query. - } - - // Annotate the updated form with its predicted types. - std::vector<FormStructure*> forms(1, *updated_form); - driver_->SendAutofillTypePredictionsToRenderer(forms); - - return true; -} - -void AutofillManager::GetProfileSuggestions( - FormStructure* form, - const FormFieldData& field, - const AutofillType& type, - std::vector<base::string16>* values, - std::vector<base::string16>* labels, - std::vector<base::string16>* icons, - std::vector<int>* unique_ids) const { - std::vector<ServerFieldType> field_types(form->field_count()); - for (size_t i = 0; i < form->field_count(); ++i) { - field_types.push_back(form->field(i)->Type().GetStorableType()); - } - std::vector<GUIDPair> guid_pairs; - - personal_data_->GetProfileSuggestions( - type, field.value, field.is_autofilled, field_types, - values, labels, icons, &guid_pairs); - - for (size_t i = 0; i < guid_pairs.size(); ++i) { - unique_ids->push_back(PackGUIDs(GUIDPair(std::string(), 0), - guid_pairs[i])); - } -} - -void AutofillManager::GetCreditCardSuggestions( - const FormFieldData& field, - const AutofillType& type, - std::vector<base::string16>* values, - std::vector<base::string16>* labels, - std::vector<base::string16>* icons, - std::vector<int>* unique_ids) const { - std::vector<GUIDPair> guid_pairs; - personal_data_->GetCreditCardSuggestions( - type, field.value, values, labels, icons, &guid_pairs); - - for (size_t i = 0; i < guid_pairs.size(); ++i) { - unique_ids->push_back(PackGUIDs(guid_pairs[i], GUIDPair(std::string(), 0))); - } -} - -void AutofillManager::ParseForms(const std::vector<FormData>& forms) { - std::vector<FormStructure*> non_queryable_forms; - for (std::vector<FormData>::const_iterator iter = forms.begin(); - iter != forms.end(); ++iter) { - scoped_ptr<FormStructure> form_structure(new FormStructure(*iter)); - if (!form_structure->ShouldBeParsed(false)) - continue; - - form_structure->DetermineHeuristicTypes(*metric_logger_); - - // Set aside forms with method GET or author-specified types, so that they - // are not included in the query to the server. - if (form_structure->ShouldBeCrowdsourced()) - form_structures_.push_back(form_structure.release()); - else - non_queryable_forms.push_back(form_structure.release()); - } - - if (!form_structures_.empty() && download_manager_) { - // Query the server if we have at least one of the forms were parsed. - download_manager_->StartQueryRequest(form_structures_.get(), - *metric_logger_); - } - - for (std::vector<FormStructure*>::const_iterator iter = - non_queryable_forms.begin(); - iter != non_queryable_forms.end(); ++iter) { - form_structures_.push_back(*iter); - } - - if (!form_structures_.empty()) - metric_logger_->LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED); - - // For the |non_queryable_forms|, we have all the field type info we're ever - // going to get about them. For the other forms, we'll wait until we get a - // response from the server. - driver_->SendAutofillTypePredictionsToRenderer(non_queryable_forms); -} - -int AutofillManager::GUIDToID(const GUIDPair& guid) const { - if (!base::IsValidGUID(guid.first)) - return 0; - - std::map<GUIDPair, int>::const_iterator iter = guid_id_map_.find(guid); - if (iter == guid_id_map_.end()) { - int id = guid_id_map_.size() + 1; - guid_id_map_[guid] = id; - id_guid_map_[id] = guid; - return id; - } else { - return iter->second; - } -} - -const GUIDPair AutofillManager::IDToGUID(int id) const { - if (id == 0) - return GUIDPair(std::string(), 0); - - std::map<int, GUIDPair>::const_iterator iter = id_guid_map_.find(id); - if (iter == id_guid_map_.end()) { - NOTREACHED(); - return GUIDPair(std::string(), 0); - } - - return iter->second; -} - -// When sending IDs (across processes) to the renderer we pack credit card and -// profile IDs into a single integer. Credit card IDs are sent in the high -// word and profile IDs are sent in the low word. -int AutofillManager::PackGUIDs(const GUIDPair& cc_guid, - const GUIDPair& profile_guid) const { - int cc_id = GUIDToID(cc_guid); - int profile_id = GUIDToID(profile_guid); - - DCHECK(cc_id <= std::numeric_limits<unsigned short>::max()); - DCHECK(profile_id <= std::numeric_limits<unsigned short>::max()); - - return cc_id << std::numeric_limits<unsigned short>::digits | profile_id; -} - -// When receiving IDs (across processes) from the renderer we unpack credit card -// and profile IDs from a single integer. Credit card IDs are stored in the -// high word and profile IDs are stored in the low word. -void AutofillManager::UnpackGUIDs(int id, - GUIDPair* cc_guid, - GUIDPair* profile_guid) const { - int cc_id = id >> std::numeric_limits<unsigned short>::digits & - std::numeric_limits<unsigned short>::max(); - int profile_id = id & std::numeric_limits<unsigned short>::max(); - - *cc_guid = IDToGUID(cc_id); - *profile_guid = IDToGUID(profile_id); -} - -void AutofillManager::UpdateInitialInteractionTimestamp( - const TimeTicks& interaction_timestamp) { - if (initial_interaction_timestamp_.is_null() || - interaction_timestamp < initial_interaction_timestamp_) { - initial_interaction_timestamp_ = interaction_timestamp; - } -} - -bool AutofillManager::ShouldUploadForm(const FormStructure& form) { - if (!IsAutofillEnabled()) - return false; - - if (driver_->IsOffTheRecord()) - return false; - - // Disregard forms that we wouldn't ever autofill in the first place. - if (!form.ShouldBeParsed(true)) - return false; - - return true; -} - -} // namespace autofill |