Chromium Code Reviews| Index: content/browser/service_worker/service_worker_storage.cc |
| diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6206ef226386ef3d1421ab5ba66abecd52c58eb1 |
| --- /dev/null |
| +++ b/content/browser/service_worker/service_worker_storage.cc |
| @@ -0,0 +1,192 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/service_worker/service_worker_storage.h" |
| + |
| +#include <string> |
| + |
| +#include "base/strings/string_util.h" |
| +#include "content/browser/service_worker/service_worker_register_job.h" |
| +#include "content/browser/service_worker/service_worker_registration.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "webkit/browser/quota/quota_manager.h" |
| + |
| +namespace content { |
| + |
| +const base::FilePath::CharType kServiceWorkerDirectory[] = |
| + FILE_PATH_LITERAL("ServiceWorker"); |
| + |
| +ServiceWorkerStorage::ServiceWorkerStorage( |
| + const base::FilePath& path, |
| + quota::QuotaManagerProxy* quota_manager_proxy) |
| + : quota_manager_proxy_(quota_manager_proxy), weak_factory_(this) { |
| + if (!path.empty()) |
| + path_ = path.Append(kServiceWorkerDirectory); |
| +} |
| + |
| +ServiceWorkerStorage::~ServiceWorkerStorage() {} |
| + |
| +void ServiceWorkerStorage::Shutdown() { |
| + for (PatternToRegistrationMap::const_iterator iter = |
| + registration_by_pattern_.begin(); |
| + iter != registration_by_pattern_.end(); |
| + ++iter) { |
| + iter->second->Shutdown(); |
| + } |
| + registration_by_pattern_.clear(); |
| +} |
| + |
| +void ServiceWorkerStorage::FindRegistrationForPattern( |
| + const GURL& pattern, |
| + const ResponseCallback& 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. |
|
kinuko
2013/11/25 08:17:10
I think it's ok to always call back asynchronously
alecflett
2013/11/26 23:20:00
I completely agree. Its mainly that this is in the
|
| + PatternToRegistrationMap::const_iterator match = |
| + registration_by_pattern_.find(pattern); |
| + if (match == registration_by_pattern_.end()) { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind( |
| + callback, |
| + static_cast<scoped_refptr<ServiceWorkerRegistration> >(NULL))); |
| + return; |
| + } |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, match->second)); |
| +} |
| + |
| +void ServiceWorkerStorage::FindRegistrationForDocument( |
| + const GURL& document_url, |
| + const ResponseCallback& 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. |
| + for (PatternToRegistrationMap::const_iterator it = |
| + registration_by_pattern_.begin(); |
| + it != registration_by_pattern_.end(); |
| + ++it) { |
| + if (PatternMatches(it->first, document_url)) { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(callback, |
| + static_cast<scoped_refptr<ServiceWorkerRegistration> >( |
| + it->second))); |
| + return; |
| + } |
| + } |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(callback, |
| + static_cast<scoped_refptr<ServiceWorkerRegistration> >(NULL))); |
| +} |
| + |
| +namespace { |
| +int64 NextRegistrationId() { |
| + static int64 worker_id = 0; |
| + return worker_id++; |
|
kinuko
2013/11/25 08:17:10
While we're working on in-memory version this coul
alecflett
2013/11/26 23:20:00
I'm not sure of the value of that? This local func
|
| +} |
| +} // namespace |
| + |
| +void ServiceWorkerStorage::Register(const GURL& pattern, |
| + const GURL& script_url, |
| + const ResponseCallback& callback) { |
| + scoped_ptr<ServiceWorkerRegisterJob> job = |
| + make_scoped_ptr(new ServiceWorkerRegisterJob( |
| + weak_factory_.GetWeakPtr(), |
| + base::Bind(&ServiceWorkerStorage::RegisterComplete, |
| + weak_factory_.GetWeakPtr(), |
| + callback))); |
| + job->StartRegister(pattern, script_url); |
| + registration_jobs_.push_back(job.release()); |
| +} |
| + |
| +scoped_refptr<ServiceWorkerRegistration> ServiceWorkerStorage::RegisterInternal( |
| + const GURL& pattern, |
| + const GURL& script_url) { |
| + |
| + PatternToRegistrationMap::const_iterator current( |
| + registration_by_pattern_.find(pattern)); |
| + DCHECK(current == registration_by_pattern_.end() || |
| + current->second->script_url() == script_url); |
| + |
| + if (current == registration_by_pattern_.end()) { |
| + scoped_refptr<ServiceWorkerRegistration> registration( |
| + new ServiceWorkerRegistration( |
| + pattern, script_url, NextRegistrationId())); |
| + // TODO(alecflett): version upgrade path. |
| + registration_by_pattern_[pattern] = registration; |
| + return registration; |
| + } |
| + |
| + return current->second; |
| +} |
| + |
| +void ServiceWorkerStorage::EraseJob(ServiceWorkerRegisterJob* job) { |
| + ScopedVector<ServiceWorkerRegisterJob>::iterator job_position = |
| + registration_jobs_.begin(); |
| + for (; job_position != registration_jobs_.end(); ++job_position) { |
| + if (*job_position == job) { |
| + registration_jobs_.erase(job_position); |
| + break; |
| + } |
| + } |
| + DCHECK(job_position != registration_jobs_.end()) |
| + << "Deleting non-existent job."; |
| +} |
| + |
| +void ServiceWorkerStorage::UnregisterComplete( |
| + const base::Closure& callback, |
| + ServiceWorkerRegisterJob* job, |
| + ServiceWorkerRegistration* previous_registration) { |
| + EraseJob(job); |
| + callback.Run(); |
| +} |
| + |
| +void ServiceWorkerStorage::RegisterComplete( |
| + const ResponseCallback& callback, |
| + ServiceWorkerRegisterJob* job, |
| + ServiceWorkerRegistration* registration) { |
| + EraseJob(job); |
| + callback.Run(registration); |
| +} |
| + |
| +void ServiceWorkerStorage::Unregister(const GURL& pattern, |
| + const base::Closure& callback) { |
| + scoped_ptr<ServiceWorkerRegisterJob> job = |
| + make_scoped_ptr(new ServiceWorkerRegisterJob( |
| + weak_factory_.GetWeakPtr(), |
| + base::Bind(&ServiceWorkerStorage::UnregisterComplete, |
| + weak_factory_.GetWeakPtr(), |
| + callback))); |
| + job->StartUnregister(pattern); |
| + registration_jobs_.push_back(job.release()); |
| +} |
| + |
| +void ServiceWorkerStorage::UnregisterInternal(const GURL& pattern) { |
| + PatternToRegistrationMap::const_iterator match = |
| + registration_by_pattern_.find(pattern); |
| + if (match != registration_by_pattern_.end()) { |
| + match->second->Shutdown(); |
| + registration_by_pattern_.erase(match); |
| + } |
| +} |
| + |
| +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); |
| +} |
| + |
| +} // namespace content |