Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_storage.cc
index 5be0fbb..1a3dd36 100644 (file)
 #include "content/browser/service_worker/service_worker_storage.h"
 
 #include <string>
+
+#include "base/bind_helpers.h"
 #include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_runner_util.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_disk_cache.h"
 #include "content/browser/service_worker/service_worker_info.h"
 #include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/base/net_errors.h"
 #include "webkit/browser/quota/quota_manager_proxy.h"
 
 namespace content {
 
 namespace {
 
-void RunSoon(const base::Closure& closure) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, closure);
+typedef base::Callback<void(
+    ServiceWorkerStorage::InitialData* data,
+    bool success)> InitializeCallback;
+typedef base::Callback<void(
+    const ServiceWorkerDatabase::RegistrationData& data,
+    const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources,
+    ServiceWorkerStatusCode status)> ReadRegistrationCallback;
+typedef base::Callback<void(
+    bool origin_is_deletable,
+    ServiceWorkerStatusCode status)> DeleteRegistrationCallback;
+
+void RunSoon(const tracked_objects::Location& from_here,
+             const base::Closure& closure) {
+  base::MessageLoop::current()->PostTask(from_here, closure);
+}
+
+void CompleteFindNow(
+    const scoped_refptr<ServiceWorkerRegistration>& registration,
+    ServiceWorkerStatusCode status,
+    const ServiceWorkerStorage::FindRegistrationCallback& callback) {
+  callback.Run(status, registration);
+}
+
+void CompleteFindSoon(
+    const tracked_objects::Location& from_here,
+    const scoped_refptr<ServiceWorkerRegistration>& registration,
+    ServiceWorkerStatusCode status,
+    const ServiceWorkerStorage::FindRegistrationCallback& callback) {
+  RunSoon(from_here, base::Bind(callback, status, registration));
 }
 
 const base::FilePath::CharType kServiceWorkerDirectory[] =
-    FILE_PATH_LITERAL("ServiceWorker");
+    FILE_PATH_LITERAL("Service Worker");
+const base::FilePath::CharType kDatabaseName[] =
+    FILE_PATH_LITERAL("Database");
+
+const int kMaxMemDiskCacheSize = 10 * 1024 * 1024;
+
+void EmptyCompletionCallback(int) {}
+
+void ReadInitialDataFromDB(
+    ServiceWorkerDatabase* database,
+    scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+    const InitializeCallback& callback) {
+  DCHECK(database);
+  ServiceWorkerStorage::InitialData* data =
+      new ServiceWorkerStorage::InitialData();
+  bool success =
+      database->GetNextAvailableIds(&data->next_registration_id,
+                                    &data->next_version_id,
+                                    &data->next_resource_id) &&
+      database->GetOriginsWithRegistrations(&data->origins);
+  original_task_runner->PostTask(
+      FROM_HERE, base::Bind(callback, base::Owned(data), success));
+}
+
+void ReadRegistrationFromDB(
+    ServiceWorkerDatabase* database,
+    scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+    int64 registration_id,
+    const GURL& origin,
+    const ReadRegistrationCallback& callback) {
+  DCHECK(database);
+  ServiceWorkerDatabase::RegistrationData data;
+  std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+
+  // TODO(nhiroki): The database should return more detailed status like
+  // ServiceWorkerStatusCode instead of bool value.
+  ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
+  if (!database->ReadRegistration(registration_id, origin, &data, &resources)) {
+    status = database->is_disabled() ? SERVICE_WORKER_ERROR_FAILED
+                                     : SERVICE_WORKER_ERROR_NOT_FOUND;
+  }
+  original_task_runner->PostTask(
+      FROM_HERE, base::Bind(callback, data, resources, status));
+}
+
+void DeleteRegistrationFromDB(
+    ServiceWorkerDatabase* database,
+    scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+    int64 registration_id,
+    const GURL& origin,
+    const DeleteRegistrationCallback& callback) {
+  DCHECK(database);
+  if (!database->DeleteRegistration(registration_id, origin)) {
+    original_task_runner->PostTask(
+        FROM_HERE, base::Bind(callback, false, SERVICE_WORKER_ERROR_FAILED));
+    return;
+  }
+
+  // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
+  // unique origin list.
+  std::vector<ServiceWorkerDatabase::RegistrationData> registrations;
+  if (!database->GetRegistrationsForOrigin(origin, &registrations)) {
+    original_task_runner->PostTask(
+        FROM_HERE, base::Bind(callback, false, SERVICE_WORKER_ERROR_FAILED));
+    return;
+  }
+
+  bool deletable = registrations.empty();
+  original_task_runner->PostTask(
+      FROM_HERE, base::Bind(callback, deletable, SERVICE_WORKER_OK));
+}
+
+void UpdateToActiveStateInDB(
+    ServiceWorkerDatabase* database,
+    scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+    int64 registration_id,
+    const GURL& origin,
+    const ServiceWorkerStorage::StatusCallback& callback) {
+  DCHECK(database);
+
+  // TODO(nhiroki): The database should return more detailed status like
+  // ServiceWorkerStatusCode instead of bool value.
+  ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
+  if (!database->UpdateVersionToActive(registration_id, origin)) {
+    status = database->is_disabled() ? SERVICE_WORKER_ERROR_FAILED
+                                     : SERVICE_WORKER_ERROR_NOT_FOUND;
+  }
+  original_task_runner->PostTask(FROM_HERE, base::Bind(callback, status));
+}
 
 }  // namespace
 
