// Copyright (c) 2011 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 "chrome/browser/webdata/web_data_service.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/task.h"
#include "base/threading/thread.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/ui/profile_error_dialog.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/chrome_constants.h"
#include "content/common/notification_details.h"
#include "content/common/notification_service.h"
#include "content/common/notification_source.h"
#include "content/common/notification_type.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"
////////////////////////////////////////////////////////////////////////////////
//
// WebDataService implementation.
//
////////////////////////////////////////////////////////////////////////////////
using base::Time;
using webkit_glue::FormField;
using webkit_glue::PasswordForm;
WDAppImagesResult::WDAppImagesResult() : has_all_images(false) {}
WDAppImagesResult::~WDAppImagesResult() {}
WDKeywordsResult::WDKeywordsResult()
: default_search_provider_id(0),
builtin_keyword_version(0) {
}
WDKeywordsResult::~WDKeywordsResult() {}
WebDataService::WebDataService()
: is_running_(false),
db_(NULL),
failed_init_(false),
should_commit_(false),
next_request_handle_(1),
main_loop_(MessageLoop::current()) {
}
bool WebDataService::Init(const FilePath& profile_path) {
FilePath path = profile_path;
path = path.Append(chrome::kWebDataFilename);
return InitWithPath(path);
}
void WebDataService::Shutdown() {
UnloadDatabase();
}
bool WebDataService::IsRunning() const {
return is_running_;
}
void WebDataService::UnloadDatabase() {
ScheduleTask(NewRunnableMethod(this, &WebDataService::ShutdownDatabase));
}
void WebDataService::CancelRequest(Handle h) {
base::AutoLock l(pending_lock_);
RequestMap::iterator i = pending_requests_.find(h);
if (i == pending_requests_.end()) {
NOTREACHED() << "Canceling a nonexistent web data service request";
return;
}
i->second->Cancel();
}
bool WebDataService::IsDatabaseLoaded() {
return db_ != NULL;
}
WebDatabase* WebDataService::GetDatabase() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
return db_;
}
//////////////////////////////////////////////////////////////////////////////
//
// Keywords.
//
//////////////////////////////////////////////////////////////////////////////
void WebDataService::AddKeyword(const TemplateURL& url) {
// Ensure that the keyword is already generated (and cached) before caching
// the TemplateURL for use on another keyword.
url.EnsureKeyword();
GenericRequest<TemplateURL>* request =
new GenericRequest<TemplateURL>(this, GetNextRequestHandle(), NULL, url);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::AddKeywordImpl,
request));
}
void WebDataService::RemoveKeyword(const TemplateURL& url) {
GenericRequest<TemplateURLID>* request =
new GenericRequest<TemplateURLID>(this, GetNextRequestHandle(),
NULL, url.id());
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this, &WebDataService::RemoveKeywordImpl, request));
}
void WebDataService::UpdateKeyword(const TemplateURL& url) {
// Ensure that the keyword is already generated (and cached) before caching
// the TemplateURL for use on another keyword.
url.EnsureKeyword();
GenericRequest<TemplateURL>* request =
new GenericRequest<TemplateURL>(this, GetNextRequestHandle(), NULL, url);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this, &WebDataService::UpdateKeywordImpl, request));
}
WebDataService::Handle WebDataService::GetKeywords(
WebDataServiceConsumer* consumer) {
WebDataRequest* request =
new WebDataRequest(this, GetNextRequestHandle(), consumer);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this,
&WebDataService::GetKeywordsImpl,
request));
return request->GetHandle();
}
void WebDataService::SetDefaultSearchProvider(const TemplateURL* url) {
GenericRequest<TemplateURLID>* request =
new GenericRequest<TemplateURLID>(this,
GetNextRequestHandle(),
NULL,
url ? url->id() : 0);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this, &WebDataService::SetDefaultSearchProviderImpl,
request));
}
void WebDataService::SetBuiltinKeywordVersion(int version) {
GenericRequest<int>* request =
new GenericRequest<int>(this, GetNextRequestHandle(), NULL, version);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this, &WebDataService::SetBuiltinKeywordVersionImpl,
request));
}
//////////////////////////////////////////////////////////////////////////////
//
// Web Apps
//
//////////////////////////////////////////////////////////////////////////////
void WebDataService::SetWebAppImage(const GURL& app_url,
const SkBitmap& image) {
GenericRequest2<GURL, SkBitmap>* request =
new GenericRequest2<GURL, SkBitmap>(this, GetNextRequestHandle(),
NULL, app_url, image);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::SetWebAppImageImpl,
request));
}
void WebDataService::SetWebAppHasAllImages(const GURL& app_url,
bool has_all_images) {
GenericRequest2<GURL, bool>* request =
new GenericRequest2<GURL, bool>(this, GetNextRequestHandle(),
NULL, app_url, has_all_images);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::SetWebAppHasAllImagesImpl,
request));
}
void WebDataService::RemoveWebApp(const GURL& app_url) {
GenericRequest<GURL>* request =
new GenericRequest<GURL>(this, GetNextRequestHandle(), NULL, app_url);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::RemoveWebAppImpl,
request));
}
WebDataService::Handle WebDataService::GetWebAppImages(
const GURL& app_url,
WebDataServiceConsumer* consumer) {
GenericRequest<GURL>* request =
new GenericRequest<GURL>(this, GetNextRequestHandle(), consumer, app_url);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::GetWebAppImagesImpl,
request));
return request->GetHandle();
}
////////////////////////////////////////////////////////////////////////////////
//
// Token Service
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::SetTokenForService(const std::string& service,
const std::string& token) {
GenericRequest2<std::string, std::string>* request =
new GenericRequest2<std::string, std::string>(
this, GetNextRequestHandle(), NULL, service, token);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::SetTokenForServiceImpl,
request));
}
void WebDataService::RemoveAllTokens() {
GenericRequest<std::string>* request =
new GenericRequest<std::string>(
this, GetNextRequestHandle(), NULL, std::string());
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::RemoveAllTokensImpl,
request));
}
// Null on failure. Success is WDResult<std::string>
WebDataService::Handle WebDataService::GetAllTokens(
WebDataServiceConsumer* consumer) {
GenericRequest<std::string>* request =
new GenericRequest<std::string>(
this, GetNextRequestHandle(), consumer, std::string());
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::GetAllTokensImpl,
request));
return request->GetHandle();
}
////////////////////////////////////////////////////////////////////////////////
//
// Password manager.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::AddLogin(const PasswordForm& form) {
GenericRequest<PasswordForm>* request =
new GenericRequest<PasswordForm>(this, GetNextRequestHandle(), NULL,
form);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::AddLoginImpl,
request));
}
void WebDataService::UpdateLogin(const PasswordForm& form) {
GenericRequest<PasswordForm>* request =
new GenericRequest<PasswordForm>(this, GetNextRequestHandle(),
NULL, form);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::UpdateLoginImpl,
request));
}
void WebDataService::RemoveLogin(const PasswordForm& form) {
GenericRequest<PasswordForm>* request =
new GenericRequest<PasswordForm>(this, GetNextRequestHandle(), NULL,
form);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::RemoveLoginImpl,
request));
}
void WebDataService::RemoveLoginsCreatedBetween(const Time& delete_begin,
const Time& delete_end) {
GenericRequest2<Time, Time>* request =
new GenericRequest2<Time, Time>(this,
GetNextRequestHandle(),
NULL,
delete_begin,
delete_end);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::RemoveLoginsCreatedBetweenImpl, request));
}
void WebDataService::RemoveLoginsCreatedAfter(const Time& delete_begin) {
RemoveLoginsCreatedBetween(delete_begin, Time());
}
WebDataService::Handle WebDataService::GetLogins(
const PasswordForm& form,
WebDataServiceConsumer* consumer) {
GenericRequest<PasswordForm>* request =
new GenericRequest<PasswordForm>(this, GetNextRequestHandle(),
consumer, form);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this, &WebDataService::GetLoginsImpl,
request));
return request->GetHandle();
}
WebDataService::Handle WebDataService::GetAutofillableLogins(
WebDataServiceConsumer* consumer) {
WebDataRequest* request =
new WebDataRequest(this, GetNextRequestHandle(), consumer);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::GetAutofillableLoginsImpl,
request));
return request->GetHandle();
}
WebDataService::Handle WebDataService::GetBlacklistLogins(
WebDataServiceConsumer* consumer) {
WebDataRequest* request =
new WebDataRequest(this, GetNextRequestHandle(), consumer);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::GetBlacklistLoginsImpl,
request));
return request->GetHandle();
}
////////////////////////////////////////////////////////////////////////////////
//
// Autofill.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::AddFormFields(
const std::vector<FormField>& fields) {
GenericRequest<std::vector<FormField> >* request =
new GenericRequest<std::vector<FormField> >(
this, GetNextRequestHandle(), NULL, fields);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::AddFormElementsImpl,
request));
}
WebDataService::Handle WebDataService::GetFormValuesForElementName(
const string16& name, const string16& prefix, int limit,
WebDataServiceConsumer* consumer) {
WebDataRequest* request =
new WebDataRequest(this, GetNextRequestHandle(), consumer);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this,
&WebDataService::GetFormValuesForElementNameImpl,
request,
name,
prefix,
limit));
return request->GetHandle();
}
void WebDataService::RemoveFormElementsAddedBetween(const Time& delete_begin,
const Time& delete_end) {
GenericRequest2<Time, Time>* request =
new GenericRequest2<Time, Time>(this,
GetNextRequestHandle(),
NULL,
delete_begin,
delete_end);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::RemoveFormElementsAddedBetweenImpl, request));
}
void WebDataService::RemoveFormValueForElementName(
const string16& name, const string16& value) {
GenericRequest2<string16, string16>* request =
new GenericRequest2<string16, string16>(this,
GetNextRequestHandle(),
NULL,
name, value);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this,
&WebDataService::RemoveFormValueForElementNameImpl,
request));
}
void WebDataService::AddAutofillProfile(const AutofillProfile& profile) {
GenericRequest<AutofillProfile>* request =
new GenericRequest<AutofillProfile>(
this, GetNextRequestHandle(), NULL, profile);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::AddAutofillProfileImpl,
request));
}
void WebDataService::UpdateAutofillProfile(const AutofillProfile& profile) {
GenericRequest<AutofillProfile>* request =
new GenericRequest<AutofillProfile>(
this, GetNextRequestHandle(), NULL, profile);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::UpdateAutofillProfileImpl,
request));
}
void WebDataService::RemoveAutofillProfile(const std::string& guid) {
GenericRequest<std::string>* request =
new GenericRequest<std::string>(
this, GetNextRequestHandle(), NULL, guid);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::RemoveAutofillProfileImpl,
request));
}
WebDataService::Handle WebDataService::GetAutofillProfiles(
WebDataServiceConsumer* consumer) {
WebDataRequest* request =
new WebDataRequest(this, GetNextRequestHandle(), consumer);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this,
&WebDataService::GetAutofillProfilesImpl,
request));
return request->GetHandle();
}
void WebDataService::EmptyMigrationTrash(bool notify_sync) {
GenericRequest<bool>* request =
new GenericRequest<bool>(
this, GetNextRequestHandle(), NULL, notify_sync);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::EmptyMigrationTrashImpl,
request));
}
void WebDataService::AddCreditCard(const CreditCard& credit_card) {
GenericRequest<CreditCard>* request =
new GenericRequest<CreditCard>(
this, GetNextRequestHandle(), NULL, credit_card);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::AddCreditCardImpl,
request));
}
void WebDataService::UpdateCreditCard(const CreditCard& credit_card) {
GenericRequest<CreditCard>* request =
new GenericRequest<CreditCard>(
this, GetNextRequestHandle(), NULL, credit_card);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::UpdateCreditCardImpl,
request));
}
void WebDataService::RemoveCreditCard(const std::string& guid) {
GenericRequest<std::string>* request =
new GenericRequest<std::string>(
this, GetNextRequestHandle(), NULL, guid);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::RemoveCreditCardImpl,
request));
}
WebDataService::Handle WebDataService::GetCreditCards(
WebDataServiceConsumer* consumer) {
WebDataRequest* request =
new WebDataRequest(this, GetNextRequestHandle(), consumer);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this,
&WebDataService::GetCreditCardsImpl,
request));
return request->GetHandle();
}
void WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetween(
const Time& delete_begin,
const Time& delete_end) {
GenericRequest2<Time, Time>* request =
new GenericRequest2<Time, Time>(this,
GetNextRequestHandle(),
NULL,
delete_begin,
delete_end);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(
this,
&WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl,
request));
}
WebDataService::~WebDataService() {
if (is_running_ && db_) {
DLOG_ASSERT("WebDataService dtor called without Shutdown");
}
}
bool WebDataService::InitWithPath(const FilePath& path) {
path_ = path;
is_running_ = true;
ScheduleTask(NewRunnableMethod(this,
&WebDataService::InitializeDatabaseIfNecessary));
return true;
}
void WebDataService::RequestCompleted(Handle h) {
pending_lock_.Acquire();
RequestMap::iterator i = pending_requests_.find(h);
if (i == pending_requests_.end()) {
NOTREACHED() << "Request completed called for an unknown request";
pending_lock_.Release();
return;
}
// Take ownership of the request object and remove it from the map.
scoped_ptr<WebDataRequest> request(i->second);
pending_requests_.erase(i);
pending_lock_.Release();
// Notify the consumer if needed.
WebDataServiceConsumer* consumer;
if (!request->IsCancelled() && (consumer = request->GetConsumer())) {
consumer->OnWebDataServiceRequestDone(request->GetHandle(),
request->GetResult());
} else {
// Nobody is taken ownership of the result, either because it is canceled
// or there is no consumer. Destroy results that require special handling.
WDTypedResult const *result = request->GetResult();
if (result) {
if (result->GetType() == AUTOFILL_PROFILES_RESULT) {
const WDResult<std::vector<AutofillProfile*> >* r =
static_cast<const WDResult<std::vector<AutofillProfile*> >*>(
result);
std::vector<AutofillProfile*> profiles = r->GetValue();
STLDeleteElements(&profiles);
} else if (result->GetType() == AUTOFILL_CREDITCARDS_RESULT) {
const WDResult<std::vector<CreditCard*> >* r =
static_cast<const WDResult<std::vector<CreditCard*> >*>(result);
std::vector<CreditCard*> credit_cards = r->GetValue();
STLDeleteElements(&credit_cards);
}
}
}
}
void WebDataService::RegisterRequest(WebDataRequest* request) {
base::AutoLock l(pending_lock_);
pending_requests_[request->GetHandle()] = request;
}
////////////////////////////////////////////////////////////////////////////////
//
// The following methods are executed in Chrome_WebDataThread.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::DBInitFailed(sql::InitStatus init_status) {
ShowProfileErrorDialog(
(init_status == sql::INIT_FAILURE) ?
IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR);
}
void WebDataService::InitializeDatabaseIfNecessary() {
if (db_ || failed_init_ || path_.empty())
return;
// In the rare case where the db fails to initialize a dialog may get shown
// that blocks the caller, yet allows other messages through. For this reason
// we only set db_ to the created database if creation is successful. That
// way other methods won't do anything as db_ is still NULL.
WebDatabase* db = new WebDatabase();
sql::InitStatus init_status = db->Init(path_);
if (init_status != sql::INIT_OK) {
LOG(ERROR) << "Cannot initialize the web database: " << init_status;
failed_init_ = true;
delete db;
if (main_loop_) {
main_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &WebDataService::DBInitFailed, init_status));
}
return;
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this, &WebDataService::NotifyDatabaseLoadedOnUIThread));
db_ = db;
db_->BeginTransaction();
}
void WebDataService::NotifyDatabaseLoadedOnUIThread() {
// Notify that the database has been initialized.
NotificationService::current()->Notify(NotificationType::WEB_DATABASE_LOADED,
Source<WebDataService>(this),
NotificationService::NoDetails());
}
void WebDataService::ShutdownDatabase() {
should_commit_ = false;
if (db_) {
db_->CommitTransaction();
delete db_;
db_ = NULL;
}
}
void WebDataService::Commit() {
if (should_commit_) {
should_commit_ = false;
if (db_) {
db_->CommitTransaction();
db_->BeginTransaction();
}
}
}
void WebDataService::ScheduleTask(Task* t) {
if (is_running_)
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, t);
else
NOTREACHED() << "Task scheduled after Shutdown()";
}
void WebDataService::ScheduleCommit() {
if (should_commit_ == false) {
should_commit_ = true;
ScheduleTask(NewRunnableMethod(this, &WebDataService::Commit));
}
}
int WebDataService::GetNextRequestHandle() {
base::AutoLock l(pending_lock_);
return ++next_request_handle_;
}
////////////////////////////////////////////////////////////////////////////////
//
// Keywords implementation.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::AddKeywordImpl(GenericRequest<TemplateURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
db_->GetKeywordTable()->AddKeyword(request->GetArgument());
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::RemoveKeywordImpl(
GenericRequest<TemplateURLID>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
DCHECK(request->GetArgument());
db_->GetKeywordTable()->RemoveKeyword(request->GetArgument());
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::UpdateKeywordImpl(GenericRequest<TemplateURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (!db_->GetKeywordTable()->UpdateKeyword(request->GetArgument())) {
NOTREACHED();
return;
}
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::GetKeywordsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
WDKeywordsResult result;
db_->GetKeywordTable()->GetKeywords(&result.keywords);
result.default_search_provider_id =
db_->GetKeywordTable()->GetDefaulSearchProviderID();
result.builtin_keyword_version =
db_->GetKeywordTable()->GetBuitinKeywordVersion();
request->SetResult(
new WDResult<WDKeywordsResult>(KEYWORDS_RESULT, result));
}
request->RequestComplete();
}
void WebDataService::SetDefaultSearchProviderImpl(
GenericRequest<TemplateURLID>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (!db_->GetKeywordTable()->SetDefaultSearchProviderID(
request->GetArgument())) {
NOTREACHED();
return;
}
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::SetBuiltinKeywordVersionImpl(
GenericRequest<int>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (!db_->GetKeywordTable()->SetBuitinKeywordVersion(
request->GetArgument())) {
NOTREACHED();
return;
}
ScheduleCommit();
}
request->RequestComplete();
}
////////////////////////////////////////////////////////////////////////////////
//
// Web Apps implementation.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::SetWebAppImageImpl(
GenericRequest2<GURL, SkBitmap>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
db_->GetWebAppsTable()->SetWebAppImage(
request->GetArgument1(), request->GetArgument2());
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::SetWebAppHasAllImagesImpl(
GenericRequest2<GURL, bool>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
db_->GetWebAppsTable()->SetWebAppHasAllImages(request->GetArgument1(),
request->GetArgument2());
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::RemoveWebAppImpl(GenericRequest<GURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
db_->GetWebAppsTable()->RemoveWebApp(request->GetArgument());
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::GetWebAppImagesImpl(GenericRequest<GURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
WDAppImagesResult result;
result.has_all_images =
db_->GetWebAppsTable()->GetWebAppHasAllImages(request->GetArgument());
db_->GetWebAppsTable()->GetWebAppImages(
request->GetArgument(), &result.images);
request->SetResult(
new WDResult<WDAppImagesResult>(WEB_APP_IMAGES, result));
}
request->RequestComplete();
}
////////////////////////////////////////////////////////////////////////////////
//
// Token Service implementation.
//
////////////////////////////////////////////////////////////////////////////////
// argument std::string is unused
void WebDataService::RemoveAllTokensImpl(
GenericRequest<std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (db_->GetTokenServiceTable()->RemoveAllTokens()) {
ScheduleCommit();
}
}
request->RequestComplete();
}
void WebDataService::SetTokenForServiceImpl(
GenericRequest2<std::string, std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (db_->GetTokenServiceTable()->SetTokenForService(
request->GetArgument1(), request->GetArgument2())) {
ScheduleCommit();
}
}
request->RequestComplete();
}
// argument is unused
void WebDataService::GetAllTokensImpl(
GenericRequest<std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::map<std::string, std::string> map;
db_->GetTokenServiceTable()->GetAllTokens(&map);
request->SetResult(
new WDResult<std::map<std::string, std::string> >(TOKEN_RESULT, map));
}
request->RequestComplete();
}
////////////////////////////////////////////////////////////////////////////////
//
// Password manager implementation.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::AddLoginImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (db_->GetLoginsTable()->AddLogin(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::UpdateLoginImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (db_->GetLoginsTable()->UpdateLogin(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::RemoveLoginImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (db_->GetLoginsTable()->RemoveLogin(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::RemoveLoginsCreatedBetweenImpl(
GenericRequest2<Time, Time>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (db_->GetLoginsTable()->RemoveLoginsCreatedBetween(
request->GetArgument1(), request->GetArgument2())) {
ScheduleCommit();
}
}
request->RequestComplete();
}
void WebDataService::GetLoginsImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<PasswordForm*> forms;
db_->GetLoginsTable()->GetLogins(request->GetArgument(), &forms);
request->SetResult(
new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
}
request->RequestComplete();
}
void WebDataService::GetAutofillableLoginsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<PasswordForm*> forms;
db_->GetLoginsTable()->GetAllLogins(&forms, false);
request->SetResult(
new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
}
request->RequestComplete();
}
void WebDataService::GetBlacklistLoginsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<PasswordForm*> all_forms;
db_->GetLoginsTable()->GetAllLogins(&all_forms, true);
std::vector<PasswordForm*> blacklist_forms;
for (std::vector<PasswordForm*>::iterator i = all_forms.begin();
i != all_forms.end(); ++i) {
scoped_ptr<PasswordForm> form(*i);
if (form->blacklisted_by_user) {
blacklist_forms.push_back(form.release());
}
}
all_forms.clear();
request->SetResult(
new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT,
blacklist_forms));
}
request->RequestComplete();
}
////////////////////////////////////////////////////////////////////////////////
//
// Autofill implementation.
//
////////////////////////////////////////////////////////////////////////////////
void WebDataService::AddFormElementsImpl(
GenericRequest<std::vector<FormField> >* request) {
InitializeDatabaseIfNecessary();
const std::vector<FormField>& form_fields = request->GetArgument();
if (db_ && !request->IsCancelled()) {
AutofillChangeList changes;
if (!db_->GetAutofillTable()->AddFormFieldValues(form_fields, &changes)) {
NOTREACHED();
return;
}
request->SetResult(
new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes));
ScheduleCommit();
// 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 thread, and not the UI thread.
NotificationService::current()->Notify(
NotificationType::AUTOFILL_ENTRIES_CHANGED,
Source<WebDataService>(this),
Details<AutofillChangeList>(&changes));
}
request->RequestComplete();
}
void WebDataService::GetFormValuesForElementNameImpl(WebDataRequest* request,
const string16& name, const string16& prefix, int limit) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<string16> values;
db_->GetAutofillTable()->GetFormValuesForElementName(
name, prefix, &values, limit);
request->SetResult(
new WDResult<std::vector<string16> >(AUTOFILL_VALUE_RESULT, values));
}
request->RequestComplete();
}
void WebDataService::RemoveFormElementsAddedBetweenImpl(
GenericRequest2<Time, Time>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
AutofillChangeList changes;
if (db_->GetAutofillTable()->RemoveFormElementsAddedBetween(
request->GetArgument1(), request->GetArgument2(), &changes)) {
if (!changes.empty()) {
request->SetResult(
new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes));
// 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 thread, and not the UI thread.
NotificationService::current()->Notify(
NotificationType::AUTOFILL_ENTRIES_CHANGED,
Source<WebDataService>(this),
Details<AutofillChangeList>(&changes));
}
ScheduleCommit();
}
}
request->RequestComplete();
}
void WebDataService::RemoveFormValueForElementNameImpl(
GenericRequest2<string16, string16>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const string16& name = request->GetArgument1();
const string16& value = request->GetArgument2();
if (db_->GetAutofillTable()->RemoveFormElement(name, value)) {
AutofillChangeList changes;
changes.push_back(AutofillChange(AutofillChange::REMOVE,
AutofillKey(name, value)));
request->SetResult(
new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes));
ScheduleCommit();
// Post the notifications including the list of affected keys.
NotificationService::current()->Notify(
NotificationType::AUTOFILL_ENTRIES_CHANGED,
Source<WebDataService>(this),
Details<AutofillChangeList>(&changes));
}
}
request->RequestComplete();
}
void WebDataService::AddAutofillProfileImpl(
GenericRequest<AutofillProfile>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const AutofillProfile& profile = request->GetArgument();
if (!db_->GetAutofillTable()->AddAutofillProfile(profile)) {
NOTREACHED();
return;
}
ScheduleCommit();
// Send GUID-based notification.
AutofillProfileChange change(AutofillProfileChange::ADD,
profile.guid(), &profile);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_PROFILE_CHANGED,
Source<WebDataService>(this),
Details<AutofillProfileChange>(&change));
}
request->RequestComplete();
}
void WebDataService::UpdateAutofillProfileImpl(
GenericRequest<AutofillProfile>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const AutofillProfile& profile = request->GetArgument();
// 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.
AutofillProfile* original_profile = NULL;
if (!db_->GetAutofillTable()->GetAutofillProfile(profile.guid(),
&original_profile)) {
request->RequestComplete();
return;
}
scoped_ptr<AutofillProfile> scoped_profile(original_profile);
if (!db_->GetAutofillTable()->UpdateAutofillProfileMulti(profile)) {
NOTREACHED();
return;
}
ScheduleCommit();
// Send GUID-based notification.
AutofillProfileChange change(AutofillProfileChange::UPDATE,
profile.guid(), &profile);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_PROFILE_CHANGED,
Source<WebDataService>(this),
Details<AutofillProfileChange>(&change));
}
request->RequestComplete();
}
void WebDataService::RemoveAutofillProfileImpl(
GenericRequest<std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::string guid = request->GetArgument();
AutofillProfile* profile = NULL;
if (!db_->GetAutofillTable()->GetAutofillProfile(guid, &profile)) {
NOTREACHED();
return;
}
scoped_ptr<AutofillProfile> scoped_profile(profile);
if (!db_->GetAutofillTable()->RemoveAutofillProfile(guid)) {
NOTREACHED();
return;
}
ScheduleCommit();
// Send GUID-based notification.
AutofillProfileChange change(AutofillProfileChange::REMOVE, guid, NULL);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_PROFILE_CHANGED,
Source<WebDataService>(this),
Details<AutofillProfileChange>(&change));
}
request->RequestComplete();
}
void WebDataService::GetAutofillProfilesImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<AutofillProfile*> profiles;
db_->GetAutofillTable()->GetAutofillProfiles(&profiles);
request->SetResult(
new WDResult<std::vector<AutofillProfile*> >(AUTOFILL_PROFILES_RESULT,
profiles));
}
request->RequestComplete();
}
void WebDataService::EmptyMigrationTrashImpl(
GenericRequest<bool>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
bool notify_sync = request->GetArgument();
if (notify_sync) {
std::vector<std::string> guids;
if (!db_->GetAutofillTable()->GetAutofillProfilesInTrash(&guids)) {
NOTREACHED();
return;
}
for (std::vector<std::string>::const_iterator iter = guids.begin();
iter != guids.end(); ++iter) {
// Send GUID-based notification.
AutofillProfileChange change(AutofillProfileChange::REMOVE,
*iter, NULL);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_PROFILE_CHANGED,
Source<WebDataService>(this),
Details<AutofillProfileChange>(&change));
}
// If we trashed any profiles they may have been merged, so send out
// update notifications as well.
if (!guids.empty()) {
std::vector<AutofillProfile*> profiles;
db_->GetAutofillTable()->GetAutofillProfiles(&profiles);
for (std::vector<AutofillProfile*>::const_iterator
iter = profiles.begin();
iter != profiles.end(); ++iter) {
AutofillProfileChange change(AutofillProfileChange::UPDATE,
(*iter)->guid(), *iter);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_PROFILE_CHANGED,
Source<WebDataService>(this),
Details<AutofillProfileChange>(&change));
}
STLDeleteElements(&profiles);
}
}
if (!db_->GetAutofillTable()->EmptyAutofillProfilesTrash()) {
NOTREACHED();
return;
}
ScheduleCommit();
}
request->RequestComplete();
}
void WebDataService::AddCreditCardImpl(
GenericRequest<CreditCard>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const CreditCard& credit_card = request->GetArgument();
if (!db_->GetAutofillTable()->AddCreditCard(credit_card)) {
NOTREACHED();
return;
}
ScheduleCommit();
// Send GUID-based notification.
AutofillCreditCardChange change(AutofillCreditCardChange::ADD,
credit_card.guid(), &credit_card);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_CREDIT_CARD_CHANGED,
Source<WebDataService>(this),
Details<AutofillCreditCardChange>(&change));
}
request->RequestComplete();
}
void WebDataService::UpdateCreditCardImpl(
GenericRequest<CreditCard>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const CreditCard& credit_card = request->GetArgument();
// 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.
CreditCard* original_credit_card = NULL;
if (!db_->GetAutofillTable()->GetCreditCard(credit_card.guid(),
&original_credit_card)) {
request->RequestComplete();
return;
}
scoped_ptr<CreditCard> scoped_credit_card(original_credit_card);
if (!db_->GetAutofillTable()->UpdateCreditCard(credit_card)) {
NOTREACHED();
return;
}
ScheduleCommit();
// Send GUID-based notification.
AutofillCreditCardChange change(AutofillCreditCardChange::UPDATE,
credit_card.guid(), &credit_card);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_CREDIT_CARD_CHANGED,
Source<WebDataService>(this),
Details<AutofillCreditCardChange>(&change));
}
request->RequestComplete();
}
void WebDataService::RemoveCreditCardImpl(
GenericRequest<std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::string guid = request->GetArgument();
if (!db_->GetAutofillTable()->RemoveCreditCard(guid)) {
NOTREACHED();
return;
}
ScheduleCommit();
// Send GUID-based notification.
AutofillCreditCardChange change(AutofillCreditCardChange::REMOVE,
guid, NULL);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_CREDIT_CARD_CHANGED,
Source<WebDataService>(this),
Details<AutofillCreditCardChange>(&change));
}
request->RequestComplete();
}
void WebDataService::GetCreditCardsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<CreditCard*> credit_cards;
db_->GetAutofillTable()->GetCreditCards(&credit_cards);
request->SetResult(
new WDResult<std::vector<CreditCard*> >(AUTOFILL_CREDITCARDS_RESULT,
credit_cards));
}
request->RequestComplete();
}
void WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl(
GenericRequest2<Time, Time>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<std::string> profile_guids;
std::vector<std::string> credit_card_guids;
if (db_->GetAutofillTable()->
RemoveAutofillProfilesAndCreditCardsModifiedBetween(
request->GetArgument1(),
request->GetArgument2(),
&profile_guids,
&credit_card_guids)) {
for (std::vector<std::string>::iterator iter = profile_guids.begin();
iter != profile_guids.end(); ++iter) {
AutofillProfileChange change(AutofillProfileChange::REMOVE, *iter,
NULL);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_PROFILE_CHANGED,
Source<WebDataService>(this),
Details<AutofillProfileChange>(&change));
}
for (std::vector<std::string>::iterator iter = credit_card_guids.begin();
iter != credit_card_guids.end(); ++iter) {
AutofillCreditCardChange change(AutofillCreditCardChange::REMOVE,
*iter, NULL);
NotificationService::current()->Notify(
NotificationType::AUTOFILL_CREDIT_CARD_CHANGED,
Source<WebDataService>(this),
Details<AutofillCreditCardChange>(&change));
}
// Note: It is the caller's responsibility to post notifications for any
// changes, e.g. by calling the Refresh() method of PersonalDataManager.
ScheduleCommit();
}
}
request->RequestComplete();
}
////////////////////////////////////////////////////////////////////////////////
//
// WebDataRequest implementation.
//
////////////////////////////////////////////////////////////////////////////////
WebDataService::WebDataRequest::WebDataRequest(WebDataService* service,
Handle handle,
WebDataServiceConsumer* consumer)
: service_(service),
handle_(handle),
canceled_(false),
consumer_(consumer),
result_(NULL) {
message_loop_ = MessageLoop::current();
}
WebDataService::WebDataRequest::~WebDataRequest() {
delete result_;
}
WebDataService::Handle WebDataService::WebDataRequest::GetHandle() const {
return handle_;
}
WebDataServiceConsumer* WebDataService::WebDataRequest::GetConsumer() const {
return consumer_;
}
bool WebDataService::WebDataRequest::IsCancelled() const {
return canceled_;
}
void WebDataService::WebDataRequest::Cancel() {
canceled_ = true;
consumer_ = NULL;
}
void WebDataService::WebDataRequest::SetResult(WDTypedResult* r) {
result_ = r;
}
const WDTypedResult* WebDataService::WebDataRequest::GetResult() const {
return result_;
}
void WebDataService::WebDataRequest::RequestComplete() {
WebDataService* s = service_;
Task* t = NewRunnableMethod(s,
&WebDataService::RequestCompleted,
handle_);
message_loop_->PostTask(FROM_HERE, t);
}