<commit_before>// Copyright (c) 2009 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/task.h"
#include "base/thread.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.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 "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "webkit/glue/password_form.h"

////////////////////////////////////////////////////////////////////////////////
//
// WebDataService implementation.
//
////////////////////////////////////////////////////////////////////////////////

using base::Time;
using webkit_glue::FormField;
using webkit_glue::PasswordForm;

WebDataService::WebDataService()
  : is_running_(false),
    db_(NULL),
    failed_init_(false),
    should_commit_(false),
    next_request_handle_(1),
    main_loop_(MessageLoop::current()) {
}

WebDataService::~WebDataService() {
  if (is_running_ && db_) {
    DLOG_ASSERT("WebDataService dtor called without Shutdown");
  }
}

bool WebDataService::Init(const FilePath& profile_path) {
  FilePath path = profile_path;
  path = path.Append(chrome::kWebDataFilename);
  return InitWithPath(path);
}

bool WebDataService::InitWithPath(const FilePath& path) {
  path_ = path;
  is_running_ = true;
  ScheduleTask(NewRunnableMethod(this,
      &WebDataService::InitializeDatabaseIfNecessary));
  return true;
}

void WebDataService::Shutdown() {
  UnloadDatabase();
}

bool WebDataService::IsRunning() const {
  return is_running_;
}

void WebDataService::UnloadDatabase() {
  ScheduleTask(NewRunnableMethod(this, &WebDataService::ShutdownDatabase));
}

void WebDataService::ScheduleCommit() {
  if (should_commit_ == false) {
    should_commit_ = true;
    ScheduleTask(NewRunnableMethod(this, &WebDataService::Commit));
  }
}

void WebDataService::ScheduleTask(Task* t) {
  if (is_running_)
    ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, t);
  else
    NOTREACHED() << "Task scheduled after Shutdown()";
}

void WebDataService::RegisterRequest(WebDataRequest* request) {
  AutoLock l(pending_lock_);
  pending_requests_[request->GetHandle()] = request;
}

void WebDataService::CancelRequest(Handle h) {
  AutoLock l(pending_lock_);
  RequestMap::iterator i = pending_requests_.find(h);
  if (i == pending_requests_.end()) {
    NOTREACHED() << "Canceling a nonexistant web data service request";
    return;
  }
  i->second->Cancel();
}

void WebDataService::AddFormFieldValues(
    const std::vector<FormField>& element) {
  GenericRequest<std::vector<FormField> >* request =
      new GenericRequest<std::vector<FormField> >(
          this, GetNextRequestHandle(), NULL, element);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod(this,
                                 &WebDataService::AddFormFieldValuesImpl,
                                 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::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(int profile_id) {
  GenericRequest<int>* request =
      new GenericRequest<int>(
          this, GetNextRequestHandle(), NULL, profile_id);
  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::AddCreditCard(const CreditCard& creditcard) {
  GenericRequest<CreditCard>* request =
      new GenericRequest<CreditCard>(
          this, GetNextRequestHandle(), NULL, creditcard);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod(this,
                                 &WebDataService::AddCreditCardImpl,
                                 request));
}

void WebDataService::UpdateCreditCard(const CreditCard& creditcard) {
  GenericRequest<CreditCard>* request =
      new GenericRequest<CreditCard>(
          this, GetNextRequestHandle(), NULL, creditcard);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod(this,
                                 &WebDataService::UpdateCreditCardImpl,
                                 request));
}

void WebDataService::RemoveCreditCard(int creditcard_id) {
  GenericRequest<int>* request =
      new GenericRequest<int>(
          this, GetNextRequestHandle(), NULL, creditcard_id);
  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();
}

bool WebDataService::IsDatabaseLoaded() {
  return db_ != NULL;
}

WebDatabase* WebDataService::GetDatabase() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
  return db_;
}

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());
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Keywords.
//
//////////////////////////////////////////////////////////////////////////////

void WebDataService::AddKeyword(const TemplateURL& url) {
  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<TemplateURL::IDType>* request =
      new GenericRequest<TemplateURL::IDType>(this, GetNextRequestHandle(),
                                              NULL, url.id());
  RegisterRequest(request);
  ScheduleTask(
      NewRunnableMethod(this, &WebDataService::RemoveKeywordImpl, request));
}

