summaryrefslogtreecommitdiffstats
path: root/chrome/browser/webdata/web_data_service.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/webdata/web_data_service.cc')
-rw-r--r--chrome/browser/webdata/web_data_service.cc687
1 files changed, 687 insertions, 0 deletions
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
new file mode 100644
index 0000000..350e80c
--- /dev/null
+++ b/chrome/browser/webdata/web_data_service.cc
@@ -0,0 +1,687 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "chrome/browser/webdata/web_data_service.h"
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ie7_password.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/common/chrome_constants.h"
+#include "webkit/glue/password_form.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// WebDataService implementation.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+WebDataService::WebDataService() : should_commit_(false),
+ next_request_handle_(1),
+ thread_(NULL),
+ db_(NULL) {
+}
+
+WebDataService::~WebDataService() {
+ if (thread_) {
+ Shutdown();
+ }
+}
+
+bool WebDataService::Init(const std::wstring& profile_path) {
+ std::wstring path = profile_path;
+ file_util::AppendToPath(&path, chrome::kWebDataFilename);
+ return InitWithPath(path);
+}
+
+bool WebDataService::InitWithPath(const std::wstring& path) {
+ thread_ = new Thread("Chrome_WebDataThread");
+
+ if (!thread_->Start()) {
+ delete thread_;
+ thread_ = NULL;
+ return false;
+ }
+
+ ScheduleTask(NewRunnableMethod(this,
+ &WebDataService::InitializeDatabase,
+ path));
+ return true;
+}
+
+class ShutdownTask : public Task {
+ public:
+ explicit ShutdownTask(WebDataService* wds) : service_(wds) {
+ }
+ virtual void Run() {
+ service_->ShutdownDatabase();
+ }
+
+ private:
+
+ WebDataService* service_;
+};
+
+void WebDataService::Shutdown() {
+ if (thread_) {
+ // We cannot use NewRunnableMethod() because this can be called from our
+ // destructor. NewRunnableMethod() would AddRef() this instance.
+ ScheduleTask(new ShutdownTask(this));
+
+ // The thread destructor sends a message to terminate the thread and waits
+ // until the thread has exited.
+ delete thread_;
+ thread_ = NULL;
+ }
+}
+
+bool WebDataService::IsRunning() {
+ return thread_ != NULL;
+}
+
+void WebDataService::ScheduleCommit() {
+ if (should_commit_ == false) {
+ should_commit_ = true;
+ ScheduleTask(NewRunnableMethod(this, &WebDataService::Commit));
+ }
+}
+
+void WebDataService::ScheduleTask(Task* t) {
+ if (thread_)
+ thread_->message_loop()->PostTask(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::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);
+ 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<TemplateURL::IDType>* request =
+ new GenericRequest<TemplateURL::IDType>(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();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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::AddIE7Login(const IE7PasswordInfo& info) {
+ GenericRequest<IE7PasswordInfo>* request =
+ new GenericRequest<IE7PasswordInfo>(this, GetNextRequestHandle(), NULL,
+ info);
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this, &WebDataService::AddIE7LoginImpl,
+ 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::RemoveIE7Login(const IE7PasswordInfo& info) {
+ GenericRequest<IE7PasswordInfo>* request =
+ new GenericRequest<IE7PasswordInfo>(this, GetNextRequestHandle(), NULL,
+ info);
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this, &WebDataService::RemoveIE7LoginImpl,
+ 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::GetIE7Login(
+ const IE7PasswordInfo& info,
+ WebDataServiceConsumer* consumer) {
+ GenericRequest<IE7PasswordInfo>* request =
+ new GenericRequest<IE7PasswordInfo>(this, GetNextRequestHandle(),
+ consumer, info);
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this, &WebDataService::GetIE7LoginImpl,
+ request));
+ return request->GetHandle();
+}
+
+WebDataService::Handle WebDataService::GetAllAutofillableLogins(
+ WebDataServiceConsumer* consumer) {
+ WebDataRequest* request =
+ new WebDataRequest(this, GetNextRequestHandle(), consumer);
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this,
+ &WebDataService::GetAllAutofillableLoginsImpl,
+ request));
+ return request->GetHandle();
+}
+
+WebDataService::Handle WebDataService::GetAllLogins(
+ WebDataServiceConsumer* consumer) {
+ WebDataRequest* request =
+ new WebDataRequest(this, GetNextRequestHandle(), consumer);
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this, &WebDataService::GetAllLoginsImpl,
+ request));
+ return request->GetHandle();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The following methods are executed in Chrome_WebDataThread.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void WebDataService::Commit() {
+ if (should_commit_) {
+ should_commit_ = false;
+
+ if (db_) {
+ db_->CommitTransaction();
+ db_->BeginTransaction();
+ }
+ }
+}
+
+void WebDataService::InitializeDatabase(const std::wstring& path) {
+ DCHECK(!db_);
+ // In the rare case where the db fails to initialize a dialog may get shown
+ // the 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();
+ if (!db->Init(path)) {
+ NOTREACHED() << "Cannot initialize the web database";
+ delete db;
+ return;
+ }
+
+ db_ = db;
+
+ db_->BeginTransaction();
+}
+
+void WebDataService::ShutdownDatabase() {
+ if (db_) {
+ db_->CommitTransaction();
+ delete db_;
+ db_ = NULL;
+ }
+}
+
+//
+// Keywords.
+//
+void WebDataService::AddKeywordImpl(GenericRequest<TemplateURL>* request) {
+ if (db_ && !request->IsCancelled()) {
+ db_->AddKeyword(request->GetArgument());
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::RemoveKeywordImpl(
+ GenericRequest<TemplateURL::IDType>* request) {
+ if (db_ && !request->IsCancelled()) {
+ DCHECK(request->GetArgument());
+ db_->RemoveKeyword(request->GetArgument());
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::UpdateKeywordImpl(
+ GenericRequest<TemplateURL>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (!db_->UpdateKeyword(request->GetArgument()))
+ NOTREACHED();
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::GetKeywordsImpl(WebDataRequest* request) {
+ if (db_ && !request->IsCancelled()) {
+ WDKeywordsResult result;
+ db_->GetKeywords(&result.keywords);
+ result.default_search_provider_id = db_->GetDefaulSearchProviderID();
+ result.builtin_keyword_version = db_->GetBuitinKeywordVersion();
+ request->SetResult(
+ new WDResult<WDKeywordsResult>(KEYWORDS_RESULT, result));
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::SetDefaultSearchProviderImpl(
+ GenericRequest<TemplateURL::IDType>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (!db_->SetDefaultSearchProviderID(request->GetArgument()))
+ NOTREACHED();
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::SetBuiltinKeywordVersionImpl(
+ GenericRequest<int>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (!db_->SetBuitinKeywordVersion(request->GetArgument()))
+ NOTREACHED();
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+//
+// Password manager support.
+//
+void WebDataService::AddLoginImpl(GenericRequest<PasswordForm>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (db_->AddLogin(request->GetArgument()))
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::AddIE7LoginImpl(GenericRequest<IE7PasswordInfo>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (db_->AddIE7Login(request->GetArgument()))
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::UpdateLoginImpl(GenericRequest<PasswordForm>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (db_->UpdateLogin(request->GetArgument()))
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::RemoveLoginImpl(GenericRequest<PasswordForm>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (db_->RemoveLogin(request->GetArgument()))
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::RemoveIE7LoginImpl(
+ GenericRequest<IE7PasswordInfo>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (db_->RemoveIE7Login(request->GetArgument()))
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::RemoveLoginsCreatedBetweenImpl(
+ GenericRequest2<Time, Time>* request) {
+ if (db_ && !request->IsCancelled()) {
+ if (db_->RemoveLoginsCreatedBetween(request->GetArgument1(),
+ request->GetArgument2()))
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::GetLoginsImpl(GenericRequest<PasswordForm>* request) {
+ if (db_ && !request->IsCancelled()) {
+ std::vector<PasswordForm*> forms;
+ db_->GetLogins(request->GetArgument(), &forms);
+ request->SetResult(
+ new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::GetIE7LoginImpl(
+ GenericRequest<IE7PasswordInfo>* request) {
+ if (db_ && !request->IsCancelled()) {
+ IE7PasswordInfo result;
+ db_->GetIE7Login(request->GetArgument(), &result);
+ request->SetResult(
+ new WDResult<IE7PasswordInfo>(PASSWORD_IE7_RESULT, result));
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::GetAllAutofillableLoginsImpl(WebDataRequest* request) {
+ if (db_ && !request->IsCancelled()) {
+ std::vector<PasswordForm*> forms;
+ db_->GetAllLogins(&forms, false);
+ request->SetResult(
+ new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::GetAllLoginsImpl(WebDataRequest* request) {
+ if (db_ && !request->IsCancelled()) {
+ std::vector<PasswordForm*> forms;
+ db_->GetAllLogins(&forms, true);
+ request->SetResult(
+ new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
+ }
+ request->RequestComplete();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Web Apps implementation.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void WebDataService::SetWebAppImageImpl(
+ GenericRequest2<GURL, SkBitmap>* request) {
+ if (db_ && !request->IsCancelled()) {
+ db_->SetWebAppImage(request->GetArgument1(), request->GetArgument2());
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::SetWebAppHasAllImagesImpl(
+ GenericRequest2<GURL, bool>* request) {
+ if (db_ && !request->IsCancelled()) {
+ db_->SetWebAppHasAllImages(request->GetArgument1(),
+ request->GetArgument2());
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::RemoveWebAppImpl(GenericRequest<GURL>* request) {
+ if (db_ && !request->IsCancelled()) {
+ db_->RemoveWebApp(request->GetArgument());
+ ScheduleCommit();
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::GetWebAppImagesImpl(GenericRequest<GURL>* request) {
+ if (db_ && !request->IsCancelled()) {
+ WDAppImagesResult result;
+ result.has_all_images = db_->GetWebAppHasAllImages(request->GetArgument());
+ db_->GetWebAppImages(request->GetArgument(), &result.images);
+ request->SetResult(
+ new WDResult<WDAppImagesResult>(WEB_APP_IMAGES, result));
+ }
+ 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);
+}
+
+int WebDataService::GetNextRequestHandle() {
+ AutoLock l(pending_lock_);
+ return ++next_request_handle_;
+}