Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/autofill/core/browser/autocomplete_history_manager.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/prefs/pref_service.h"
     10 #include "base/strings/string16.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "components/autofill/core/browser/autofill_client.h"
     13 #include "components/autofill/core/browser/autofill_driver.h"
     14 #include "components/autofill/core/browser/autofill_external_delegate.h"
     15 #include "components/autofill/core/browser/validation.h"
     16 #include "components/autofill/core/common/autofill_pref_names.h"
     17 #include "components/autofill/core/common/form_data.h"
     18 
     19 namespace autofill {
     20 namespace {
     21 
     22 // Limit on the number of suggestions to appear in the pop-up menu under an
     23 // text input element in a form.
     24 const int kMaxAutocompleteMenuItems = 6;
     25 
     26 bool IsTextField(const FormFieldData& field) {
     27   return
     28       field.form_control_type == "text" ||
     29       field.form_control_type == "search" ||
     30       field.form_control_type == "tel" ||
     31       field.form_control_type == "url" ||
     32       field.form_control_type == "email";
     33 }
     34 
     35 }  // namespace
     36 
     37 AutocompleteHistoryManager::AutocompleteHistoryManager(
     38     AutofillDriver* driver,
     39     AutofillClient* autofill_client)
     40     : driver_(driver),
     41       database_(autofill_client->GetDatabase()),
     42       pending_query_handle_(0),
     43       query_id_(0),
     44       external_delegate_(NULL),
     45       autofill_client_(autofill_client) {
     46   DCHECK(autofill_client_);
     47 }
     48 
     49 AutocompleteHistoryManager::~AutocompleteHistoryManager() {
     50   CancelPendingQuery();
     51 }
     52 
     53 void AutocompleteHistoryManager::OnWebDataServiceRequestDone(
     54     WebDataServiceBase::Handle h,
     55     const WDTypedResult* result) {
     56   DCHECK(pending_query_handle_);
     57   pending_query_handle_ = 0;
     58 
     59   if (!autofill_client_->IsAutocompleteEnabled()) {
     60     SendSuggestions(NULL);
     61     return;
     62   }
     63 
     64   DCHECK(result);
     65   // Returning early here if |result| is NULL.  We've seen this happen on
     66   // Linux due to NFS dismounting and causing sql failures.
     67   // See http://crbug.com/68783.
     68   if (!result) {
     69     SendSuggestions(NULL);
     70     return;
     71   }
     72 
     73   DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
     74   const WDResult<std::vector<base::string16> >* autofill_result =
     75       static_cast<const WDResult<std::vector<base::string16> >*>(result);
     76   std::vector<base::string16> suggestions = autofill_result->GetValue();
     77   SendSuggestions(&suggestions);
     78 }
     79 
     80 void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
     81     int query_id,
     82     const base::string16& name,
     83     const base::string16& prefix,
     84     const std::string form_control_type,
     85     const std::vector<base::string16>& autofill_values,
     86     const std::vector<base::string16>& autofill_labels,
     87     const std::vector<base::string16>& autofill_icons,
     88     const std::vector<int>& autofill_unique_ids) {
     89   CancelPendingQuery();
     90 
     91   query_id_ = query_id;
     92   autofill_values_ = autofill_values;
     93   autofill_labels_ = autofill_labels;
     94   autofill_icons_ = autofill_icons;
     95   autofill_unique_ids_ = autofill_unique_ids;
     96   if (!autofill_client_->IsAutocompleteEnabled() ||
     97       form_control_type == "textarea") {
     98     SendSuggestions(NULL);
     99     return;
    100   }
    101 
    102   if (database_.get()) {
    103     pending_query_handle_ = database_->GetFormValuesForElementName(
    104         name, prefix, kMaxAutocompleteMenuItems, this);
    105   }
    106 }
    107 
    108 void AutocompleteHistoryManager::OnFormSubmitted(const FormData& form) {
    109   if (!autofill_client_->IsAutocompleteEnabled())
    110     return;
    111 
    112   if (driver_->IsOffTheRecord())
    113     return;
    114 
    115   // Don't save data that was submitted through JavaScript.
    116   if (!form.user_submitted)
    117     return;
    118 
    119   // We put the following restriction on stored FormFields:
    120   //  - non-empty name
    121   //  - non-empty value
    122   //  - text field
    123   //  - value is not a credit card number
    124   //  - value is not a SSN
    125   std::vector<FormFieldData> values;
    126   for (std::vector<FormFieldData>::const_iterator iter =
    127            form.fields.begin();
    128        iter != form.fields.end(); ++iter) {
    129     if (!iter->value.empty() &&
    130         !iter->name.empty() &&
    131         IsTextField(*iter) &&
    132         !autofill::IsValidCreditCardNumber(iter->value) &&
    133         !autofill::IsSSN(iter->value)) {
    134       values.push_back(*iter);
    135     }
    136   }
    137 
    138   if (!values.empty() && database_.get())
    139     database_->AddFormFields(values);
    140 }
    141 
    142 void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
    143     const base::string16& name, const base::string16& value) {
    144   if (database_.get())
    145     database_->RemoveFormValueForElementName(name, value);
    146 }
    147 
    148 void AutocompleteHistoryManager::SetExternalDelegate(
    149     AutofillExternalDelegate* delegate) {
    150   external_delegate_ = delegate;
    151 }
    152 
    153 void AutocompleteHistoryManager::CancelPendingQuery() {
    154   if (pending_query_handle_) {
    155     if (database_.get())
    156       database_->CancelRequest(pending_query_handle_);
    157     pending_query_handle_ = 0;
    158   }
    159 }
    160 
    161 void AutocompleteHistoryManager::SendSuggestions(
    162     const std::vector<base::string16>* suggestions) {
    163   if (suggestions) {
    164     // Combine Autofill and Autocomplete values into values and labels.
    165     for (size_t i = 0; i < suggestions->size(); ++i) {
    166       bool unique = true;
    167       for (size_t j = 0; j < autofill_values_.size(); ++j) {
    168         // Don't add duplicate values.
    169         if (autofill_values_[j] == (*suggestions)[i]) {
    170           unique = false;
    171           break;
    172         }
    173       }
    174 
    175       if (unique) {
    176         autofill_values_.push_back((*suggestions)[i]);
    177         autofill_labels_.push_back(base::string16());
    178         autofill_icons_.push_back(base::string16());
    179         autofill_unique_ids_.push_back(0);  // 0 means no profile.
    180       }
    181     }
    182   }
    183 
    184   external_delegate_->OnSuggestionsReturned(query_id_,
    185                                             autofill_values_,
    186                                             autofill_labels_,
    187                                             autofill_icons_,
    188                                             autofill_unique_ids_);
    189 
    190   query_id_ = 0;
    191   autofill_values_.clear();
    192   autofill_labels_.clear();
    193   autofill_icons_.clear();
    194   autofill_unique_ids_.clear();
    195 }
    196 
    197 }  // namespace autofill
    198