blob: 3c4deea28f65d59bfe4d9ffe8ae331b39c4b61f8 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "components/autofill/core/browser/autofill_country.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/webdata/common/web_database_backend.h"
using base::Bind;
using base::Time;
namespace autofill {
AutofillWebDataBackendImpl::AutofillWebDataBackendImpl(
scoped_refptr<WebDatabaseBackend> web_database_backend,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const base::Closure& on_changed_callback,
const base::Callback<void(syncer::ModelType)>& on_sync_started_callback)
: base::RefCountedDeleteOnSequence<AutofillWebDataBackendImpl>(
std::move(db_task_runner)),
ui_task_runner_(ui_task_runner),
web_database_backend_(web_database_backend),
on_changed_callback_(on_changed_callback),
on_sync_started_callback_(on_sync_started_callback) {}
void AutofillWebDataBackendImpl::AddObserver(
AutofillWebDataServiceObserverOnDBSequence* observer) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
db_observer_list_.AddObserver(observer);
}
void AutofillWebDataBackendImpl::RemoveObserver(
AutofillWebDataServiceObserverOnDBSequence* observer) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
db_observer_list_.RemoveObserver(observer);
}
AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() {
DCHECK(!user_data_); // Forgot to call ResetUserData?
}
WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
return web_database_backend_->database();
}
void AutofillWebDataBackendImpl::RemoveExpiredFormElements() {
web_database_backend_->ExecuteWriteTask(
Bind(&AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl,
this));
}
void AutofillWebDataBackendImpl::NotifyOfAutofillProfileChanged(
const AutofillProfileChange& change) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
// DB sequence notification.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillProfileChanged(change);
}
void AutofillWebDataBackendImpl::NotifyOfCreditCardChanged(
const CreditCardChange& change) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
// DB sequence notification.
for (auto& db_observer : db_observer_list_)
db_observer.CreditCardChanged(change);
}
void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
// DB sequence notification.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillMultipleChanged();
// UI sequence notification.
ui_task_runner_->PostTask(FROM_HERE, on_changed_callback_);
}
void AutofillWebDataBackendImpl::NotifyThatSyncHasStarted(
syncer::ModelType model_type) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (on_sync_started_callback_.is_null())
return;
// UI sequence notification.
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(on_sync_started_callback_, model_type));
}
base::SupportsUserData* AutofillWebDataBackendImpl::GetDBUserData() {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (!user_data_)
user_data_.reset(new SupportsUserDataAggregatable());
return user_data_.get();
}
void AutofillWebDataBackendImpl::ResetUserData() {
user_data_.reset();
}
WebDatabase::State AutofillWebDataBackendImpl::AddFormElements(
const std::vector<FormFieldData>& fields, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
AutofillChangeList changes;
if (!AutofillTable::FromWebDatabase(db)->AddFormFieldValues(
fields, &changes)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
// Post the notifications including the list of affected keys.
// This is sent here so that work resulting from this notification will be
// done on the DB sequence, and not the UI sequence.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
return WebDatabase::COMMIT_NEEDED;
}
std::unique_ptr<WDTypedResult>
AutofillWebDataBackendImpl::GetFormValuesForElementName(
const base::string16& name,
const base::string16& prefix,
int limit,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<base::string16> values;
AutofillTable::FromWebDatabase(db)->GetFormValuesForElementName(
name, prefix, &values, limit);
return std::unique_ptr<WDTypedResult>(
new WDResult<std::vector<base::string16>>(AUTOFILL_VALUE_RESULT, values));
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween(
const base::Time& delete_begin,
const base::Time& delete_end,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
AutofillChangeList changes;
if (AutofillTable::FromWebDatabase(db)->RemoveFormElementsAddedBetween(
delete_begin, delete_end, &changes)) {
if (!changes.empty()) {
// Post the notifications including the list of affected keys.
// This is sent here so that work resulting from this notification
// will be done on the DB sequence, and not the UI sequence.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
}
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveFormValueForElementName(
const base::string16& name, const base::string16& value, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->RemoveFormElement(name, value)) {
AutofillChangeList changes;
changes.push_back(
AutofillChange(AutofillChange::REMOVE, AutofillKey(name, value)));
// Post the notifications including the list of affected keys.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile(
const AutofillProfile& profile, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->AddAutofillProfile(profile)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
// Send GUID-based notification.
AutofillProfileChange change(
AutofillProfileChange::ADD, profile.guid(), &profile);
for (auto& db_observer : db_observer_list_)
db_observer.AutofillProfileChanged(change);
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile(
const AutofillProfile& profile, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
// Only perform the update if the profile exists. It is currently
// valid to try to update a missing profile. We simply drop the write and
// the caller will detect this on the next refresh.
std::unique_ptr<AutofillProfile> original_profile =
AutofillTable::FromWebDatabase(db)->GetAutofillProfile(profile.guid());
if (!original_profile) {
return WebDatabase::COMMIT_NOT_NEEDED;
}
if (!AutofillTable::FromWebDatabase(db)->UpdateAutofillProfile(profile)) {
NOTREACHED();
return WebDatabase::COMMIT_NEEDED;
}
// Send GUID-based notification.
AutofillProfileChange change(
AutofillProfileChange::UPDATE, profile.guid(), &profile);
for (auto& db_observer : db_observer_list_)
db_observer.AutofillProfileChanged(change);
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile(
const std::string& guid, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::unique_ptr<AutofillProfile> profile =
AutofillTable::FromWebDatabase(db)->GetAutofillProfile(guid);
if (!profile) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
if (!AutofillTable::FromWebDatabase(db)->RemoveAutofillProfile(guid)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
// Send GUID-based notification.
AutofillProfileChange change(AutofillProfileChange::REMOVE, guid, nullptr);
for (auto& db_observer : db_observer_list_)
db_observer.AutofillProfileChanged(change);
return WebDatabase::COMMIT_NEEDED;
}
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetAutofillProfiles(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<AutofillProfile>> profiles;
AutofillTable::FromWebDatabase(db)->GetAutofillProfiles(&profiles);
return std::unique_ptr<WDTypedResult>(
new WDResult<std::vector<std::unique_ptr<AutofillProfile>>>(
AUTOFILL_PROFILES_RESULT, std::move(profiles)));
}
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerProfiles(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<AutofillProfile>> profiles;
AutofillTable::FromWebDatabase(db)->GetServerProfiles(&profiles);
return std::unique_ptr<WDTypedResult>(
new WDResult<std::vector<std::unique_ptr<AutofillProfile>>>(
AUTOFILL_PROFILES_RESULT, std::move(profiles)));
}
std::unique_ptr<WDTypedResult>
AutofillWebDataBackendImpl::GetCountOfValuesContainedBetween(
const base::Time& begin,
const base::Time& end,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
int value = AutofillTable::FromWebDatabase(db)
->GetCountOfValuesContainedBetween(begin, end);
return std::unique_ptr<WDTypedResult>(
new WDResult<int>(AUTOFILL_VALUE_RESULT, value));
}
WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillEntries(
const std::vector<AutofillEntry>& autofill_entries,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)
->UpdateAutofillEntries(autofill_entries))
return WebDatabase::COMMIT_NOT_NEEDED;
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard(
const CreditCard& credit_card, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->AddCreditCard(credit_card)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
for (auto& db_observer : db_observer_list_) {
db_observer.CreditCardChanged(CreditCardChange(
CreditCardChange::ADD, credit_card.guid(), &credit_card));
}
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard(
const CreditCard& credit_card, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
// It is currently valid to try to update a missing profile. We simply drop
// the write and the caller will detect this on the next refresh.
std::unique_ptr<CreditCard> original_credit_card =
AutofillTable::FromWebDatabase(db)->GetCreditCard(credit_card.guid());
if (!original_credit_card)
return WebDatabase::COMMIT_NOT_NEEDED;
if (!AutofillTable::FromWebDatabase(db)->UpdateCreditCard(credit_card)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
for (auto& db_observer : db_observer_list_) {
db_observer.CreditCardChanged(CreditCardChange(
CreditCardChange::UPDATE, credit_card.guid(), &credit_card));
}
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard(
const std::string& guid, WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->RemoveCreditCard(guid)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
for (auto& db_observer : db_observer_list_) {
db_observer.CreditCardChanged(
CreditCardChange(CreditCardChange::REMOVE, guid, nullptr));
}
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::AddFullServerCreditCard(
const CreditCard& credit_card,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->AddFullServerCreditCard(
credit_card)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
}
for (auto& db_observer : db_observer_list_) {
db_observer.CreditCardChanged(CreditCardChange(
CreditCardChange::ADD, credit_card.guid(), &credit_card));
}
return WebDatabase::COMMIT_NEEDED;
}
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetCreditCards(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<CreditCard>> credit_cards;
AutofillTable::FromWebDatabase(db)->GetCreditCards(&credit_cards);
return std::unique_ptr<WDTypedResult>(
new WDResult<std::vector<std::unique_ptr<CreditCard>>>(
AUTOFILL_CREDITCARDS_RESULT, std::move(credit_cards)));
}
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerCreditCards(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<CreditCard>> credit_cards;
AutofillTable::FromWebDatabase(db)->GetServerCreditCards(&credit_cards);
return std::unique_ptr<WDTypedResult>(
new WDResult<std::vector<std::unique_ptr<CreditCard>>>(
AUTOFILL_CREDITCARDS_RESULT, std::move(credit_cards)));
}
WebDatabase::State AutofillWebDataBackendImpl::UnmaskServerCreditCard(
const CreditCard& card,
const base::string16& full_number,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->UnmaskServerCreditCard(
card, full_number))
return WebDatabase::COMMIT_NEEDED;
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State
AutofillWebDataBackendImpl::MaskServerCreditCard(
const std::string& id,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->MaskServerCreditCard(id))
return WebDatabase::COMMIT_NEEDED;
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::UpdateServerCardMetadata(
const CreditCard& card,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
DCHECK_NE(CreditCard::LOCAL_CARD, card.record_type());
if (!AutofillTable::FromWebDatabase(db)->UpdateServerCardMetadata(card))
return WebDatabase::COMMIT_NOT_NEEDED;
for (auto& db_observer : db_observer_list_) {
db_observer.CreditCardChanged(
CreditCardChange(CreditCardChange::UPDATE, card.server_id(), &card));
}
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata(
const AutofillProfile& profile,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
DCHECK_EQ(AutofillProfile::SERVER_PROFILE, profile.record_type());
if (!AutofillTable::FromWebDatabase(db)->UpdateServerAddressMetadata(
profile)) {
return WebDatabase::COMMIT_NOT_NEEDED;
}
for (auto& db_observer : db_observer_list_) {
db_observer.AutofillProfileChanged(AutofillProfileChange(
AutofillProfileChange::UPDATE, profile.server_id(), &profile));
}
return WebDatabase::COMMIT_NEEDED;
}
std::unique_ptr<WDTypedResult>
AutofillWebDataBackendImpl::GetPaymentsCustomerData(WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::unique_ptr<PaymentsCustomerData> customer_data;
AutofillTable::FromWebDatabase(db)->GetPaymentsCustomerData(&customer_data);
return std::make_unique<WDResult<std::unique_ptr<PaymentsCustomerData>>>(
AUTOFILL_CUSTOMERDATA_RESULT, std::move(customer_data));
}
WebDatabase::State AutofillWebDataBackendImpl::ClearAllServerData(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->ClearAllServerData()) {
NotifyOfMultipleAutofillChanges();
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::ClearAllLocalData(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->ClearAllLocalData()) {
NotifyOfMultipleAutofillChanges();
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State
AutofillWebDataBackendImpl::RemoveAutofillDataModifiedBetween(
const base::Time& delete_begin,
const base::Time& delete_end,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<std::string> profile_guids;
std::vector<std::string> credit_card_guids;
if (AutofillTable::FromWebDatabase(db)->RemoveAutofillDataModifiedBetween(
delete_begin,
delete_end,
&profile_guids,
&credit_card_guids)) {
for (const std::string& guid : profile_guids) {
for (auto& db_observer : db_observer_list_) {
db_observer.AutofillProfileChanged(AutofillProfileChange(
AutofillProfileChange::REMOVE, guid, nullptr));
}
}
for (const std::string& guid : credit_card_guids) {
for (auto& db_observer : db_observer_list_) {
db_observer.CreditCardChanged(
CreditCardChange(CreditCardChange::REMOVE, guid, nullptr));
}
}
// Note: It is the caller's responsibility to post notifications for any
// changes, e.g. by calling the Refresh() method of PersonalDataManager.
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveOriginURLsModifiedBetween(
const base::Time& delete_begin,
const base::Time& delete_end,
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<AutofillProfile>> profiles;
if (!AutofillTable::FromWebDatabase(db)->RemoveOriginURLsModifiedBetween(
delete_begin, delete_end, &profiles)) {
return WebDatabase::COMMIT_NOT_NEEDED;
}
for (const auto& profile : profiles) {
AutofillProfileChange change(AutofillProfileChange::UPDATE, profile->guid(),
profile.get());
for (auto& db_observer : db_observer_list_)
db_observer.AutofillProfileChanged(change);
}
// Note: It is the caller's responsibility to post notifications for any
// changes, e.g. by calling the Refresh() method of PersonalDataManager.
return WebDatabase::COMMIT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
AutofillChangeList changes;
if (AutofillTable::FromWebDatabase(db)->RemoveExpiredFormElements(&changes)) {
if (!changes.empty()) {
// Post the notifications including the list of affected keys.
// This is sent here so that work resulting from this notification
// will be done on the DB sequence, and not the UI sequence.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
}
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
WebDatabase::State AutofillWebDataBackendImpl::RemoveOrphanAutofillTableRows(
WebDatabase* db) {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->RemoveOrphanAutofillTableRows()) {
return WebDatabase::COMMIT_NEEDED;
}
return WebDatabase::COMMIT_NOT_NEEDED;
}
} // namespace autofill