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
22using base::Bind;
23using base::Time;
24
25namespace autofill {
26
27AutofillWebDataBackendImpl::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
40void AutofillWebDataBackendImpl::AddObserver(
41    AutofillWebDataServiceObserverOnDBThread* observer) {
42  DCHECK(db_thread_->BelongsToCurrentThread());
43  db_observer_list_.AddObserver(observer);
44}
45
46void AutofillWebDataBackendImpl::RemoveObserver(
47    AutofillWebDataServiceObserverOnDBThread* observer) {
48  DCHECK(db_thread_->BelongsToCurrentThread());
49  db_observer_list_.RemoveObserver(observer);
50}
51
52AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() {
53  DCHECK(!user_data_.get()); // Forgot to call ResetUserData?
54}
55
56WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
57  DCHECK(db_thread_->BelongsToCurrentThread());
58  return web_database_backend_->database();
59}
60
61void AutofillWebDataBackendImpl::RemoveExpiredFormElements() {
62  web_database_backend_->ExecuteWriteTask(
63      Bind(&AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl,
64           this));
65}
66
67void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
68  DCHECK(db_thread_->BelongsToCurrentThread());
69  ui_thread_->PostTask(FROM_HERE, on_changed_callback_);
70}
71
72base::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
79void AutofillWebDataBackendImpl::ResetUserData() {
80  user_data_.reset();
81}
82
83WebDatabase::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
103scoped_ptr<WDTypedResult>
104AutofillWebDataBackendImpl::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
116scoped_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
124WebDatabase::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
146WebDatabase::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
165WebDatabase::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
183WebDatabase::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
211WebDatabase::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
235scoped_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
248WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillEntries(
249    const std::vector<autofill::AutofillEntry>& autofill_entries,
250    WebDatabase* db) {
251  DCHECK(db_thread_->BelongsToCurrentThread());
252  if (!AutofillTable::FromWebDatabase(db)
253           ->UpdateAutofillEntries(autofill_entries))
254    return WebDatabase::COMMIT_NOT_NEEDED;
255
256  return WebDatabase::COMMIT_NEEDED;
257}
258
259WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard(
260    const CreditCard& credit_card, WebDatabase* db) {
261  DCHECK(db_thread_->BelongsToCurrentThread());
262  if (!AutofillTable::FromWebDatabase(db)->AddCreditCard(credit_card)) {
263    NOTREACHED();
264    return WebDatabase::COMMIT_NOT_NEEDED;
265  }
266
267  return WebDatabase::COMMIT_NEEDED;
268}
269
270WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard(
271    const CreditCard& credit_card, WebDatabase* db) {
272  DCHECK(db_thread_->BelongsToCurrentThread());
273  // It is currently valid to try to update a missing profile.  We simply drop
274  // the write and the caller will detect this on the next refresh.
275  CreditCard* original_credit_card = NULL;
276  if (!AutofillTable::FromWebDatabase(db)->GetCreditCard(credit_card.guid(),
277      &original_credit_card)) {
278    return WebDatabase::COMMIT_NOT_NEEDED;
279  }
280  scoped_ptr<CreditCard> scoped_credit_card(original_credit_card);
281
282  if (!AutofillTable::FromWebDatabase(db)->UpdateCreditCard(credit_card)) {
283    NOTREACHED();
284    return WebDatabase::COMMIT_NOT_NEEDED;
285  }
286  return WebDatabase::COMMIT_NEEDED;
287}
288
289WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard(
290    const std::string& guid, WebDatabase* db) {
291  DCHECK(db_thread_->BelongsToCurrentThread());
292  if (!AutofillTable::FromWebDatabase(db)->RemoveCreditCard(guid)) {
293    NOTREACHED();
294    return WebDatabase::COMMIT_NOT_NEEDED;
295  }
296  return WebDatabase::COMMIT_NEEDED;
297}
298
299scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetCreditCards(
300    WebDatabase* db) {
301  DCHECK(db_thread_->BelongsToCurrentThread());
302  std::vector<CreditCard*> credit_cards;
303  AutofillTable::FromWebDatabase(db)->GetCreditCards(&credit_cards);
304  return scoped_ptr<WDTypedResult>(
305      new WDDestroyableResult<std::vector<CreditCard*> >(
306          AUTOFILL_CREDITCARDS_RESULT,
307          credit_cards,
308        base::Bind(&AutofillWebDataBackendImpl::DestroyAutofillCreditCardResult,
309              base::Unretained(this))));
310}
311
312WebDatabase::State
313    AutofillWebDataBackendImpl::RemoveAutofillDataModifiedBetween(
314        const base::Time& delete_begin,
315        const base::Time& delete_end,
316        WebDatabase* db) {
317  DCHECK(db_thread_->BelongsToCurrentThread());
318  std::vector<std::string> profile_guids;
319  std::vector<std::string> credit_card_guids;
320  if (AutofillTable::FromWebDatabase(db)->RemoveAutofillDataModifiedBetween(
321          delete_begin,
322          delete_end,
323          &profile_guids,
324          &credit_card_guids)) {
325    for (std::vector<std::string>::iterator iter = profile_guids.begin();
326         iter != profile_guids.end(); ++iter) {
327      AutofillProfileChange change(AutofillProfileChange::REMOVE, *iter, NULL);
328      FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
329                        db_observer_list_,
330                        AutofillProfileChanged(change));
331    }
332    // Note: It is the caller's responsibility to post notifications for any
333    // changes, e.g. by calling the Refresh() method of PersonalDataManager.
334    return WebDatabase::COMMIT_NEEDED;
335  }
336  return WebDatabase::COMMIT_NOT_NEEDED;
337}
338
339WebDatabase::State AutofillWebDataBackendImpl::RemoveOriginURLsModifiedBetween(
340    const base::Time& delete_begin,
341    const base::Time& delete_end,
342    WebDatabase* db) {
343  DCHECK(db_thread_->BelongsToCurrentThread());
344  ScopedVector<AutofillProfile> profiles;
345  if (AutofillTable::FromWebDatabase(db)->RemoveOriginURLsModifiedBetween(
346          delete_begin, delete_end, &profiles)) {
347    for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin();
348         it != profiles.end(); ++it) {
349      AutofillProfileChange change(AutofillProfileChange::UPDATE,
350                                   (*it)->guid(), *it);
351      FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
352                        db_observer_list_,
353                        AutofillProfileChanged(change));
354    }
355    // Note: It is the caller's responsibility to post notifications for any
356    // changes, e.g. by calling the Refresh() method of PersonalDataManager.
357    return WebDatabase::COMMIT_NEEDED;
358  }
359  return WebDatabase::COMMIT_NOT_NEEDED;
360}
361
362WebDatabase::State AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl(
363    WebDatabase* db) {
364  DCHECK(db_thread_->BelongsToCurrentThread());
365  AutofillChangeList changes;
366
367  if (AutofillTable::FromWebDatabase(db)->RemoveExpiredFormElements(&changes)) {
368    if (!changes.empty()) {
369      // Post the notifications including the list of affected keys.
370      // This is sent here so that work resulting from this notification
371      // will be done on the DB thread, and not the UI thread.
372      FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
373                        db_observer_list_,
374                        AutofillEntriesChanged(changes));
375    }
376    return WebDatabase::COMMIT_NEEDED;
377  }
378  return WebDatabase::COMMIT_NOT_NEEDED;
379}
380
381void AutofillWebDataBackendImpl::DestroyAutofillProfileResult(
382    const WDTypedResult* result) {
383  DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT);
384  const WDResult<std::vector<AutofillProfile*> >* r =
385      static_cast<const WDResult<std::vector<AutofillProfile*> >*>(result);
386  std::vector<AutofillProfile*> profiles = r->GetValue();
387  STLDeleteElements(&profiles);
388}
389
390void AutofillWebDataBackendImpl::DestroyAutofillCreditCardResult(
391      const WDTypedResult* result) {
392  DCHECK(result->GetType() == AUTOFILL_CREDITCARDS_RESULT);
393  const WDResult<std::vector<CreditCard*> >* r =
394      static_cast<const WDResult<std::vector<CreditCard*> >*>(result);
395
396  std::vector<CreditCard*> credit_cards = r->GetValue();
397  STLDeleteElements(&credit_cards);
398}
399
400}  // namespace autofill
401