autocomplete_history_manager.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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#include "content/public/browser/browser_context.h"
20#include "content/public/browser/render_view_host.h"
21#include "content/public/browser/web_contents.h"
22
23using content::BrowserContext;
24using content::WebContents;
25
26namespace autofill {
27namespace {
28
29// Limit on the number of suggestions to appear in the pop-up menu under an
30// text input element in a form.
31const int kMaxAutocompleteMenuItems = 6;
32
33bool IsTextField(const FormFieldData& field) {
34  return
35      field.form_control_type == "text" ||
36      field.form_control_type == "search" ||
37      field.form_control_type == "tel" ||
38      field.form_control_type == "url" ||
39      field.form_control_type == "email" ||
40      field.form_control_type == "text";
41}
42
43}  // namespace
44
45AutocompleteHistoryManager::AutocompleteHistoryManager(
46    AutofillDriver* driver,
47    AutofillManagerDelegate* manager_delegate)
48    : browser_context_(driver->GetWebContents()->GetBrowserContext()),
49      driver_(driver),
50      autofill_data_(
51          AutofillWebDataService::FromBrowserContext(browser_context_)),
52      pending_query_handle_(0),
53      query_id_(0),
54      external_delegate_(NULL),
55      manager_delegate_(manager_delegate),
56      send_ipc_(true) {
57  DCHECK(manager_delegate_);
58}
59
60AutocompleteHistoryManager::~AutocompleteHistoryManager() {
61  CancelPendingQuery();
62}
63
64void AutocompleteHistoryManager::OnWebDataServiceRequestDone(
65    WebDataServiceBase::Handle h,
66    const WDTypedResult* result) {
67  DCHECK(pending_query_handle_);
68  pending_query_handle_ = 0;
69
70  if (!manager_delegate_->IsAutocompleteEnabled()) {
71    SendSuggestions(NULL);
72    return;
73  }
74
75  DCHECK(result);
76  // Returning early here if |result| is NULL.  We've seen this happen on
77  // Linux due to NFS dismounting and causing sql failures.
78  // See http://crbug.com/68783.
79  if (!result) {
80    SendSuggestions(NULL);
81    return;
82  }
83
84  DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
85  const WDResult<std::vector<base::string16> >* autofill_result =
86      static_cast<const WDResult<std::vector<base::string16> >*>(result);
87  std::vector<base::string16> suggestions = autofill_result->GetValue();
88  SendSuggestions(&suggestions);
89}
90
91void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
92    int query_id,
93    const base::string16& name,
94    const base::string16& prefix,
95    const std::vector<base::string16>& autofill_values,
96    const std::vector<base::string16>& autofill_labels,
97    const std::vector<string16>& autofill_icons,
98    const std::vector<int>& autofill_unique_ids) {
99  CancelPendingQuery();
100
101  query_id_ = query_id;
102  autofill_values_ = autofill_values;
103  autofill_labels_ = autofill_labels;
104  autofill_icons_ = autofill_icons;
105  autofill_unique_ids_ = autofill_unique_ids;
106  if (!manager_delegate_->IsAutocompleteEnabled()) {
107    SendSuggestions(NULL);
108    return;
109  }
110
111  if (autofill_data_.get()) {
112    pending_query_handle_ = autofill_data_->GetFormValuesForElementName(
113        name, prefix, kMaxAutocompleteMenuItems, this);
114  }
115}
116
117void AutocompleteHistoryManager::OnFormSubmitted(const FormData& form) {
118  if (!manager_delegate_->IsAutocompleteEnabled())
119    return;
120
121  if (browser_context_->IsOffTheRecord())
122    return;
123
124  // Don't save data that was submitted through JavaScript.
125  if (!form.user_submitted)
126    return;
127
128  // We put the following restriction on stored FormFields:
129  //  - non-empty name
130  //  - non-empty value
131  //  - text field
132  //  - value is not a credit card number
133  //  - value is not a SSN
134  std::vector<FormFieldData> values;
135  for (std::vector<FormFieldData>::const_iterator iter =
136           form.fields.begin();
137       iter != form.fields.end(); ++iter) {
138    if (!iter->value.empty() &&
139        !iter->name.empty() &&
140        IsTextField(*iter) &&
141        !autofill::IsValidCreditCardNumber(iter->value) &&
142        !autofill::IsSSN(iter->value)) {
143      values.push_back(*iter);
144    }
145  }
146
147  if (!values.empty() && autofill_data_.get())
148    autofill_data_->AddFormFields(values);
149}
150
151void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
152    const base::string16& name, const base::string16& value) {
153  if (autofill_data_.get())
154    autofill_data_->RemoveFormValueForElementName(name, value);
155}
156
157void AutocompleteHistoryManager::SetExternalDelegate(
158    AutofillExternalDelegate* delegate) {
159  external_delegate_ = delegate;
160}
161
162void AutocompleteHistoryManager::CancelPendingQuery() {
163  if (pending_query_handle_) {
164    if (autofill_data_.get())
165      autofill_data_->CancelRequest(pending_query_handle_);
166    pending_query_handle_ = 0;
167  }
168}
169
170void AutocompleteHistoryManager::SendSuggestions(
171    const std::vector<base::string16>* suggestions) {
172  if (suggestions) {
173    // Combine Autofill and Autocomplete values into values and labels.
174    for (size_t i = 0; i < suggestions->size(); ++i) {
175      bool unique = true;
176      for (size_t j = 0; j < autofill_values_.size(); ++j) {
177        // Don't add duplicate values.
178        if (autofill_values_[j] == (*suggestions)[i]) {
179          unique = false;
180          break;
181        }
182      }
183
184      if (unique) {
185        autofill_values_.push_back((*suggestions)[i]);
186        autofill_labels_.push_back(base::string16());
187        autofill_icons_.push_back(base::string16());
188        autofill_unique_ids_.push_back(0);  // 0 means no profile.
189      }
190    }
191  }
192
193  external_delegate_->OnSuggestionsReturned(query_id_,
194                                            autofill_values_,
195                                            autofill_labels_,
196                                            autofill_icons_,
197                                            autofill_unique_ids_);
198
199  query_id_ = 0;
200  autofill_values_.clear();
201  autofill_labels_.clear();
202  autofill_icons_.clear();
203  autofill_unique_ids_.clear();
204}
205
206}  // namespace autofill
207