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
AutofillWebDataBackendImpl(scoped_refptr<WebDataServiceBackend> web_database_backend,scoped_refptr<base::MessageLoopProxy> ui_thread,scoped_refptr<base::MessageLoopProxy> db_thread,const base::Closure & on_changed_callback)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
AddObserver(AutofillWebDataServiceObserverOnDBThread * observer)40 void AutofillWebDataBackendImpl::AddObserver(
41 AutofillWebDataServiceObserverOnDBThread* observer) {
42 DCHECK(db_thread_->BelongsToCurrentThread());
43 db_observer_list_.AddObserver(observer);
44 }
45
RemoveObserver(AutofillWebDataServiceObserverOnDBThread * observer)46 void AutofillWebDataBackendImpl::RemoveObserver(
47 AutofillWebDataServiceObserverOnDBThread* observer) {
48 DCHECK(db_thread_->BelongsToCurrentThread());
49 db_observer_list_.RemoveObserver(observer);
50 }
51
~AutofillWebDataBackendImpl()52 AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() {
53 DCHECK(!user_data_.get()); // Forgot to call ResetUserData?
54 }
55
GetDatabase()56 WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
57 DCHECK(db_thread_->BelongsToCurrentThread());
58 return web_database_backend_->database();
59 }
60
RemoveExpiredFormElements()61 void AutofillWebDataBackendImpl::RemoveExpiredFormElements() {
62 web_database_backend_->ExecuteWriteTask(
63 Bind(&AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl,
64 this));
65 }
66
NotifyOfMultipleAutofillChanges()67 void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
68 DCHECK(db_thread_->BelongsToCurrentThread());
69 ui_thread_->PostTask(FROM_HERE, on_changed_callback_);
70 }
71
GetDBUserData()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
ResetUserData()79 void AutofillWebDataBackendImpl::ResetUserData() {
80 user_data_.reset();
81 }
82
AddFormElements(const std::vector<FormFieldData> & fields,WebDatabase * db)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>
GetFormValuesForElementName(const base::string16 & name,const base::string16 & prefix,int limit,WebDatabase * db)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
HasFormElements(WebDatabase * db)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
RemoveFormElementsAddedBetween(const base::Time & delete_begin,const base::Time & delete_end,WebDatabase * db)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
RemoveFormValueForElementName(const base::string16 & name,const base::string16 & value,WebDatabase * db)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
AddAutofillProfile(const AutofillProfile & profile,WebDatabase * db)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
UpdateAutofillProfile(const AutofillProfile & profile,WebDatabase * db)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
RemoveAutofillProfile(const std::string & guid,WebDatabase * db)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
GetAutofillProfiles(WebDatabase * db)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
UpdateAutofillEntries(const std::vector<autofill::AutofillEntry> & autofill_entries,WebDatabase * db)248 WebDatabase::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
AddCreditCard(const CreditCard & credit_card,WebDatabase * db)259 WebDatabase::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
UpdateCreditCard(const CreditCard & credit_card,WebDatabase * db)270 WebDatabase::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
RemoveCreditCard(const std::string & guid,WebDatabase * db)289 WebDatabase::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
GetCreditCards(WebDatabase * db)299 scoped_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
312 WebDatabase::State
RemoveAutofillDataModifiedBetween(const base::Time & delete_begin,const base::Time & delete_end,WebDatabase * db)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
RemoveOriginURLsModifiedBetween(const base::Time & delete_begin,const base::Time & delete_end,WebDatabase * db)339 WebDatabase::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
RemoveExpiredFormElementsImpl(WebDatabase * db)362 WebDatabase::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
DestroyAutofillProfileResult(const WDTypedResult * result)381 void 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
DestroyAutofillCreditCardResult(const WDTypedResult * result)390 void 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