• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/autocomplete_history_manager.h"
6 
7 #include <vector>
8 
9 #include "base/string16.h"
10 #include "base/string_number_conversions.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/autofill/credit_card.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/autofill_messages.h"
16 #include "chrome/common/pref_names.h"
17 #include "content/browser/renderer_host/render_view_host.h"
18 #include "content/browser/tab_contents/tab_contents.h"
19 #include "webkit/glue/form_data.h"
20 
21 using webkit_glue::FormData;
22 
23 namespace {
24 
25 // Limit on the number of suggestions to appear in the pop-up menu under an
26 // text input element in a form.
27 const int kMaxAutocompleteMenuItems = 6;
28 
29 // The separator characters for SSNs.
30 const string16 kSSNSeparators = ASCIIToUTF16(" -");
31 
IsSSN(const string16 & text)32 bool IsSSN(const string16& text) {
33   string16 number_string;
34   RemoveChars(text, kSSNSeparators.c_str(), &number_string);
35 
36   // A SSN is of the form AAA-GG-SSSS (A = area number, G = group number, S =
37   // serial number). The validation we do here is simply checking if the area,
38   // group, and serial numbers are valid. It is possible to check if the group
39   // number is valid for the given area, but that data changes all the time.
40   //
41   // See: http://www.socialsecurity.gov/history/ssn/geocard.html
42   //      http://www.socialsecurity.gov/employer/stateweb.htm
43   //      http://www.socialsecurity.gov/employer/ssnvhighgroup.htm
44   if (number_string.length() != 9 || !IsStringASCII(number_string))
45     return false;
46 
47   int area;
48   if (!base::StringToInt(number_string.begin(),
49                          number_string.begin() + 3,
50                          &area))
51     return false;
52   if (area < 1 ||
53       area == 666 ||
54       (area > 733 && area < 750) ||
55       area > 772)
56     return false;
57 
58   int group;
59   if (!base::StringToInt(number_string.begin() + 3,
60                          number_string.begin() + 5,
61                          &group) || group == 0)
62     return false;
63 
64   int serial;
65   if (!base::StringToInt(number_string.begin() + 5,
66                          number_string.begin() + 9,
67                          &serial) || serial == 0)
68     return false;
69 
70   return true;
71 }
72 
73 }  // namespace
74 
AutocompleteHistoryManager(TabContents * tab_contents)75 AutocompleteHistoryManager::AutocompleteHistoryManager(
76     TabContents* tab_contents)
77     : TabContentsObserver(tab_contents),
78       pending_query_handle_(0),
79       query_id_(0) {
80   profile_ = tab_contents->profile();
81   // May be NULL in unit tests.
82   web_data_service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
83   autofill_enabled_.Init(prefs::kAutofillEnabled, profile_->GetPrefs(), NULL);
84 }
85 
~AutocompleteHistoryManager()86 AutocompleteHistoryManager::~AutocompleteHistoryManager() {
87   CancelPendingQuery();
88 }
89 
OnMessageReceived(const IPC::Message & message)90 bool AutocompleteHistoryManager::OnMessageReceived(
91     const IPC::Message& message) {
92   bool handled = true;
93   IPC_BEGIN_MESSAGE_MAP(AutocompleteHistoryManager, message)
94     IPC_MESSAGE_HANDLER(AutofillHostMsg_RemoveAutocompleteEntry,
95                         OnRemoveAutocompleteEntry)
96     IPC_MESSAGE_UNHANDLED(handled = false)
97   IPC_END_MESSAGE_MAP()
98   return handled;
99 }
100 
OnFormSubmitted(const FormData & form)101 void AutocompleteHistoryManager::OnFormSubmitted(const FormData& form) {
102   if (!*autofill_enabled_)
103     return;
104 
105   if (profile_->IsOffTheRecord())
106     return;
107 
108   // Don't save data that was submitted through JavaScript.
109   if (!form.user_submitted)
110     return;
111 
112   // We put the following restriction on stored FormFields:
113   //  - non-empty name
114   //  - non-empty value
115   //  - text field
116   //  - value is not a credit card number
117   //  - value is not a SSN
118   std::vector<webkit_glue::FormField> values;
119   for (std::vector<webkit_glue::FormField>::const_iterator iter =
120            form.fields.begin();
121        iter != form.fields.end(); ++iter) {
122     if (!iter->value.empty() &&
123         !iter->name.empty() &&
124         iter->form_control_type == ASCIIToUTF16("text") &&
125         !CreditCard::IsValidCreditCardNumber(iter->value) &&
126         !IsSSN(iter->value)) {
127       values.push_back(*iter);
128     }
129   }
130 
131   if (!values.empty() && web_data_service_.get())
132     web_data_service_->AddFormFields(values);
133 }
134 
OnRemoveAutocompleteEntry(const string16 & name,const string16 & value)135 void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
136     const string16& name, const string16& value) {
137   if (web_data_service_.get())
138     web_data_service_->RemoveFormValueForElementName(name, value);
139 }
140 
OnGetAutocompleteSuggestions(int query_id,const string16 & name,const string16 & prefix,const std::vector<string16> & autofill_values,const std::vector<string16> & autofill_labels,const std::vector<string16> & autofill_icons,const std::vector<int> & autofill_unique_ids)141 void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
142     int query_id,
143     const string16& name,
144     const string16& prefix,
145     const std::vector<string16>& autofill_values,
146     const std::vector<string16>& autofill_labels,
147     const std::vector<string16>& autofill_icons,
148     const std::vector<int>& autofill_unique_ids) {
149   CancelPendingQuery();
150 
151   query_id_ = query_id;
152   autofill_values_ = autofill_values;
153   autofill_labels_ = autofill_labels;
154   autofill_icons_ = autofill_icons;
155   autofill_unique_ids_ = autofill_unique_ids;
156   if (!*autofill_enabled_) {
157     SendSuggestions(NULL);
158     return;
159   }
160 
161   if (web_data_service_.get()) {
162     pending_query_handle_ = web_data_service_->GetFormValuesForElementName(
163         name, prefix, kMaxAutocompleteMenuItems, this);
164   }
165 }
166 
OnWebDataServiceRequestDone(WebDataService::Handle h,const WDTypedResult * result)167 void AutocompleteHistoryManager::OnWebDataServiceRequestDone(
168     WebDataService::Handle h,
169     const WDTypedResult* result) {
170   DCHECK(pending_query_handle_);
171   pending_query_handle_ = 0;
172 
173   if (!*autofill_enabled_) {
174     SendSuggestions(NULL);
175     return;
176   }
177 
178   DCHECK(result);
179   // Returning early here if |result| is NULL.  We've seen this happen on
180   // Linux due to NFS dismounting and causing sql failures.
181   // See http://crbug.com/68783.
182   if (!result) {
183     SendSuggestions(NULL);
184     return;
185   }
186 
187   DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
188   const WDResult<std::vector<string16> >* autofill_result =
189       static_cast<const WDResult<std::vector<string16> >*>(result);
190   std::vector<string16> suggestions = autofill_result->GetValue();
191   SendSuggestions(&suggestions);
192 }
193 
AutocompleteHistoryManager(TabContents * tab_contents,Profile * profile,WebDataService * wds)194 AutocompleteHistoryManager::AutocompleteHistoryManager(
195     TabContents* tab_contents,
196     Profile* profile,
197     WebDataService* wds)
198     : TabContentsObserver(tab_contents),
199       profile_(profile),
200       web_data_service_(wds),
201       pending_query_handle_(0),
202       query_id_(0) {
203   autofill_enabled_.Init(
204       prefs::kAutofillEnabled, profile_->GetPrefs(), NULL);
205 }
206 
CancelPendingQuery()207 void AutocompleteHistoryManager::CancelPendingQuery() {
208   if (pending_query_handle_) {
209     SendSuggestions(NULL);
210     if (web_data_service_.get())
211       web_data_service_->CancelRequest(pending_query_handle_);
212     pending_query_handle_ = 0;
213   }
214 }
215 
SendSuggestions(const std::vector<string16> * suggestions)216 void AutocompleteHistoryManager::SendSuggestions(
217     const std::vector<string16>* suggestions) {
218   if (suggestions) {
219     // Combine Autofill and Autocomplete values into values and labels.
220     for (size_t i = 0; i < suggestions->size(); ++i) {
221       bool unique = true;
222       for (size_t j = 0; j < autofill_values_.size(); ++j) {
223         // Don't add duplicate values.
224         if (autofill_values_[j] == (*suggestions)[i]) {
225           unique = false;
226           break;
227         }
228       }
229 
230       if (unique) {
231         autofill_values_.push_back((*suggestions)[i]);
232         autofill_labels_.push_back(string16());
233         autofill_icons_.push_back(string16());
234         autofill_unique_ids_.push_back(0);  // 0 means no profile.
235       }
236     }
237   }
238 
239   Send(new AutofillMsg_SuggestionsReturned(routing_id(),
240                                            query_id_,
241                                            autofill_values_,
242                                            autofill_labels_,
243                                            autofill_icons_,
244                                            autofill_unique_ids_));
245 
246   query_id_ = 0;
247   autofill_values_.clear();
248   autofill_labels_.clear();
249   autofill_icons_.clear();
250   autofill_unique_ids_.clear();
251 }
252