+ServiceWorkerStorage::InitialData::InitialData()
+    : next_registration_id(kInvalidServiceWorkerRegistrationId),
+      next_version_id(kInvalidServiceWorkerVersionId),
+      next_resource_id(kInvalidServiceWorkerResourceId) {
+}
+
+ServiceWorkerStorage::InitialData::~InitialData() {
+}
+
 ServiceWorkerStorage::ServiceWorkerStorage(
     const base::FilePath& path,
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    base::SequencedTaskRunner* database_task_runner,
     quota::QuotaManagerProxy* quota_manager_proxy)
-    : last_registration_id_(0),  // TODO(kinuko): this should be read from disk.
-      last_version_id_(0),       // TODO(kinuko): this should be read from disk.
-      quota_manager_proxy_(quota_manager_proxy) {
-  if (!path.empty())
+    : next_registration_id_(kInvalidServiceWorkerRegistrationId),
+      next_version_id_(kInvalidServiceWorkerVersionId),
+      next_resource_id_(kInvalidServiceWorkerResourceId),
+      state_(UNINITIALIZED),
+      context_(context),
+      database_task_runner_(database_task_runner),
+      quota_manager_proxy_(quota_manager_proxy),
+      weak_factory_(this) {
+  if (!path.empty()) {
     path_ = path.Append(kServiceWorkerDirectory);
+    database_.reset(new ServiceWorkerDatabase(path_.Append(kDatabaseName)));
+  } else {
+    // Create an in-memory database.
+    database_.reset(new ServiceWorkerDatabase(base::FilePath()));
+  }
 }
 
 ServiceWorkerStorage::~ServiceWorkerStorage() {
-  for (PatternToRegistrationMap::const_iterator iter =
-           registration_by_pattern_.begin();
-       iter != registration_by_pattern_.end();
-       ++iter) {
-    iter->second->Shutdown();
-  }
-  registration_by_pattern_.clear();
+  weak_factory_.InvalidateWeakPtrs();
+  database_task_runner_->DeleteSoon(FROM_HERE, database_.release());
 }
 
 void ServiceWorkerStorage::FindRegistrationForPattern(
-    const GURL& pattern,
+    const GURL& scope,
     const FindRegistrationCallback& callback) {
-  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NOT_FOUND;
-  scoped_refptr<ServiceWorkerRegistration> found;
-  PatternToRegistrationMap::const_iterator match =
-      registration_by_pattern_.find(pattern);
-  if (match != registration_by_pattern_.end()) {
-    status = SERVICE_WORKER_OK;
-    found = match->second;
+  scoped_refptr<ServiceWorkerRegistration> null_registration;
+  if (!LazyInitialize(base::Bind(
+          &ServiceWorkerStorage::FindRegistrationForPattern,
+          weak_factory_.GetWeakPtr(), scope, callback))) {
+    if (state_ != INITIALIZING || !context_) {
+      CompleteFindSoon(FROM_HERE, null_registration,
+                       SERVICE_WORKER_ERROR_FAILED, callback);
+    }
+    return;
+  }
+  DCHECK_EQ(INITIALIZED, state_);
+
+  // See if there are any stored registrations for the origin.
+  if (!ContainsKey(registered_origins_, scope.GetOrigin())) {
+    // Look for something currently being installed.
+    scoped_refptr<ServiceWorkerRegistration> installing_registration =
+        FindInstallingRegistrationForPattern(scope);
+    if (installing_registration) {
+      CompleteFindSoon(
+          FROM_HERE, installing_registration, SERVICE_WORKER_OK, callback);
+      return;
+    }
+    CompleteFindSoon(
+        FROM_HERE, null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
+    return;
   }
-  // Always simulate asynchronous call for now.
-  RunSoon(base::Bind(callback, status, found));
+
+  RegistrationList* registrations = new RegistrationList();
+  PostTaskAndReplyWithResult(
+      database_task_runner_,
+      FROM_HERE,
+      base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin,
+                 base::Unretained(database_.get()),
+                 scope.GetOrigin(), base::Unretained(registrations)),
+      base::Bind(&ServiceWorkerStorage::DidGetRegistrationsForPattern,
+                 weak_factory_.GetWeakPtr(), scope, callback,
+                 base::Owned(registrations)));
 }
 
 void ServiceWorkerStorage::FindRegistrationForDocument(
     const GURL& document_url,
     const FindRegistrationCallback& callback) {
-  // TODO(alecflett): This needs to be synchronous in the fast path,
-  // but asynchronous in the slow path (when the patterns have to be
-  // loaded from disk). For now it is always pessimistically async.
-  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NOT_FOUND;
-  scoped_refptr<ServiceWorkerRegistration> found;
-  for (PatternToRegistrationMap::const_iterator it =
-           registration_by_pattern_.begin();
-       it != registration_by_pattern_.end();
-       ++it) {
-    if (PatternMatches(it->first, document_url)) {
-      status = SERVICE_WORKER_OK;
-      found = it->second;
-      break;
-    }
+  scoped_refptr<ServiceWorkerRegistration> null_registration;
+  if (!LazyInitialize(base::Bind(
+          &ServiceWorkerStorage::FindRegistrationForDocument,
+          weak_factory_.GetWeakPtr(), document_url, callback))) {
+    if (state_ != INITIALIZING || !context_)
+      CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
+    return;
   }
-  // Always simulate asynchronous call for now.
-  RunSoon(base::Bind(callback, status, found));
-}
+  DCHECK_EQ(INITIALIZED, state_);
 
-void ServiceWorkerStorage::GetAllRegistrations(
-    const GetAllRegistrationInfosCallback& callback) {
-  std::vector<ServiceWorkerRegistrationInfo> registrations;
-  for (PatternToRegistrationMap::const_iterator it =
-           registration_by_pattern_.begin();
-       it != registration_by_pattern_.end();
-       ++it) {
-    ServiceWorkerRegistration* registration(it->second.get());
-    registrations.push_back(registration->GetInfo());
+  // See if there are any stored registrations for the origin.
+  if (!ContainsKey(registered_origins_, document_url.GetOrigin())) {
+    // Look for something currently being installed.
+    scoped_refptr<ServiceWorkerRegistration> installing_registration =
+        FindInstallingRegistrationForDocument(document_url);
+    if (installing_registration) {
+      CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback);
+      return;
+    }
+    CompleteFindNow(
+        null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
+    return;
   }
 
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE, base::Bind(callback, registrations));
+  RegistrationList* registrations = new RegistrationList();
+  PostTaskAndReplyWithResult(
+      database_task_runner_,
+      FROM_HERE,
+      base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin,
+                 base::Unretained(database_.get()),
+                 document_url.GetOrigin(), base::Unretained(registrations)),
+      base::Bind(&ServiceWorkerStorage::DidGetRegistrationsForDocument,
+                 weak_factory_.GetWeakPtr(), document_url, callback,
+                 base::Owned(registrations)));
 }
 
 void ServiceWorkerStorage::FindRegistrationForId(
     int64 registration_id,
+    const GURL& origin,
     const FindRegistrationCallback& callback) {
-  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NOT_FOUND;
-  scoped_refptr<ServiceWorkerRegistration> found;
-  for (PatternToRegistrationMap::const_iterator it =
-           registration_by_pattern_.begin();
-       it != registration_by_pattern_.end();
-       ++it) {
-    if (registration_id == it->second->id()) {
-      status = SERVICE_WORKER_OK;
-      found = it->second;
-      break;
+  scoped_refptr<ServiceWorkerRegistration> null_registration;
+  if (!LazyInitialize(base::Bind(
+          &ServiceWorkerStorage::FindRegistrationForId,
+          weak_factory_.GetWeakPtr(), registration_id, origin, callback))) {
+    if (state_ != INITIALIZING || !context_)
+      CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
+    return;
+  }
+  DCHECK_EQ(INITIALIZED, state_);
+
+  // See if there are any stored registrations for the origin.
+  if (!ContainsKey(registered_origins_, origin)) {
+    // Look for somthing currently being installed.
+    scoped_refptr<ServiceWorkerRegistration> installing_registration =
+        FindInstallingRegistrationForId(registration_id);
+    if (installing_registration) {
+      CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback);
+      return;
     }
+    CompleteFindNow(
+        null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
+    return;
   }
-  RunSoon(base::Bind(callback, status, found));
+
+  scoped_refptr<ServiceWorkerRegistration> registration =
+      context_->GetLiveRegistration(registration_id);
+  if (registration) {
+    CompleteFindNow(registration, SERVICE_WORKER_OK, callback);
+    return;
+  }
+
+  database_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&ReadRegistrationFromDB,
+                 database_.get(),
+                 base::MessageLoopProxy::current(),
+                 registration_id, origin,
+                 base::Bind(&ServiceWorkerStorage::DidReadRegistrationForId,
+                            weak_factory_.GetWeakPtr(), callback)));
+}
+
+void ServiceWorkerStorage::GetAllRegistrations(
+    const GetAllRegistrationInfosCallback& callback) {
+  if (!LazyInitialize(base::Bind(
+          &ServiceWorkerStorage::GetAllRegistrations,
+          weak_factory_.GetWeakPtr(), callback))) {
+    if (state_ != INITIALIZING || !context_) {
+      RunSoon(FROM_HERE, base::Bind(
+          callback, std::vector<ServiceWorkerRegistrationInfo>()));
+    }
+    return;
+  }
+  DCHECK_EQ(INITIALIZED, state_);
+
+  RegistrationList* registrations = new RegistrationList;
+  PostTaskAndReplyWithResult(
+      database_task_runner_,
+      FROM_HERE,
+      base::Bind(&ServiceWorkerDatabase::GetAllRegistrations,
+                 base::Unretained(database_.get()),
+                 base::Unretained(registrations)),
+      base::Bind(&ServiceWorkerStorage::DidGetAllRegistrations,
+                 weak_factory_.GetWeakPtr(),
+                 callback,
+                 base::Owned(registrations)));
 }
 
 void ServiceWorkerStorage::StoreRegistration(
     ServiceWorkerRegistration* registration,
+    ServiceWorkerVersion* version,
     const StatusCallback& callback) {
   DCHECK(registration);
+  DCHECK(version);
 
-  PatternToRegistrationMap::const_iterator current(
-      registration_by_pattern_.find(registration->pattern()));
-  if (current != registration_by_pattern_.end() &&
-      current->second->script_url() != registration->script_url()) {
-    RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_EXISTS));
+  DCHECK(state_ == INITIALIZED || state_ == DISABLED);
+  if (state_ != INITIALIZED || !context_) {
+    RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
     return;
   }
 
-  // This may update the existing registration information.
-  registration_by_pattern_[registration->pattern()] = registration;
+  ServiceWorkerDatabase::RegistrationData data;
+  data.registration_id = registration->id();
+  data.scope = registration->pattern();
+  data.script = registration->script_url();
+  data.has_fetch_handler = true;
+  data.version_id = version->version_id();
+  data.last_update_check = base::Time::Now();
+  data.is_active = false;  // initially stored in the waiting state
+
+  ResourceList resources;
+  PostTaskAndReplyWithResult(
+      database_task_runner_,
+      FROM_HERE,
+      base::Bind(&ServiceWorkerDatabase::WriteRegistration,
+                 base::Unretained(database_.get()), data, resources),
+      base::Bind(&ServiceWorkerStorage::DidStoreRegistration,
+                 weak_factory_.GetWeakPtr(),
+                 registration->script_url().GetOrigin(),
+                 callback));
+}
+
+void ServiceWorkerStorage::UpdateToActiveState(
+    ServiceWorkerRegistration* registration,
+    const StatusCallback& callback) {
+  DCHECK(registration);
+
+  DCHECK(state_ == INITIALIZED || state_ == DISABLED);
+  if (state_ != INITIALIZED || !context_) {
+    RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+    return;
+  }
 
-  RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
+  database_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&UpdateToActiveStateInDB,
+                 database_.get(),
+                 base::MessageLoopProxy::current(),
+                 registration->id(),
+                 registration->script_url().GetOrigin(),
+                 callback));
 }
 
 void ServiceWorkerStorage::DeleteRegistration(
-    const GURL& pattern,
+    int64 registration_id,
+    const GURL& origin,
     const StatusCallback& callback) {
-  PatternToRegistrationMap::iterator match =
-      registration_by_pattern_.find(pattern);
-  if (match == registration_by_pattern_.end()) {
-    RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_NOT_FOUND));
+  DCHECK(state_ == INITIALIZED || state_ == DISABLED);
+  if (state_ != INITIALIZED || !context_) {
+    RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
     return;
   }
