autocomplete_history_manager.cc revision f2477e01787aa58f445919b809d89e252beef54f
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_messages.h"
17#include "components/autofill/core/common/autofill_pref_names.h"
18#include "components/autofill/core/common/form_data.h"
19
20namespace autofill {
21namespace {
22
23// Limit on the number of suggestions to appear in the pop-up menu under an
24// text input element in a form.
25const int kMaxAutocompleteMenuItems = 6;
26
27bool IsTextField(const FormFieldData& field) {
28  return
29      field.form_control_type == "text" ||
30      field.form_control_type == "search" ||
31      field.form_control_type == "tel" ||
32      field.form_control_type == "url" ||
33      field.form_control_type == "email";
34}
35
36}  // namespace
37
38AutocompleteHistoryManager::AutocompleteHistoryManager(
39    AutofillDriver* driver,
40    AutofillManagerDelegate* manager_delegate)
41    : driver_(driver),
42      database_(manager_delegate->GetDatabase()),
43      pending_query_handle_(0),
44      query_id_(0),
45      external_delegate_(NULL),
46      manager_delegate_(manager_delegate),
47      send_ipc_(true) {
48  DCHECK(manager_delegate_);
49}
50
51AutocompleteHistoryManager::~AutocompleteHistoryManager() {
52  CancelPendingQuery();
53}
54
55void AutocompleteHistoryManager::OnWebDataServiceRequestDone(
56    WebDataServiceBase::Handle h,
57    const WDTypedResult* result) {
58  DCHECK(pending_query_handle_);
59  pending_query_handle_ = 0;
60
61  if (!manager_delegate_->IsAutocompleteEnabled()) {
62    SendSuggestions(NULL);
63    return;
64  }
65
66  DCHECK(result);
67  // Returning early here if |result| is NULL.  We've seen this happen on
68  // Linux due to NFS dismounting and causing sql failures.
69  // See http://crbug.com/68783.
70  if (!result) {
71    SendSuggestions(NULL);
72    return;
73  }
74
75  DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
76  const WDResult<std::vector<base::string16> >* autofill_result =
77      static_cast<const WDResult<std::vector<base::string16> >*>(result);
78  std::vector<base::string16> suggestions = autofill_result->GetValue();
79  SendSuggestions(&suggestions);
80}
81
82void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
83    int query_id,
84    const base::string16& name,
85    const base::string16& prefix,
86    const std::vector<base::string16>& autofill_values,
87    const std::vector<base::string16>& autofill_labels,
88    const std::vector<string16>& autofill_icons,
89    const std::vector<int>& autofill_unique_ids) {
90  CancelPendingQuery();
91
92  query_id_ = query_id;
93  autofill_values_ = autofill_values;
94  autofill_labels_ = autofill_labels;
95  autofill_icons_ = autofill_icons;
96  autofill_unique_ids_ = autofill_unique_ids;
97  if (!manager_delegate_->IsAutocompleteEnabled()) {
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
108void AutocompleteHistoryManager::OnFormSubmitted(const FormData& form) {
109  if (!manager_delegate_->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
142void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
143    const base::string16& name, const base::string16& value) {
144  if (database_.get())
145    database_->RemoveFormValueForElementName(name, value);
146}
147
148void AutocompleteHistoryManager::SetExternalDelegate(
149    AutofillExternalDelegate* delegate) {
150  external_delegate_ = delegate;
151}
152
153void 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
161void 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