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 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 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 86 AutocompleteHistoryManager::~AutocompleteHistoryManager() { 87 CancelPendingQuery(); 88 } 89 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 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 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 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 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 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 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 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