-  registration_by_pattern_.erase(match);
-  RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
+
+  database_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&DeleteRegistrationFromDB,
+                 database_.get(),
+                 base::MessageLoopProxy::current(),
+                 registration_id, origin,
+                 base::Bind(&ServiceWorkerStorage::DidDeleteRegistration,
+                            weak_factory_.GetWeakPtr(), origin, callback)));
+
+  // TODO(michaeln): Either its instance should also be
+  // removed from liveregistrations map or the live object
+  // should marked as deleted in some way and not 'findable'
+  // thereafter.
+}
+
+scoped_ptr<ServiceWorkerResponseReader>
+ServiceWorkerStorage::CreateResponseReader(int64 response_id) {
+  return make_scoped_ptr(
+      new ServiceWorkerResponseReader(response_id, disk_cache()));
+}
+
+scoped_ptr<ServiceWorkerResponseWriter>
+ServiceWorkerStorage::CreateResponseWriter(int64 response_id) {
+  return make_scoped_ptr(
+      new ServiceWorkerResponseWriter(response_id, disk_cache()));
 }
 
 int64 ServiceWorkerStorage::NewRegistrationId() {
-  return ++last_registration_id_;
+  if (state_ == DISABLED)
+    return kInvalidServiceWorkerRegistrationId;
+  DCHECK_EQ(INITIALIZED, state_);
+  return next_registration_id_++;
 }
 
 int64 ServiceWorkerStorage::NewVersionId() {
-  return ++last_version_id_;
-}
-
-bool ServiceWorkerStorage::PatternMatches(const GURL& pattern,
-                                          const GURL& url) {
-  // This is a really basic, naive
-  // TODO(alecflett): Formalize what pattern matches mean.
-  // Temporarily borrowed directly from appcache::Namespace::IsMatch().
-  // We have to escape '?' characters since MatchPattern also treats those
-  // as wildcards which we don't want here, we only do '*'s.
-  std::string pattern_spec(pattern.spec());
-  if (pattern.has_query())
-    ReplaceSubstringsAfterOffset(&pattern_spec, 0, "?", "\\?");
-  return MatchPattern(url.spec(), pattern_spec);
+  if (state_ == DISABLED)
+    return kInvalidServiceWorkerVersionId;
+  DCHECK_EQ(INITIALIZED, state_);
+  return next_version_id_++;
+}
+
+int64 ServiceWorkerStorage::NewResourceId() {
+  if (state_ == DISABLED)
+    return kInvalidServiceWorkerResourceId;
+  DCHECK_EQ(INITIALIZED, state_);
+  return next_resource_id_++;
+}
+
+void ServiceWorkerStorage::NotifyInstallingRegistration(
+      ServiceWorkerRegistration* registration) {
+  installing_registrations_[registration->id()] = registration;
+}
+
+void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
+      ServiceWorkerRegistration* registration) {
+  installing_registrations_.erase(registration->id());
+}
+
+bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) {
+  if (!context_)
+    return false;
+
+  switch (state_) {
+    case INITIALIZED:
+      return true;
+    case DISABLED:
+      return false;
+    case INITIALIZING:
+      pending_tasks_.push_back(callback);
+      return false;
+    case UNINITIALIZED:
+      pending_tasks_.push_back(callback);
+      // Fall-through.
+  }
+
+  state_ = INITIALIZING;
+  database_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&ReadInitialDataFromDB,
+                 database_.get(),
+                 base::MessageLoopProxy::current(),
+                 base::Bind(&ServiceWorkerStorage::DidReadInitialData,
+                            weak_factory_.GetWeakPtr())));
+  return false;
+}
+
+void ServiceWorkerStorage::DidReadInitialData(
+    InitialData* data,
+    bool success) {
+  DCHECK(data);
+  DCHECK_EQ(INITIALIZING, state_);
+
+  if (success) {
+    next_registration_id_ = data->next_registration_id;
+    next_version_id_ = data->next_version_id;
+    next_resource_id_ = data->next_resource_id;
+    registered_origins_.swap(data->origins);
+    state_ = INITIALIZED;
+  } else {
+    DLOG(WARNING) << "Failed to initialize.";
+    state_ = DISABLED;
+  }
+
+  for (std::vector<base::Closure>::const_iterator it = pending_tasks_.begin();
+       it != pending_tasks_.end(); ++it) {
+    RunSoon(FROM_HERE, *it);
+  }
+  pending_tasks_.clear();
+}
+
+void ServiceWorkerStorage::DidGetRegistrationsForPattern(
+    const GURL& scope,
+    const FindRegistrationCallback& callback,
+    RegistrationList* registrations,
+    bool success) {
+  DCHECK(registrations);
+  if (!success) {
+    callback.Run(SERVICE_WORKER_ERROR_FAILED,
+                 scoped_refptr<ServiceWorkerRegistration>());
+    return;
+  }
+
+  // Find one with a matching scope.
+  for (RegistrationList::const_iterator it = registrations->begin();
+       it != registrations->end(); ++it) {
+    if (scope == it->scope) {
+      scoped_refptr<ServiceWorkerRegistration> registration =
+          context_->GetLiveRegistration(it->registration_id);
+      if (!registration)
+        registration = CreateRegistration(*it);
+      callback.Run(SERVICE_WORKER_OK, registration);
+      return;
+    }
+  }
+
+  // Look for something currently being installed.
+  scoped_refptr<ServiceWorkerRegistration> installing_registration =
+      FindInstallingRegistrationForPattern(scope);
+  if (installing_registration) {
+    callback.Run(SERVICE_WORKER_OK, installing_registration);
+    return;
+  }
+
+  callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND,
+               scoped_refptr<ServiceWorkerRegistration>());
+}
+
+void ServiceWorkerStorage::DidGetRegistrationsForDocument(
+    const GURL& document_url,
+    const FindRegistrationCallback& callback,
+    RegistrationList* registrations,
+    bool success) {
+  DCHECK(registrations);
+  if (!success) {
+    callback.Run(SERVICE_WORKER_ERROR_FAILED,
+                 scoped_refptr<ServiceWorkerRegistration>());
+    return;
+  }
+
+  // Find one with a pattern match.
+  for (RegistrationList::const_iterator it = registrations->begin();
+       it != registrations->end(); ++it) {
+    // TODO(michaeln): if there are multiple matches the one with
+    // the longest scope should win.
+    if (ServiceWorkerUtils::ScopeMatches(it->scope, document_url)) {
+      scoped_refptr<ServiceWorkerRegistration> registration =
+          context_->GetLiveRegistration(it->registration_id);
+      if (registration) {
+        callback.Run(SERVICE_WORKER_OK, registration);
+        return;
+      }
+      callback.Run(SERVICE_WORKER_OK, CreateRegistration(*it));
+      return;
+    }
+  }
+
+  // Look for something currently being installed.
+  // TODO(michaeln): Should be mixed in with the stored registrations
+  // for this test.
+  scoped_refptr<ServiceWorkerRegistration> installing_registration =
+      FindInstallingRegistrationForDocument(document_url);
+  if (installing_registration) {
+    callback.Run(SERVICE_WORKER_OK, installing_registration);
+    return;
+  }
+
+  callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND,
+               scoped_refptr<ServiceWorkerRegistration>());
+}
+
+void ServiceWorkerStorage::DidReadRegistrationForId(
+    const FindRegistrationCallback& callback,
+    const ServiceWorkerDatabase::RegistrationData& registration,
+    const ResourceList& resources,
+    ServiceWorkerStatusCode status) {
+  if (status == SERVICE_WORKER_OK) {
+    callback.Run(status, CreateRegistration(registration));
+    return;
+  }
+
+  if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+    // Look for somthing currently being installed.
+    scoped_refptr<ServiceWorkerRegistration> installing_registration =
+        FindInstallingRegistrationForId(registration.registration_id);
+    if (installing_registration) {
+      callback.Run(SERVICE_WORKER_OK, installing_registration);
+      return;
+    }
+    callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND,
+                 scoped_refptr<ServiceWorkerRegistration>());
+    return;
+  }
+
+  callback.Run(status, scoped_refptr<ServiceWorkerRegistration>());
+  return;
+}
+
+void ServiceWorkerStorage::DidGetAllRegistrations(
+    const GetAllRegistrationInfosCallback& callback,
+    RegistrationList* registrations,
+    bool success) {
+  DCHECK(registrations);
+  if (!success) {
+    callback.Run(std::vector<ServiceWorkerRegistrationInfo>());
+    return;
+  }
+
+  // Add all stored registrations.
+  std::set<int64> pushed_registrations;
+  std::vector<ServiceWorkerRegistrationInfo> infos;
+  for (RegistrationList::const_iterator it = registrations->begin();
+       it != registrations->end(); ++it) {
+    DCHECK(pushed_registrations.insert(it->registration_id).second);
+    ServiceWorkerRegistration* registration =
+        context_->GetLiveRegistration(it->registration_id);
+    if (registration) {
+      infos.push_back(registration->GetInfo());
+      continue;
+    }
+    ServiceWorkerRegistrationInfo info;
+    info.pattern = it->scope;
+    info.script_url = it->script;
+    info.active_version.is_null = false;
+    if (it->is_active)
+      info.active_version.status = ServiceWorkerVersion::ACTIVE;
+    else
+      info.active_version.status = ServiceWorkerVersion::INSTALLED;
+    info.active_version.version_id = it->version_id;
+    infos.push_back(info);
+  }
+
+  // Add unstored registrations that are being installed.
+  for (RegistrationRefsById::const_iterator it =
+           installing_registrations_.begin();
+       it != installing_registrations_.end(); ++it) {
+    if (pushed_registrations.insert(it->first).second)
+      infos.push_back(it->second->GetInfo());
+  }
+
+  callback.Run(infos);
+}
+
+void ServiceWorkerStorage::DidStoreRegistration(
+    const GURL& origin,
+    const StatusCallback& callback,
+    bool success) {
+  if (!success) {
+    callback.Run(SERVICE_WORKER_ERROR_FAILED);
+    return;
+  }
+  registered_origins_.insert(origin);
+  callback.Run(SERVICE_WORKER_OK);
+}
+
+void ServiceWorkerStorage::DidDeleteRegistration(
+    const GURL& origin,
+    const StatusCallback& callback,
+    bool origin_is_deletable,
+    ServiceWorkerStatusCode status) {
+  if (origin_is_deletable)
+    registered_origins_.erase(origin);
+  callback.Run(status);
+}
+
+scoped_refptr<ServiceWorkerRegistration>
+ServiceWorkerStorage::CreateRegistration(
+    const ServiceWorkerDatabase::RegistrationData& data) {
+  scoped_refptr<ServiceWorkerRegistration> registration(
+      new ServiceWorkerRegistration(
+          data.scope, data.script, data.registration_id, context_));
+
+  scoped_refptr<ServiceWorkerVersion> version =
+      context_->GetLiveVersion(data.version_id);
+  if (!version) {
+    version = new ServiceWorkerVersion(registration, data.version_id, context_);
+    version->SetStatus(data.GetVersionStatus());
+  }
+
+  if (version->status() == ServiceWorkerVersion::ACTIVE)
+    registration->set_active_version(version);
+  else if (version->status() == ServiceWorkerVersion::INSTALLED)
+    registration->set_pending_version(version);
+  else
+    NOTREACHED();
+  // TODO(michaeln): Hmmm, what if DeleteReg was invoked after
+  // the Find result we're returning here? NOTREACHED condition?
+
+  return registration;
+}
+
+ServiceWorkerRegistration*
+ServiceWorkerStorage::FindInstallingRegistrationForDocument(
+    const GURL& document_url) {
+  // TODO(michaeln): if there are multiple matches the one with
+  // the longest scope should win, and these should on equal footing
+  // with the stored registrations in FindRegistrationForDocument().
+  for (RegistrationRefsById::const_iterator it =
+           installing_registrations_.begin();
+       it != installing_registrations_.end(); ++it) {
+    if (ServiceWorkerUtils::ScopeMatches(
+            it->second->pattern(), document_url)) {
+      return it->second;
+    }
+  }
+  return NULL;
+}
+
+ServiceWorkerRegistration*
+ServiceWorkerStorage::FindInstallingRegistrationForPattern(
+    const GURL& scope) {
+  for (RegistrationRefsById::const_iterator it =
+           installing_registrations_.begin();
+       it != installing_registrations_.end(); ++it) {
+    if (it->second->pattern() == scope)
+      return it->second;
+  }
+  return NULL;
+}
+
+ServiceWorkerRegistration*
+ServiceWorkerStorage::FindInstallingRegistrationForId(
+    int64 registration_id) {
+  RegistrationRefsById::const_iterator found =
+      installing_registrations_.find(registration_id);
+  if (found == installing_registrations_.end())
+    return NULL;
+  return found->second;
+}
+
+ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() {
+  if (disk_cache_)
+    return disk_cache_.get();
+
+  // TODO(michaeln): Store data on disk and do error checking.
+  disk_cache_.reset(new ServiceWorkerDiskCache);
+  int rv = disk_cache_->InitWithMemBackend(
+      kMaxMemDiskCacheSize,
+      base::Bind(&EmptyCompletionCallback));
+  DCHECK_EQ(net::OK, rv);
+  return disk_cache_.get();
 }
 
 }  // namespace content