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
IsTextField(const FormFieldData & field)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
AutocompleteHistoryManager(AutofillDriver * driver,AutofillClient * autofill_client)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
~AutocompleteHistoryManager()49 AutocompleteHistoryManager::~AutocompleteHistoryManager() {
50 CancelPendingQuery();
51 }
52
OnWebDataServiceRequestDone(WebDataServiceBase::Handle h,const WDTypedResult * result)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
OnGetAutocompleteSuggestions(int query_id,const base::string16 & name,const base::string16 & prefix,const std::string form_control_type,const std::vector<base::string16> & autofill_values,const std::vector<base::string16> & autofill_labels,const std::vector<base::string16> & autofill_icons,const std::vector<int> & autofill_unique_ids)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
OnFormSubmitted(const FormData & form)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
OnRemoveAutocompleteEntry(const base::string16 & name,const base::string16 & value)142 void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
143 const base::string16& name, const base::string16& value) {
144 if (database_.get())
145 database_->RemoveFormValueForElementName(name, value);
146 }
147
SetExternalDelegate(AutofillExternalDelegate * delegate)148 void AutocompleteHistoryManager::SetExternalDelegate(
149 AutofillExternalDelegate* delegate) {
150 external_delegate_ = delegate;
151 }
152
CancelPendingQuery()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
SendSuggestions(const std::vector<base::string16> * suggestions)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