Home | History | Annotate | Download | only in browser
      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