Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_storage.cc
blob07addb2875ae83c18795a26fc546ef4c968aaa87
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/service_worker/service_worker_storage.h"
7 #include <string>
9 #include "base/message_loop/message_loop.h"
10 #include "base/sequenced_task_runner.h"
11 #include "content/browser/service_worker/service_worker_context_core.h"
12 #include "content/browser/service_worker/service_worker_disk_cache.h"
13 #include "content/browser/service_worker/service_worker_info.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_utils.h"
16 #include "content/browser/service_worker/service_worker_version.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/base/net_errors.h"
19 #include "webkit/browser/quota/quota_manager_proxy.h"
21 namespace content {
23 namespace {
25 void RunSoon(const tracked_objects::Location& from_here,
26 const base::Closure& closure) {
27 base::MessageLoop::current()->PostTask(from_here, closure);
30 void CompleteFindNow(
31 const scoped_refptr<ServiceWorkerRegistration>& registration,
32 ServiceWorkerStatusCode status,
33 const ServiceWorkerStorage::FindRegistrationCallback& callback) {
34 callback.Run(status, registration);
37 void CompleteFindSoon(
38 const tracked_objects::Location& from_here,
39 const scoped_refptr<ServiceWorkerRegistration>& registration,
40 ServiceWorkerStatusCode status,
41 const ServiceWorkerStorage::FindRegistrationCallback& callback) {
42 RunSoon(from_here, base::Bind(callback, status, registration));
45 const base::FilePath::CharType kServiceWorkerDirectory[] =
46 FILE_PATH_LITERAL("ServiceWorker");
49 const int kMaxMemDiskCacheSize = 10 * 1024 * 1024;
51 void EmptyCompletionCallback(int) {}
53 } // namespace
55 ServiceWorkerStorage::ServiceWorkerStorage(
56 const base::FilePath& path,
57 base::WeakPtr<ServiceWorkerContextCore> context,
58 base::SequencedTaskRunner* database_task_runner,
59 quota::QuotaManagerProxy* quota_manager_proxy)
60 : last_registration_id_(0),
61 last_version_id_(0),
62 last_resource_id_(0),
63 simulated_lazy_initted_(false),
64 context_(context),
65 database_task_runner_(database_task_runner),
66 quota_manager_proxy_(quota_manager_proxy) {
67 if (!path.empty())
68 path_ = path.Append(kServiceWorkerDirectory);
71 ServiceWorkerStorage::~ServiceWorkerStorage() {
74 void ServiceWorkerStorage::FindRegistrationForPattern(
75 const GURL& scope,
76 const FindRegistrationCallback& callback) {
77 simulated_lazy_initted_ = true;
78 scoped_refptr<ServiceWorkerRegistration> null_registration;
79 if (!context_) {
80 CompleteFindSoon(
81 FROM_HERE, null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
82 return;
85 scoped_refptr<ServiceWorkerRegistration> installing_registration =
86 FindInstallingRegistrationForPattern(scope);
87 if (installing_registration) {
88 CompleteFindSoon(
89 FROM_HERE, installing_registration, SERVICE_WORKER_OK, callback);
90 return;
93 // See if there are any registrations for the origin.
94 OriginRegistrationsMap::const_iterator
95 found = stored_registrations_.find(scope.GetOrigin());
96 if (found == stored_registrations_.end()) {
97 CompleteFindSoon(
98 FROM_HERE, null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
99 return;
102 // Find one with a matching scope.
103 for (RegistrationsMap::const_iterator it = found->second.begin();
104 it != found->second.end(); ++it) {
105 if (scope == it->second.scope) {
106 const ServiceWorkerDatabase::RegistrationData* data = &(it->second);
107 scoped_refptr<ServiceWorkerRegistration> registration =
108 context_->GetLiveRegistration(data->registration_id);
109 if (registration) {
110 CompleteFindSoon(FROM_HERE, registration, SERVICE_WORKER_OK, callback);
111 return;
114 registration = CreateRegistration(data);
115 CompleteFindSoon(FROM_HERE, registration, SERVICE_WORKER_OK, callback);
116 return;
120 CompleteFindSoon(
121 FROM_HERE, null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
124 void ServiceWorkerStorage::FindRegistrationForDocument(
125 const GURL& document_url,
126 const FindRegistrationCallback& callback) {
127 simulated_lazy_initted_ = true;
128 scoped_refptr<ServiceWorkerRegistration> null_registration;
129 if (!context_) {
130 CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
131 return;
134 // See if there are any registrations for the origin.
135 OriginRegistrationsMap::const_iterator
136 found = stored_registrations_.find(document_url.GetOrigin());
137 if (found == stored_registrations_.end()) {
138 // Look for something currently being installed.
139 scoped_refptr<ServiceWorkerRegistration> installing_registration =
140 FindInstallingRegistrationForDocument(document_url);
141 if (installing_registration) {
142 CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback);
143 return;
146 // Return syncly to simulate this class having an in memory map of
147 // origins with registrations.
148 CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_NOT_FOUND,
149 callback);
150 return;
153 // Find one with a pattern match.
154 for (RegistrationsMap::const_iterator it = found->second.begin();
155 it != found->second.end(); ++it) {
156 // TODO(michaeln): if there are multiple matches the one with
157 // the longest scope should win.
158 if (ServiceWorkerUtils::ScopeMatches(it->second.scope, document_url)) {
159 const ServiceWorkerDatabase::RegistrationData* data = &(it->second);
161 // If its in the live map, return syncly to simulate this class having
162 // iterated over the values in that map instead of reading the db.
163 scoped_refptr<ServiceWorkerRegistration> registration =
164 context_->GetLiveRegistration(data->registration_id);
165 if (registration) {
166 CompleteFindNow(registration, SERVICE_WORKER_OK, callback);
167 return;
170 // If we have to create a new instance, return it asyncly to simulate
171 // having had to retreive the RegistrationData from the db.
172 registration = CreateRegistration(data);
173 CompleteFindSoon(FROM_HERE, registration, SERVICE_WORKER_OK, callback);
174 return;
178 // Look for something currently being installed.
179 // TODO(michaeln): Should be mixed in with the stored registrations
180 // for this test.
181 scoped_refptr<ServiceWorkerRegistration> installing_registration =
182 FindInstallingRegistrationForDocument(document_url);
183 if (installing_registration) {
184 CompleteFindSoon(
185 FROM_HERE, installing_registration, SERVICE_WORKER_OK, callback);
186 return;
189 // Return asyncly to simulate having had to look in the db since this
190 // origin does have some registations.
191 CompleteFindSoon(
192 FROM_HERE, null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
195 void ServiceWorkerStorage::FindRegistrationForId(
196 int64 registration_id,
197 const FindRegistrationCallback& callback) {
198 simulated_lazy_initted_ = true;
199 scoped_refptr<ServiceWorkerRegistration> null_registration;
200 if (!context_) {
201 CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
202 return;
204 scoped_refptr<ServiceWorkerRegistration> installing_registration =
205 FindInstallingRegistrationForId(registration_id);
206 if (installing_registration) {
207 CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback);
208 return;
210 RegistrationPtrMap::const_iterator found =
211 registrations_by_id_.find(registration_id);
212 if (found == registrations_by_id_.end()) {
213 CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_NOT_FOUND,
214 callback);
215 return;
217 scoped_refptr<ServiceWorkerRegistration> registration =
218 context_->GetLiveRegistration(registration_id);
219 if (registration) {
220 CompleteFindNow(registration, SERVICE_WORKER_OK, callback);
221 return;
223 registration = CreateRegistration(found->second);
224 CompleteFindSoon(FROM_HERE, registration, SERVICE_WORKER_OK, callback);
227 void ServiceWorkerStorage::GetAllRegistrations(
228 const GetAllRegistrationInfosCallback& callback) {
229 simulated_lazy_initted_ = true;
230 std::vector<ServiceWorkerRegistrationInfo> registrations;
231 if (!context_) {
232 RunSoon(FROM_HERE, base::Bind(callback, registrations));
233 return;
236 // Add all stored registrations.
237 for (RegistrationPtrMap::const_iterator it = registrations_by_id_.begin();
238 it != registrations_by_id_.end(); ++it) {
239 ServiceWorkerRegistration* registration =
240 context_->GetLiveRegistration(it->first);
241 if (registration) {
242 registrations.push_back(registration->GetInfo());
243 continue;
245 ServiceWorkerRegistrationInfo info;
246 info.pattern = it->second->scope;
247 info.script_url = it->second->script;
248 info.active_version.is_null = false;
249 if (it->second->is_active)
250 info.active_version.status = ServiceWorkerVersion::ACTIVE;
251 else
252 info.active_version.status = ServiceWorkerVersion::INSTALLED;
253 registrations.push_back(info);
256 // Add unstored registrations that are being installed.
257 for (RegistrationRefsById::const_iterator it =
258 installing_registrations_.begin();
259 it != installing_registrations_.end(); ++it) {
260 if (registrations_by_id_.find(it->first) == registrations_by_id_.end())
261 registrations.push_back(it->second->GetInfo());
264 RunSoon(FROM_HERE, base::Bind(callback, registrations));
267 void ServiceWorkerStorage::StoreRegistration(
268 ServiceWorkerRegistration* registration,
269 ServiceWorkerVersion* version,
270 const StatusCallback& callback) {
271 DCHECK(registration);
272 DCHECK(version);
273 DCHECK(simulated_lazy_initted_);
274 if (!context_) {
275 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
276 return;
279 // Keep a database struct in the storage map.
280 RegistrationsMap& storage_map =
281 stored_registrations_[registration->script_url().GetOrigin()];
282 ServiceWorkerDatabase::RegistrationData& data =
283 storage_map[registration->id()];
284 data.registration_id = registration->id();
285 data.scope = registration->pattern();
286 data.script = registration->script_url();
287 data.has_fetch_handler = true;
288 data.version_id = version->version_id();
289 data.last_update_check = base::Time::Now();
290 data.is_active = false; // initially stored in the waiting state
292 // Keep a seperate map of ptrs keyed by id only.
293 registrations_by_id_[registration->id()] = &storage_map[registration->id()];
295 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_OK));
298 void ServiceWorkerStorage::UpdateToActiveState(
299 ServiceWorkerRegistration* registration,
300 const StatusCallback& callback) {
301 DCHECK(simulated_lazy_initted_);
302 if (!context_) {
303 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
304 return;
307 RegistrationPtrMap::const_iterator
308 found = registrations_by_id_.find(registration->id());
309 if (found == registrations_by_id_.end()) {
310 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_NOT_FOUND));
311 return;
313 DCHECK(!found->second->is_active);
314 found->second->is_active = true;
315 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_OK));
318 void ServiceWorkerStorage::DeleteRegistration(
319 int64 registration_id,
320 const StatusCallback& callback) {
321 DCHECK(simulated_lazy_initted_);
322 RegistrationPtrMap::iterator
323 found = registrations_by_id_.find(registration_id);
324 if (found == registrations_by_id_.end()) {
325 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_NOT_FOUND));
326 return;
329 GURL origin = found->second->script.GetOrigin();
330 stored_registrations_[origin].erase(registration_id);
331 if (stored_registrations_[origin].empty())
332 stored_registrations_.erase(origin);
334 registrations_by_id_.erase(found);
336 RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_OK));
337 // TODO(michaeln): Either its instance should also be
338 // removed from liveregistrations map or the live object
339 // should marked as deleted in some way and not 'findable'
340 // thereafter.
343 scoped_ptr<ServiceWorkerResponseReader>
344 ServiceWorkerStorage::CreateResponseReader(int64 response_id) {
345 return make_scoped_ptr(
346 new ServiceWorkerResponseReader(response_id, disk_cache()));
349 scoped_ptr<ServiceWorkerResponseWriter>
350 ServiceWorkerStorage::CreateResponseWriter(int64 response_id) {
351 return make_scoped_ptr(
352 new ServiceWorkerResponseWriter(response_id, disk_cache()));
355 int64 ServiceWorkerStorage::NewRegistrationId() {
356 DCHECK(simulated_lazy_initted_);
357 return ++last_registration_id_;
360 int64 ServiceWorkerStorage::NewVersionId() {
361 DCHECK(simulated_lazy_initted_);
362 return ++last_version_id_;
365 int64 ServiceWorkerStorage::NewResourceId() {
366 DCHECK(simulated_lazy_initted_);
367 return ++last_resource_id_;
370 void ServiceWorkerStorage::NotifyInstallingRegistration(
371 ServiceWorkerRegistration* registration) {
372 installing_registrations_[registration->id()] = registration;
375 void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
376 ServiceWorkerRegistration* registration) {
377 installing_registrations_.erase(registration->id());
380 scoped_refptr<ServiceWorkerRegistration>
381 ServiceWorkerStorage::CreateRegistration(
382 const ServiceWorkerDatabase::RegistrationData* data) {
383 scoped_refptr<ServiceWorkerRegistration> registration(
384 new ServiceWorkerRegistration(
385 data->scope, data->script, data->registration_id, context_));
387 scoped_refptr<ServiceWorkerVersion> version =
388 context_->GetLiveVersion(data->version_id);
389 if (!version) {
390 version = new ServiceWorkerVersion(
391 registration, data->version_id, context_);
392 version->SetStatus(data->GetVersionStatus());
395 if (version->status() == ServiceWorkerVersion::ACTIVE)
396 registration->set_active_version(version);
397 else if (version->status() == ServiceWorkerVersion::INSTALLED)
398 registration->set_pending_version(version);
399 else
400 NOTREACHED();
401 // TODO(michaeln): Hmmm, what if DeleteReg was invoked after
402 // the Find result we're returning here? NOTREACHED condition?
404 return registration;
407 ServiceWorkerRegistration*
408 ServiceWorkerStorage::FindInstallingRegistrationForDocument(
409 const GURL& document_url) {
410 // TODO(michaeln): if there are multiple matches the one with
411 // the longest scope should win, and these should on equal footing
412 // with the stored registrations in FindRegistrationForDocument().
413 for (RegistrationRefsById::const_iterator it =
414 installing_registrations_.begin();
415 it != installing_registrations_.end(); ++it) {
416 if (ServiceWorkerUtils::ScopeMatches(
417 it->second->pattern(), document_url)) {
418 return it->second;
421 return NULL;
424 ServiceWorkerRegistration*
425 ServiceWorkerStorage::FindInstallingRegistrationForPattern(
426 const GURL& scope) {
427 for (RegistrationRefsById::const_iterator it =
428 installing_registrations_.begin();
429 it != installing_registrations_.end(); ++it) {
430 if (it->second->pattern() == scope)
431 return it->second;
433 return NULL;
436 ServiceWorkerRegistration*
437 ServiceWorkerStorage::FindInstallingRegistrationForId(
438 int64 registration_id) {
439 RegistrationRefsById::const_iterator found =
440 installing_registrations_.find(registration_id);
441 if (found == installing_registrations_.end())
442 return NULL;
443 return found->second;
446 ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() {
447 if (disk_cache_)
448 return disk_cache_.get();
450 // TODO(michaeln): Store data on disk and do error checking.
451 disk_cache_.reset(new ServiceWorkerDiskCache);
452 int rv = disk_cache_->InitWithMemBackend(
453 kMaxMemDiskCacheSize,
454 base::Bind(&EmptyCompletionCallback));
455 DCHECK_EQ(net::OK, rv);
456 return disk_cache_.get();
459 } // namespace content