autocomplete_history_manager.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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_driver.h"
13#include "components/autofill/core/browser/autofill_external_delegate.h"
14#include "components/autofill/core/browser/autofill_manager_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
19namespace autofill {
20namespace {
21
22// Limit on the number of suggestions to appear in the pop-up menu under an
23// text input element in a form.
24const int kMaxAutocompleteMenuItems = 6;
25
26bool 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
37AutocompleteHistoryManager::AutocompleteHistoryManager(
38    AutofillDriver* driver,
39    AutofillManagerDelegate* manager_delegate)
40    : driver_(driver),
41      database_(manager_delegate->GetDatabase()),
42      pending_query_handle_(0),
43      query_id_(0),
44      external_delegate_(NULL),
45      manager_delegate_(manager_delegate) {
46  DCHECK(manager_delegate_);
47}
48
49AutocompleteHistoryManager::~AutocompleteHistoryManager() {
50  CancelPendingQuery();
51}
52
53void AutocompleteHistoryManager::OnWebDataServiceRequestDone(
54    WebDataServiceBase::Handle h,
55    const WDTypedResult* result) {
56  DCHECK(pending_query_handle_);
57  pending_query_handle_ = 0;
58
59  if (!manager_delegate_->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
80void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
81    int query_id,
82    const base::string16& name,
83    const base::string16& prefix,
84    const std::vector<base::string16>& autofill_values,
85    const std::vector<base::string16>& autofill_labels,
86    const std::vector<base::string16>& autofill_icons,
87    const std::vector<int>& autofill_unique_ids) {
88  CancelPendingQuery();
89
90  query_id_ = query_id;
91  autofill_values_ = autofill_values;
92  autofill_labels_ = autofill_labels;
93  autofill_icons_ = autofill_icons;
94  autofill_unique_ids_ = autofill_unique_ids;
95  if (!manager_delegate_->IsAutocompleteEnabled()) {
96    SendSuggestions(NULL);
97    return;
98  }
99
100  if (database_.get()) {
101    pending_query_handle_ = database_->GetFormValuesForElementName(
102        name, prefix, kMaxAutocompleteMenuItems, this);
103  }
104}
105
106void AutocompleteHistoryManager::OnFormSubmitted(const FormData& form) {
107  if (!manager_delegate_->IsAutocompleteEnabled())
108    return;
109
110  if (driver_->IsOffTheRecord())
111    return;
112
113  // Don't save data that was submitted through JavaScript.
114  if (!form.user_submitted)
115    return;
116
117  // We put the following restriction on stored FormFields:
118  //  - non-empty name
119  //  - non-empty value
120  //  - text field
121  //  - value is not a credit card number
122  //  - value is not a SSN
123  std::vector<FormFieldData> values;
124  for (std::vector<FormFieldData>::const_iterator iter =
125           form.fields.begin();
126       iter != form.fields.end(); ++iter) {
127    if (!iter->value.empty() &&
128        !iter->name.empty() &&
129        IsTextField(*iter) &&
130        !autofill::IsValidCreditCardNumber(iter->value) &&
131        !autofill::IsSSN(iter->value)) {
132      values.push_back(*iter);
133    }
134  }
135
136  if (!values.empty() && database_.get())
137    database_->AddFormFields(values);
138}
139
140void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
141    const base::string16& name, const base::string16& value) {
142  if (database_.get())
143    database_->RemoveFormValueForElementName(name, value);
144}
145
146void AutocompleteHistoryManager::SetExternalDelegate(
147    AutofillExternalDelegate* delegate) {
148  external_delegate_ = delegate;
149}
150
151void AutocompleteHistoryManager::CancelPendingQuery() {
152  if (pending_query_handle_) {
153    if (database_.get())
154      database_->CancelRequest(pending_query_handle_);
155    pending_query_handle_ = 0;
156  }
157}
158
159void AutocompleteHistoryManager::SendSuggestions(
160    const std::vector<base::string16>* suggestions) {
161  if (suggestions) {
162    // Combine Autofill and Autocomplete values into values and labels.
163    for (size_t i = 0; i < suggestions->size(); ++i) {
164      bool unique = true;
165      for (size_t j = 0; j < autofill_values_.size(); ++j) {
166        // Don't add duplicate values.
167        if (autofill_values_[j] == (*suggestions)[i]) {
168          unique = false;
169          break;
170        }
171      }
172
173      if (unique) {
174        autofill_values_.push_back((*suggestions)[i]);
175        autofill_labels_.push_back(base::string16());
176        autofill_icons_.push_back(base::string16());
177        autofill_unique_ids_.push_back(0);  // 0 means no profile.
178      }
179    }
180  }
181
182  external_delegate_->OnSuggestionsReturned(query_id_,
183                                            autofill_values_,
184                                            autofill_labels_,
185                                            autofill_icons_,
186                                            autofill_unique_ids_);
187
188  query_id_ = 0;
189  autofill_values_.clear();
190  autofill_labels_.clear();
191  autofill_icons_.clear();
192  autofill_unique_ids_.clear();
193}
194
195}  // namespace autofill
196