Home | History | Annotate | Download | only in webdata
      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/webdata/autofill_webdata_backend_impl.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_vector.h"
      9 #include "base/stl_util.h"
     10 #include "components/autofill/core/browser/autofill_country.h"
     11 #include "components/autofill/core/browser/autofill_profile.h"
     12 #include "components/autofill/core/browser/credit_card.h"
     13 #include "components/autofill/core/browser/webdata/autofill_change.h"
     14 #include "components/autofill/core/browser/webdata/autofill_entry.h"
     15 #include "components/autofill/core/browser/webdata/autofill_table.h"
     16 #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
     17 #include "components/autofill/core/common/form_field_data.h"
     18 #include "components/webdata/common/web_data_service_backend.h"
     19 
     20 using base::Bind;
     21 using base::Time;
     22 using content::BrowserThread;
     23 
     24 namespace autofill {
     25 
     26 AutofillWebDataBackendImpl::AutofillWebDataBackendImpl(
     27     scoped_refptr<WebDataServiceBackend> web_database_backend,
     28     const base::Closure& on_changed_callback)
     29     : web_database_backend_(web_database_backend),
     30       on_changed_callback_(on_changed_callback) {
     31 }
     32 
     33 void AutofillWebDataBackendImpl::AddObserver(
     34     AutofillWebDataServiceObserverOnDBThread* observer) {
     35   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     36   db_observer_list_.AddObserver(observer);
     37 }
     38 
     39 void AutofillWebDataBackendImpl::RemoveObserver(
     40     AutofillWebDataServiceObserverOnDBThread* observer) {
     41   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     42   db_observer_list_.RemoveObserver(observer);
     43 }
     44 
     45 AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() {
     46   DCHECK(!user_data_.get()); // Forgot to call ResetUserData?
     47 }
     48 
     49 WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
     50   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     51   return web_database_backend_->database();
     52 }
     53 
     54 void AutofillWebDataBackendImpl::RemoveExpiredFormElements() {
     55   web_database_backend_->ExecuteWriteTask(
     56       Bind(&AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl,
     57            this));
     58 }
     59 
     60 void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
     61   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     62   BrowserThread::PostTask(BrowserThread::UI,
     63                           FROM_HERE,
     64                           on_changed_callback_);
     65 }
     66 
     67 base::SupportsUserData* AutofillWebDataBackendImpl::GetDBUserData() {
     68   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     69   if (!user_data_)
     70     user_data_.reset(new SupportsUserDataAggregatable());
     71   return user_data_.get();
     72 }
     73 
     74 void AutofillWebDataBackendImpl::ResetUserData() {
     75   user_data_.reset();
     76 }
     77 
     78 WebDatabase::State AutofillWebDataBackendImpl::AddFormElements(
     79     const std::vector<FormFieldData>& fields, WebDatabase* db) {
     80   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     81   AutofillChangeList changes;
     82   if (!AutofillTable::FromWebDatabase(db)->AddFormFieldValues(
     83         fields, &changes)) {
     84     NOTREACHED();
     85     return WebDatabase::COMMIT_NOT_NEEDED;
     86   }
     87 
     88   // Post the notifications including the list of affected keys.
     89   // This is sent here so that work resulting from this notification will be
     90   // done on the DB thread, and not the UI thread.
     91   FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
     92                     db_observer_list_,
     93                     AutofillEntriesChanged(changes));
     94 
     95   return WebDatabase::COMMIT_NEEDED;
     96 }
     97 
     98 scoped_ptr<WDTypedResult>
     99 AutofillWebDataBackendImpl::GetFormValuesForElementName(
    100     const base::string16& name, const base::string16& prefix, int limit,
    101     WebDatabase* db) {
    102   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    103   std::vector<base::string16> values;
    104   AutofillTable::FromWebDatabase(db)->GetFormValuesForElementName(
    105       name, prefix, &values, limit);
    106   return scoped_ptr<WDTypedResult>(
    107       new WDResult<std::vector<base::string16> >(AUTOFILL_VALUE_RESULT,
    108                                                  values));
    109 }
    110 
    111 scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::HasFormElements(
    112     WebDatabase* db) {
    113   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    114   bool value = AutofillTable::FromWebDatabase(db)->HasFormElements();
    115   return scoped_ptr<WDTypedResult>(
    116       new WDResult<bool>(AUTOFILL_VALUE_RESULT, value));
    117 }
    118 
    119 WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween(
    120     const base::Time& delete_begin,
    121     const base::Time& delete_end,
    122     WebDatabase* db) {
    123   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    124   AutofillChangeList changes;
    125 
    126   if (AutofillTable::FromWebDatabase(db)->RemoveFormElementsAddedBetween(
    127           delete_begin, delete_end, &changes)) {
    128     if (!changes.empty()) {
    129       // Post the notifications including the list of affected keys.
    130       // This is sent here so that work resulting from this notification
    131       // will be done on the DB thread, and not the UI thread.
    132       FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    133                         db_observer_list_,
    134                         AutofillEntriesChanged(changes));
    135     }
    136     return WebDatabase::COMMIT_NEEDED;
    137   }
    138   return WebDatabase::COMMIT_NOT_NEEDED;
    139 }
    140 
    141 WebDatabase::State AutofillWebDataBackendImpl::RemoveFormValueForElementName(
    142     const base::string16& name, const base::string16& value, WebDatabase* db) {
    143   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    144 
    145   if (AutofillTable::FromWebDatabase(db)->RemoveFormElement(name, value)) {
    146     AutofillChangeList changes;
    147     changes.push_back(
    148         AutofillChange(AutofillChange::REMOVE, AutofillKey(name, value)));
    149 
    150     // Post the notifications including the list of affected keys.
    151     FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    152                       db_observer_list_,
    153                       AutofillEntriesChanged(changes));
    154 
    155     return WebDatabase::COMMIT_NEEDED;
    156   }
    157   return WebDatabase::COMMIT_NOT_NEEDED;
    158 }
    159 
    160 WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile(
    161     const AutofillProfile& profile, WebDatabase* db) {
    162   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    163   if (!AutofillTable::FromWebDatabase(db)->AddAutofillProfile(profile)) {
    164     NOTREACHED();
    165     return WebDatabase::COMMIT_NOT_NEEDED;
    166   }
    167 
    168   // Send GUID-based notification.
    169   AutofillProfileChange change(
    170       AutofillProfileChange::ADD, profile.guid(), &profile);
    171   FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    172                     db_observer_list_,
    173                     AutofillProfileChanged(change));
    174 
    175   return WebDatabase::COMMIT_NEEDED;
    176 }
    177 
    178 WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile(
    179     const AutofillProfile& profile, WebDatabase* db) {
    180   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    181   // Only perform the update if the profile exists.  It is currently
    182   // valid to try to update a missing profile.  We simply drop the write and
    183   // the caller will detect this on the next refresh.
    184   AutofillProfile* original_profile = NULL;
    185   if (!AutofillTable::FromWebDatabase(db)->GetAutofillProfile(profile.guid(),
    186       &original_profile)) {
    187     return WebDatabase::COMMIT_NOT_NEEDED;
    188   }
    189   scoped_ptr<AutofillProfile> scoped_profile(original_profile);
    190 
    191   if (!AutofillTable::FromWebDatabase(db)->UpdateAutofillProfile(profile)) {
    192     NOTREACHED();
    193     return WebDatabase::COMMIT_NEEDED;
    194   }
    195 
    196   // Send GUID-based notification.
    197   AutofillProfileChange change(
    198       AutofillProfileChange::UPDATE, profile.guid(), &profile);
    199   FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    200                     db_observer_list_,
    201                     AutofillProfileChanged(change));
    202 
    203   return WebDatabase::COMMIT_NEEDED;
    204 }
    205 
    206 WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile(
    207     const std::string& guid, WebDatabase* db) {
    208   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    209   AutofillProfile* profile = NULL;
    210   if (!AutofillTable::FromWebDatabase(db)->GetAutofillProfile(guid, &profile)) {
    211     NOTREACHED();
    212     return WebDatabase::COMMIT_NOT_NEEDED;
    213   }
    214   scoped_ptr<AutofillProfile> scoped_profile(profile);
    215 
    216   if (!AutofillTable::FromWebDatabase(db)->RemoveAutofillProfile(guid)) {
    217     NOTREACHED();
    218     return WebDatabase::COMMIT_NOT_NEEDED;
    219   }
    220 
    221   // Send GUID-based notification.
    222   AutofillProfileChange change(AutofillProfileChange::REMOVE, guid, NULL);
    223   FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    224                     db_observer_list_,
    225                     AutofillProfileChanged(change));
    226 
    227   return WebDatabase::COMMIT_NEEDED;
    228 }
    229 
    230 scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetAutofillProfiles(
    231     WebDatabase* db) {
    232   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    233   std::vector<AutofillProfile*> profiles;
    234   AutofillTable::FromWebDatabase(db)->GetAutofillProfiles(&profiles);
    235   return scoped_ptr<WDTypedResult>(
    236       new WDDestroyableResult<std::vector<AutofillProfile*> >(
    237           AUTOFILL_PROFILES_RESULT,
    238           profiles,
    239           base::Bind(&AutofillWebDataBackendImpl::DestroyAutofillProfileResult,
    240               base::Unretained(this))));
    241 }
    242 
    243 WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard(
    244     const CreditCard& credit_card, WebDatabase* db) {
    245   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    246   if (!AutofillTable::FromWebDatabase(db)->AddCreditCard(credit_card)) {
    247     NOTREACHED();
    248     return WebDatabase::COMMIT_NOT_NEEDED;
    249   }
    250 
    251   return WebDatabase::COMMIT_NEEDED;
    252 }
    253 
    254 WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard(
    255     const CreditCard& credit_card, WebDatabase* db) {
    256   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    257   // It is currently valid to try to update a missing profile.  We simply drop
    258   // the write and the caller will detect this on the next refresh.
    259   CreditCard* original_credit_card = NULL;
    260   if (!AutofillTable::FromWebDatabase(db)->GetCreditCard(credit_card.guid(),
    261       &original_credit_card)) {
    262     return WebDatabase::COMMIT_NOT_NEEDED;
    263   }
    264   scoped_ptr<CreditCard> scoped_credit_card(original_credit_card);
    265 
    266   if (!AutofillTable::FromWebDatabase(db)->UpdateCreditCard(credit_card)) {
    267     NOTREACHED();
    268     return WebDatabase::COMMIT_NOT_NEEDED;
    269   }
    270   return WebDatabase::COMMIT_NEEDED;
    271 }
    272 
    273 WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard(
    274     const std::string& guid, WebDatabase* db) {
    275   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    276   if (!AutofillTable::FromWebDatabase(db)->RemoveCreditCard(guid)) {
    277     NOTREACHED();
    278     return WebDatabase::COMMIT_NOT_NEEDED;
    279   }
    280   return WebDatabase::COMMIT_NEEDED;
    281 }
    282 
    283 scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetCreditCards(
    284     WebDatabase* db) {
    285   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    286   std::vector<CreditCard*> credit_cards;
    287   AutofillTable::FromWebDatabase(db)->GetCreditCards(&credit_cards);
    288   return scoped_ptr<WDTypedResult>(
    289       new WDDestroyableResult<std::vector<CreditCard*> >(
    290           AUTOFILL_CREDITCARDS_RESULT,
    291           credit_cards,
    292         base::Bind(&AutofillWebDataBackendImpl::DestroyAutofillCreditCardResult,
    293               base::Unretained(this))));
    294 }
    295 
    296 WebDatabase::State
    297     AutofillWebDataBackendImpl::RemoveAutofillDataModifiedBetween(
    298         const base::Time& delete_begin,
    299         const base::Time& delete_end,
    300         WebDatabase* db) {
    301   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    302   std::vector<std::string> profile_guids;
    303   std::vector<std::string> credit_card_guids;
    304   if (AutofillTable::FromWebDatabase(db)->RemoveAutofillDataModifiedBetween(
    305           delete_begin,
    306           delete_end,
    307           &profile_guids,
    308           &credit_card_guids)) {
    309     for (std::vector<std::string>::iterator iter = profile_guids.begin();
    310          iter != profile_guids.end(); ++iter) {
    311       AutofillProfileChange change(AutofillProfileChange::REMOVE, *iter, NULL);
    312       FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    313                         db_observer_list_,
    314                         AutofillProfileChanged(change));
    315     }
    316     // Note: It is the caller's responsibility to post notifications for any
    317     // changes, e.g. by calling the Refresh() method of PersonalDataManager.
    318     return WebDatabase::COMMIT_NEEDED;
    319   }
    320   return WebDatabase::COMMIT_NOT_NEEDED;
    321 }
    322 
    323 WebDatabase::State AutofillWebDataBackendImpl::RemoveOriginURLsModifiedBetween(
    324     const base::Time& delete_begin,
    325     const base::Time& delete_end,
    326     WebDatabase* db) {
    327   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    328   ScopedVector<AutofillProfile> profiles;
    329   if (AutofillTable::FromWebDatabase(db)->RemoveOriginURLsModifiedBetween(
    330           delete_begin, delete_end, &profiles)) {
    331     for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin();
    332          it != profiles.end(); ++it) {
    333       AutofillProfileChange change(AutofillProfileChange::UPDATE,
    334                                    (*it)->guid(), *it);
    335       FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    336                         db_observer_list_,
    337                         AutofillProfileChanged(change));
    338     }
    339     // Note: It is the caller's responsibility to post notifications for any
    340     // changes, e.g. by calling the Refresh() method of PersonalDataManager.
    341     return WebDatabase::COMMIT_NEEDED;
    342   }
    343   return WebDatabase::COMMIT_NOT_NEEDED;
    344 }
    345 
    346 WebDatabase::State AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl(
    347     WebDatabase* db) {
    348   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    349   AutofillChangeList changes;
    350 
    351   if (AutofillTable::FromWebDatabase(db)->RemoveExpiredFormElements(&changes)) {
    352     if (!changes.empty()) {
    353       // Post the notifications including the list of affected keys.
    354       // This is sent here so that work resulting from this notification
    355       // will be done on the DB thread, and not the UI thread.
    356       FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
    357                         db_observer_list_,
    358                         AutofillEntriesChanged(changes));
    359     }
    360     return WebDatabase::COMMIT_NEEDED;
    361   }
    362   return WebDatabase::COMMIT_NOT_NEEDED;
    363 }
    364 
    365 void AutofillWebDataBackendImpl::DestroyAutofillProfileResult(
    366     const WDTypedResult* result) {
    367   DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT);
    368   const WDResult<std::vector<AutofillProfile*> >* r =
    369       static_cast<const WDResult<std::vector<AutofillProfile*> >*>(result);
    370   std::vector<AutofillProfile*> profiles = r->GetValue();
    371   STLDeleteElements(&profiles);
    372 }
    373 
    374 void AutofillWebDataBackendImpl::DestroyAutofillCreditCardResult(
    375       const WDTypedResult* result) {
    376   DCHECK(result->GetType() == AUTOFILL_CREDITCARDS_RESULT);
    377   const WDResult<std::vector<CreditCard*> >* r =
    378       static_cast<const WDResult<std::vector<CreditCard*> >*>(result);
    379 
    380   std::vector<CreditCard*> credit_cards = r->GetValue();
    381   STLDeleteElements(&credit_cards);
    382 }
    383 
    384 }  // namespace autofill
    385