void WebDataService::UpdateKeyword(const TemplateURL& url) {
  GenericRequest<TemplateURL>* request =
      new GenericRequest<TemplateURL>(this, GetNextRequestHandle(), NULL, url);<commit_msg>Fix memory leak for autofil profiles and credit cards. BUG=42185 TEST=In the bug. Review URL: http://codereview.chromium.org/1732004<commit_after>// Copyright (c) 2009 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/thread.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.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 "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "webkit/glue/password_form.h"

////////////////////////////////////////////////////////////////////////////////
//
// WebDataService implementation.
//
////////////////////////////////////////////////////////////////////////////////

using base::Time;
using webkit_glue::FormField;
using webkit_glue::PasswordForm;

WebDataService::WebDataService()
  : is_running_(false),
    db_(NULL),
    failed_init_(false),
    should_commit_(false),
    next_request_handle_(1),
    main_loop_(MessageLoop::current()) {
}

WebDataService::~WebDataService() {
  if (is_running_ && db_) {
    DLOG_ASSERT("WebDataService dtor called without Shutdown");
  }
}

bool WebDataService::Init(const FilePath& profile_path) {
  FilePath path = profile_path;
  path = path.Append(chrome::kWebDataFilename);
  return InitWithPath(path);
}

bool WebDataService::InitWithPath(const FilePath& path) {
  path_ = path;
  is_running_ = true;
  ScheduleTask(NewRunnableMethod(this,
      &WebDataService::InitializeDatabaseIfNecessary));
  return true;
}

void WebDataService::Shutdown() {
  UnloadDatabase();
}

bool WebDataService::IsRunning() const {
  return is_running_;
}

void WebDataService::UnloadDatabase() {
  ScheduleTask(NewRunnableMethod(this, &WebDataService::ShutdownDatabase));
}

void WebDataService::ScheduleCommit() {
  if (should_commit_ == false) {
    should_commit_ = true;
    ScheduleTask(NewRunnableMethod(this, &WebDataService::Commit));
  }
}

void WebDataService::ScheduleTask(Task* t) {
  if (is_running_)
    ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, t);
  else
    NOTREACHED() << "Task scheduled after Shutdown()";
}

void WebDataService::RegisterRequest(WebDataRequest* request) {
  AutoLock l(pending_lock_);
  pending_requests_[request->GetHandle()] = request;
}

void WebDataService::CancelRequest(Handle h) {
  AutoLock l(pending_lock_);
  RequestMap::iterator i = pending_requests_.find(h);
  if (i == pending_requests_.end()) {
    NOTREACHED() << "Canceling a nonexistant web data service request";
    return;
  }
  i->second->Cancel();
}

void WebDataService::AddFormFieldValues(
    const std::vector<FormField>& element) {
  GenericRequest<std::vector<FormField> >* request =
      new GenericRequest<std::vector<FormField> >(
          this, GetNextRequestHandle(), NULL, element);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod(this,
                                 &WebDataService::AddFormFieldValuesImpl,
                                 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::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(int profile_id) {
  GenericRequest<int>* request =
      new GenericRequest<int>(
          this, GetNextRequestHandle(), NULL, profile_id);
  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::AddCreditCard(const CreditCard& creditcard) {
  GenericRequest<CreditCard>* request =
      new GenericRequest<CreditCard>(
          this, GetNextRequestHandle(), NULL, creditcard);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod(this,
                                 &WebDataService::AddCreditCardImpl,
                                 request));
}

void WebDataService::UpdateCreditCard(const CreditCard& creditcard) {
  GenericRequest<CreditCard>* request =
      new GenericRequest<CreditCard>(
          this, GetNextRequestHandle(), NULL, creditcard);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod(this,
                                 &WebDataService::UpdateCreditCardImpl,
                                 request));
}

void WebDataService::RemoveCreditCard(int creditcard_id) {
  GenericRequest<int>* request =
      new GenericRequest<int>(
          this, GetNextRequestHandle(), NULL, creditcard_id);
  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();
}

bool WebDataService::IsDatabaseLoaded() {
  return db_ != NULL;
}

WebDatabase* WebDataService::GetDatabase() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
  return db_;
}

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);
      }
    }
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Keywords.
//
//////////////////////////////////////////////////////////////////////////////

void WebDataService::AddKeyword(const TemplateURL& url) {
  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<TemplateURL::IDType>* request =
      new GenericRequest<TemplateURL::IDType>(this, GetNextRequestHandle(),
                                              NULL, url.id());
  RegisterRequest(request);
  ScheduleTask(
      NewRunnableMethod(this, &WebDataService::RemoveKeywordImpl, request));
}

void WebDataService::UpdateKeyword(const TemplateURL& url) {
  GenericRequest<TemplateURL>* request =
      new GenericRequest<TemplateURL>(this, GetNextRequestHandle(), NULL, url);
{'fraction_non_alphanumeric': 0.13402061855670103, 'fraction_numerical': 0.002860948058994722, 'mean_word_length': 2.926786751888437, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 96, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 50, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6708133', 'n_tokens_mistral': 5451, 'n_tokens_neox': 5338, 'n_words': 1011}