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