Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_storage.cc
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.
4
5 #include "content/browser/service_worker/service_worker_storage.h"
6
7 #include <string>
8
9 #include "base/bind_helpers.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/task_runner_util.h"
13 #include "content/browser/service_worker/service_worker_context_core.h"
14 #include "content/browser/service_worker/service_worker_disk_cache.h"
15 #include "content/browser/service_worker/service_worker_info.h"
16 #include "content/browser/service_worker/service_worker_registration.h"
17 #include "content/browser/service_worker/service_worker_utils.h"
18 #include "content/browser/service_worker/service_worker_version.h"
19 #include "content/common/service_worker/service_worker_types.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "net/base/net_errors.h"
22 #include "webkit/browser/quota/quota_manager_proxy.h"
23
24 namespace content {
25
26 namespace {
27
28 typedef base::Callback<void(
29     ServiceWorkerStorage::InitialData* data,
30     bool success)> InitializeCallback;
31 typedef base::Callback<void(
32     const ServiceWorkerDatabase::RegistrationData& data,
33     const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources,
34     ServiceWorkerStatusCode status)> ReadRegistrationCallback;
35 typedef base::Callback<void(
36     bool origin_is_deletable,
37     ServiceWorkerStatusCode status)> DeleteRegistrationCallback;
38
39 void RunSoon(const tracked_objects::Location& from_here,
40              const base::Closure& closure) {
41   base::MessageLoop::current()->PostTask(from_here, closure);
42 }
43
44 void CompleteFindNow(
45     const scoped_refptr<ServiceWorkerRegistration>& registration,
46     ServiceWorkerStatusCode status,
47     const ServiceWorkerStorage::FindRegistrationCallback& callback) {
48   callback.Run(status, registration);
49 }
50
51 void CompleteFindSoon(
52     const tracked_objects::Location& from_here,
53     const scoped_refptr<ServiceWorkerRegistration>& registration,
54     ServiceWorkerStatusCode status,
55     const ServiceWorkerStorage::FindRegistrationCallback& callback) {
56   RunSoon(from_here, base::Bind(callback, status, registration));
57 }
58
59 const base::FilePath::CharType kServiceWorkerDirectory[] =
60     FILE_PATH_LITERAL("Service Worker");
61 const base::FilePath::CharType kDatabaseName[] =
62     FILE_PATH_LITERAL("Database");
63
64 const int kMaxMemDiskCacheSize = 10 * 1024 * 1024;
65
66 void EmptyCompletionCallback(int) {}
67
68 void ReadInitialDataFromDB(
69     ServiceWorkerDatabase* database,
70     scoped_refptr<base::SequencedTaskRunner> original_task_runner,
71     const InitializeCallback& callback) {
72   DCHECK(database);
73   ServiceWorkerStorage::InitialData* data =
74       new ServiceWorkerStorage::InitialData();
75   bool success =
76       database->GetNextAvailableIds(&data->next_registration_id,
77                                     &data->next_version_id,
78                                     &data->next_resource_id) &&
79       database->GetOriginsWithRegistrations(&data->origins);
80   original_task_runner->PostTask(
81       FROM_HERE, base::Bind(callback, base::Owned(data), success));
82 }
83
84 void ReadRegistrationFromDB(
85     ServiceWorkerDatabase* database,
86     scoped_refptr<base::SequencedTaskRunner> original_task_runner,
87     int64 registration_id,
88     const GURL& origin,
89     const ReadRegistrationCallback& callback) {
90   DCHECK(database);
91   ServiceWorkerDatabase::RegistrationData data;
92   std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
93
94   // TODO(nhiroki): The database should return more detailed status like
95   // ServiceWorkerStatusCode instead of bool value.
96   ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
97   if (!database->ReadRegistration(registration_id, origin, &data, &resources)) {
98     status = database->is_disabled() ? SERVICE_WORKER_ERROR_FAILED
99                                      : SERVICE_WORKER_ERROR_NOT_FOUND;
100   }
101   original_task_runner->PostTask(
102       FROM_HERE, base::Bind(callback, data, resources, status));
103 }
104
105 void DeleteRegistrationFromDB(
106     ServiceWorkerDatabase* database,
107     scoped_refptr<base::SequencedTaskRunner> original_task_runner,
108     int64 registration_id,
109     const GURL& origin,
110     const DeleteRegistrationCallback& callback) {
111   DCHECK(database);
112   if (!database->DeleteRegistration(registration_id, origin)) {
113     original_task_runner->PostTask(
114         FROM_HERE, base::Bind(callback, false, SERVICE_WORKER_ERROR_FAILED));
115     return;
116   }
117
118   // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
119   // unique origin list.
120   std::vector<ServiceWorkerDatabase::RegistrationData> registrations;
121   if (!database->GetRegistrationsForOrigin(origin, &registrations)) {
122     original_task_runner->PostTask(
123         FROM_HERE, base::Bind(callback, false, SERVICE_WORKER_ERROR_FAILED));
124     return;
125   }
126
127   bool deletable = registrations.empty();
128   original_task_runner->PostTask(
129       FROM_HERE, base::Bind(callback, deletable, SERVICE_WORKER_OK));
130 }
131
132 void UpdateToActiveStateInDB(
133     ServiceWorkerDatabase* database,
134     scoped_refptr<base::SequencedTaskRunner> original_task_runner,
135     int64 registration_id,
136     const GURL& origin,
137     const ServiceWorkerStorage::StatusCallback& callback) {
138   DCHECK(database);
139
140   // TODO(nhiroki): The database should return more detailed status like
141   // ServiceWorkerStatusCode instead of bool value.
142   ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
143   if (!database->UpdateVersionToActive(registration_id, origin)) {
144     status = database->is_disabled() ? SERVICE_WORKER_ERROR_FAILED
145                                      : SERVICE_WORKER_ERROR_NOT_FOUND;
146   }
147   original_task_runner->PostTask(FROM_HERE, base::Bind(callback, status));
148 }
149
150 }  // namespace
151
152 ServiceWorkerStorage::InitialData::InitialData()
153     : next_registration_id(kInvalidServiceWorkerRegistrationId),
154       next_version_id(kInvalidServiceWorkerVersionId),
155       next_resource_id(kInvalidServiceWorkerResourceId) {
156 }
157
158 ServiceWorkerStorage::InitialData::~InitialData() {
159 }
160
161 ServiceWorkerStorage::ServiceWorkerStorage(
162     const base::FilePath& path,
163     base::WeakPtr<ServiceWorkerContextCore> context,
164     base::SequencedTaskRunner* database_task_runner,
165     quota::QuotaManagerProxy* quota_manager_proxy)
166     : next_registration_id_(kInvalidServiceWorkerRegistrationId),
167       next_version_id_(kInvalidServiceWorkerVersionId),
168       next_resource_id_(kInvalidServiceWorkerResourceId),
169       state_(UNINITIALIZED),
170       context_(context),
171       database_task_runner_(database_task_runner),
172       quota_manager_proxy_(quota_manager_proxy),
173       weak_factory_(this) {
174   if (!path.empty()) {
175     path_ = path.Append(kServiceWorkerDirectory);
176     database_.reset(new ServiceWorkerDatabase(path_.Append(kDatabaseName)));
177   } else {
178     // Create an in-memory database.
179     database_.reset(new ServiceWorkerDatabase(base::FilePath()));
180   }
181 }
182
183 ServiceWorkerStorage::~ServiceWorkerStorage() {
184   weak_factory_.InvalidateWeakPtrs();
185   database_task_runner_->DeleteSoon(FROM_HERE, database_.release());
186 }
187
188 void ServiceWorkerStorage::FindRegistrationForPattern(
189     const GURL& scope,
190     const FindRegistrationCallback& callback) {
191   scoped_refptr<ServiceWorkerRegistration> null_registration;
192   if (!LazyInitialize(base::Bind(
193           &ServiceWorkerStorage::FindRegistrationForPattern,
194           weak_factory_.GetWeakPtr(), scope, callback))) {
195     if (state_ != INITIALIZING || !context_) {
196       CompleteFindSoon(FROM_HERE, null_registration,
197                        SERVICE_WORKER_ERROR_FAILED, callback);
198     }
199     return;
200   }
201   DCHECK_EQ(INITIALIZED, state_);
202
203   // See if there are any stored registrations for the origin.
204   if (!ContainsKey(registered_origins_, scope.GetOrigin())) {
205     // Look for something currently being installed.
206     scoped_refptr<ServiceWorkerRegistration> installing_registration =
207         FindInstallingRegistrationForPattern(scope);
208     if (installing_registration) {
209       CompleteFindSoon(
210           FROM_HERE, installing_registration, SERVICE_WORKER_OK, callback);
211       return;
212     }
213     CompleteFindSoon(
214         FROM_HERE, null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
215     return;
216   }
217
218   RegistrationList* registrations = new RegistrationList();
219   PostTaskAndReplyWithResult(
220       database_task_runner_,
221       FROM_HERE,
222       base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin,
223                  base::Unretained(database_.get()),
224                  scope.GetOrigin(), base::Unretained(registrations)),
225       base::Bind(&ServiceWorkerStorage::DidGetRegistrationsForPattern,
226                  weak_factory_.GetWeakPtr(), scope, callback,
227                  base::Owned(registrations)));
228 }
229
230 void ServiceWorkerStorage::FindRegistrationForDocument(
231     const GURL& document_url,
232     const FindRegistrationCallback& callback) {
233   scoped_refptr<ServiceWorkerRegistration> null_registration;
234   if (!LazyInitialize(base::Bind(
235           &ServiceWorkerStorage::FindRegistrationForDocument,
236           weak_factory_.GetWeakPtr(), document_url, callback))) {
237     if (state_ != INITIALIZING || !context_)
238       CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
239     return;
240   }
241   DCHECK_EQ(INITIALIZED, state_);
242
243   // See if there are any stored registrations for the origin.
244   if (!ContainsKey(registered_origins_, document_url.GetOrigin())) {
245     // Look for something currently being installed.
246     scoped_refptr<ServiceWorkerRegistration> installing_registration =
247         FindInstallingRegistrationForDocument(document_url);
248     if (installing_registration) {
249       CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback);
250       return;
251     }
252     CompleteFindNow(
253         null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
254     return;
255   }
256
257   RegistrationList* registrations = new RegistrationList();
258   PostTaskAndReplyWithResult(
259       database_task_runner_,
260       FROM_HERE,
261       base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin,
262                  base::Unretained(database_.get()),
263                  document_url.GetOrigin(), base::Unretained(registrations)),
264       base::Bind(&ServiceWorkerStorage::DidGetRegistrationsForDocument,
265                  weak_factory_.GetWeakPtr(), document_url, callback,
266                  base::Owned(registrations)));
267 }
268
269 void ServiceWorkerStorage::FindRegistrationForId(
270     int64 registration_id,
271     const GURL& origin,
272     const FindRegistrationCallback& callback) {
273   scoped_refptr<ServiceWorkerRegistration> null_registration;
274   if (!LazyInitialize(base::Bind(
275           &ServiceWorkerStorage::FindRegistrationForId,
276           weak_factory_.GetWeakPtr(), registration_id, origin, callback))) {
277     if (state_ != INITIALIZING || !context_)
278       CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
279     return;
280   }
281   DCHECK_EQ(INITIALIZED, state_);
282
283   // See if there are any stored registrations for the origin.
284   if (!ContainsKey(registered_origins_, origin)) {
285     // Look for somthing currently being installed.
286     scoped_refptr<ServiceWorkerRegistration> installing_registration =
287         FindInstallingRegistrationForId(registration_id);
288     if (installing_registration) {
289       CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback);
290       return;
291     }
292     CompleteFindNow(
293         null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback);
294     return;
295   }
296
297   scoped_refptr<ServiceWorkerRegistration> registration =
298       context_->GetLiveRegistration(registration_id);
299   if (registration) {
300     CompleteFindNow(registration, SERVICE_WORKER_OK, callback);
301     return;
302   }
303
304   database_task_runner_->PostTask(
305       FROM_HERE,
306       base::Bind(&ReadRegistrationFromDB,
307                  database_.get(),
308                  base::MessageLoopProxy::current(),
309                  registration_id, origin,
310                  base::Bind(&ServiceWorkerStorage::DidReadRegistrationForId,
311                             weak_factory_.GetWeakPtr(), callback)));
312 }
313
314 void ServiceWorkerStorage::GetAllRegistrations(
315     const GetAllRegistrationInfosCallback& callback) {
316   if (!LazyInitialize(base::Bind(
317           &ServiceWorkerStorage::GetAllRegistrations,
318           weak_factory_.GetWeakPtr(), callback))) {
319     if (state_ != INITIALIZING || !context_) {
320       RunSoon(FROM_HERE, base::Bind(
321           callback, std::vector<ServiceWorkerRegistrationInfo>()));
322     }
323     return;
324   }
325   DCHECK_EQ(INITIALIZED, state_);
326
327   RegistrationList* registrations = new RegistrationList;
328   PostTaskAndReplyWithResult(
329       database_task_runner_,
330       FROM_HERE,
331       base::Bind(&ServiceWorkerDatabase::GetAllRegistrations,
332                  base::Unretained(database_.get()),
333                  base::Unretained(registrations)),
334       base::Bind(&ServiceWorkerStorage::DidGetAllRegistrations,
335                  weak_factory_.GetWeakPtr(),
336                  callback,
337                  base::Owned(registrations)));
338 }
339
340 void ServiceWorkerStorage::StoreRegistration(
341     ServiceWorkerRegistration* registration,
342     ServiceWorkerVersion* version,
343     const StatusCallback& callback) {
344   DCHECK(registration);
345   DCHECK(version);
346
347   DCHECK(state_ == INITIALIZED || state_ == DISABLED);
348   if (state_ != INITIALIZED || !context_) {
349     RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
350     return;
351   }
352
353   ServiceWorkerDatabase::RegistrationData data;
354   data.registration_id = registration->id();
355   data.scope = registration->pattern();
356   data.script = registration->script_url();
357   data.has_fetch_handler = true;
358   data.version_id = version->version_id();
359   data.last_update_check = base::Time::Now();
360   data.is_active = false;  // initially stored in the waiting state
361
362   ResourceList resources;
363   PostTaskAndReplyWithResult(
364       database_task_runner_,
365       FROM_HERE,
366       base::Bind(&ServiceWorkerDatabase::WriteRegistration,
367                  base::Unretained(database_.get()), data, resources),
368       base::Bind(&ServiceWorkerStorage::DidStoreRegistration,
369                  weak_factory_.GetWeakPtr(),
370                  registration->script_url().GetOrigin(),
371                  callback));
372 }
373
374 void ServiceWorkerStorage::UpdateToActiveState(
375     ServiceWorkerRegistration* registration,
376     const StatusCallback& callback) {
377   DCHECK(registration);
378
379   DCHECK(state_ == INITIALIZED || state_ == DISABLED);
380   if (state_ != INITIALIZED || !context_) {
381     RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
382     return;
383   }
384
385   database_task_runner_->PostTask(
386       FROM_HERE,
387       base::Bind(&UpdateToActiveStateInDB,
388                  database_.get(),
389                  base::MessageLoopProxy::current(),
390                  registration->id(),
391                  registration->script_url().GetOrigin(),
392                  callback));
393 }
394
395 void ServiceWorkerStorage::DeleteRegistration(
396     int64 registration_id,
397     const GURL& origin,
398     const StatusCallback& callback) {
399   DCHECK(state_ == INITIALIZED || state_ == DISABLED);
400   if (state_ != INITIALIZED || !context_) {
401     RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
402     return;
403   }
404
405   database_task_runner_->PostTask(
406       FROM_HERE,
407       base::Bind(&DeleteRegistrationFromDB,
408                  database_.get(),
409                  base::MessageLoopProxy::current(),
410                  registration_id, origin,
411                  base::Bind(&ServiceWorkerStorage::DidDeleteRegistration,
412                             weak_factory_.GetWeakPtr(), origin, callback)));
413
414   // TODO(michaeln): Either its instance should also be
415   // removed from liveregistrations map or the live object
416   // should marked as deleted in some way and not 'findable'
417   // thereafter.
418 }
419
420 scoped_ptr<ServiceWorkerResponseReader>
421 ServiceWorkerStorage::CreateResponseReader(int64 response_id) {
422   return make_scoped_ptr(
423       new ServiceWorkerResponseReader(response_id, disk_cache()));
424 }
425
426 scoped_ptr<ServiceWorkerResponseWriter>
427 ServiceWorkerStorage::CreateResponseWriter(int64 response_id) {
428   return make_scoped_ptr(
429       new ServiceWorkerResponseWriter(response_id, disk_cache()));
430 }
431
432 int64 ServiceWorkerStorage::NewRegistrationId() {
433   if (state_ == DISABLED)
434     return kInvalidServiceWorkerRegistrationId;
435   DCHECK_EQ(INITIALIZED, state_);
436   return next_registration_id_++;
437 }
438
439 int64 ServiceWorkerStorage::NewVersionId() {
440   if (state_ == DISABLED)
441     return kInvalidServiceWorkerVersionId;
442   DCHECK_EQ(INITIALIZED, state_);
443   return next_version_id_++;
444 }
445
446 int64 ServiceWorkerStorage::NewResourceId() {
447   if (state_ == DISABLED)
448     return kInvalidServiceWorkerResourceId;
449   DCHECK_EQ(INITIALIZED, state_);
450   return next_resource_id_++;
451 }
452
453 void ServiceWorkerStorage::NotifyInstallingRegistration(
454       ServiceWorkerRegistration* registration) {
455   installing_registrations_[registration->id()] = registration;
456 }
457
458 void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
459       ServiceWorkerRegistration* registration) {
460   installing_registrations_.erase(registration->id());
461 }
462
463 bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) {
464   if (!context_)
465     return false;
466
467   switch (state_) {
468     case INITIALIZED:
469       return true;
470     case DISABLED:
471       return false;
472     case INITIALIZING:
473       pending_tasks_.push_back(callback);
474       return false;
475     case UNINITIALIZED:
476       pending_tasks_.push_back(callback);
477       // Fall-through.
478   }
479
480   state_ = INITIALIZING;
481   database_task_runner_->PostTask(
482       FROM_HERE,
483       base::Bind(&ReadInitialDataFromDB,
484                  database_.get(),
485                  base::MessageLoopProxy::current(),
486                  base::Bind(&ServiceWorkerStorage::DidReadInitialData,
487                             weak_factory_.GetWeakPtr())));
488   return false;
489 }
490
491 void ServiceWorkerStorage::DidReadInitialData(
492     InitialData* data,
493     bool success) {
494   DCHECK(data);
495   DCHECK_EQ(INITIALIZING, state_);
496
497   if (success) {
498     next_registration_id_ = data->next_registration_id;
499     next_version_id_ = data->next_version_id;
500     next_resource_id_ = data->next_resource_id;
501     registered_origins_.swap(data->origins);
502     state_ = INITIALIZED;
503   } else {
504     DLOG(WARNING) << "Failed to initialize.";
505     state_ = DISABLED;
506   }
507
508   for (std::vector<base::Closure>::const_iterator it = pending_tasks_.begin();
509        it != pending_tasks_.end(); ++it) {
510     RunSoon(FROM_HERE, *it);
511   }
512   pending_tasks_.clear();
513 }
514
515 void ServiceWorkerStorage::DidGetRegistrationsForPattern(
516     const GURL& scope,
517     const FindRegistrationCallback& callback,
518     RegistrationList* registrations,
519     bool success) {
520   DCHECK(registrations);
521   if (!success) {
522     callback.Run(SERVICE_WORKER_ERROR_FAILED,
523                  scoped_refptr<ServiceWorkerRegistration>());
524     return;
525   }
526
527   // Find one with a matching scope.
528   for (RegistrationList::const_iterator it = registrations->begin();
529        it != registrations->end(); ++it) {
530     if (scope == it->scope) {
531       scoped_refptr<ServiceWorkerRegistration> registration =
532           context_->GetLiveRegistration(it->registration_id);
533       if (!registration)
534         registration = CreateRegistration(*it);
535       callback.Run(SERVICE_WORKER_OK, registration);
536       return;
537     }
538   }
539
540   // Look for something currently being installed.
541   scoped_refptr<ServiceWorkerRegistration> installing_registration =
542       FindInstallingRegistrationForPattern(scope);
543   if (installing_registration) {
544     callback.Run(SERVICE_WORKER_OK, installing_registration);
545     return;
546   }
547
548   callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND,
549                scoped_refptr<ServiceWorkerRegistration>());
550 }
551
552 void ServiceWorkerStorage::DidGetRegistrationsForDocument(
553     const GURL& document_url,
554     const FindRegistrationCallback& callback,
555     RegistrationList* registrations,
556     bool success) {
557   DCHECK(registrations);
558   if (!success) {
559     callback.Run(SERVICE_WORKER_ERROR_FAILED,
560                  scoped_refptr<ServiceWorkerRegistration>());
561     return;
562   }
563
564   // Find one with a pattern match.
565   for (RegistrationList::const_iterator it = registrations->begin();
566        it != registrations->end(); ++it) {
567     // TODO(michaeln): if there are multiple matches the one with
568     // the longest scope should win.
569     if (ServiceWorkerUtils::ScopeMatches(it->scope, document_url)) {
570       scoped_refptr<ServiceWorkerRegistration> registration =
571           context_->GetLiveRegistration(it->registration_id);
572       if (registration) {
573         callback.Run(SERVICE_WORKER_OK, registration);
574         return;
575       }
576       callback.Run(SERVICE_WORKER_OK, CreateRegistration(*it));
577       return;
578     }
579   }
580
581   // Look for something currently being installed.
582   // TODO(michaeln): Should be mixed in with the stored registrations
583   // for this test.
584   scoped_refptr<ServiceWorkerRegistration> installing_registration =
585       FindInstallingRegistrationForDocument(document_url);
586   if (installing_registration) {
587     callback.Run(SERVICE_WORKER_OK, installing_registration);
588     return;
589   }
590
591   callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND,
592                scoped_refptr<ServiceWorkerRegistration>());
593 }
594
595 void ServiceWorkerStorage::DidReadRegistrationForId(
596     const FindRegistrationCallback& callback,
597     const ServiceWorkerDatabase::RegistrationData& registration,
598     const ResourceList& resources,
599     ServiceWorkerStatusCode status) {
600   if (status == SERVICE_WORKER_OK) {
601     callback.Run(status, CreateRegistration(registration));
602     return;
603   }
604
605   if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
606     // Look for somthing currently being installed.
607     scoped_refptr<ServiceWorkerRegistration> installing_registration =
608         FindInstallingRegistrationForId(registration.registration_id);
609     if (installing_registration) {
610       callback.Run(SERVICE_WORKER_OK, installing_registration);
611       return;
612     }
613     callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND,
614                  scoped_refptr<ServiceWorkerRegistration>());
615     return;
616   }
617
618   callback.Run(status, scoped_refptr<ServiceWorkerRegistration>());
619   return;
620 }
621
622 void ServiceWorkerStorage::DidGetAllRegistrations(
623     const GetAllRegistrationInfosCallback& callback,
624     RegistrationList* registrations,
625     bool success) {
626   DCHECK(registrations);
627   if (!success) {
628     callback.Run(std::vector<ServiceWorkerRegistrationInfo>());
629     return;
630   }
631
632   // Add all stored registrations.
633   std::set<int64> pushed_registrations;
634   std::vector<ServiceWorkerRegistrationInfo> infos;
635   for (RegistrationList::const_iterator it = registrations->begin();
636        it != registrations->end(); ++it) {
637     DCHECK(pushed_registrations.insert(it->registration_id).second);
638     ServiceWorkerRegistration* registration =
639         context_->GetLiveRegistration(it->registration_id);
640     if (registration) {
641       infos.push_back(registration->GetInfo());
642       continue;
643     }
644     ServiceWorkerRegistrationInfo info;
645     info.pattern = it->scope;
646     info.script_url = it->script;
647     info.active_version.is_null = false;
648     if (it->is_active)
649       info.active_version.status = ServiceWorkerVersion::ACTIVE;
650     else
651       info.active_version.status = ServiceWorkerVersion::INSTALLED;
652     info.active_version.version_id = it->version_id;
653     infos.push_back(info);
654   }
655
656   // Add unstored registrations that are being installed.
657   for (RegistrationRefsById::const_iterator it =
658            installing_registrations_.begin();
659        it != installing_registrations_.end(); ++it) {
660     if (pushed_registrations.insert(it->first).second)
661       infos.push_back(it->second->GetInfo());
662   }
663
664   callback.Run(infos);
665 }
666
667 void ServiceWorkerStorage::DidStoreRegistration(
668     const GURL& origin,
669     const StatusCallback& callback,
670     bool success) {
671   if (!success) {
672     callback.Run(SERVICE_WORKER_ERROR_FAILED);
673     return;
674   }
675   registered_origins_.insert(origin);
676   callback.Run(SERVICE_WORKER_OK);
677 }
678
679 void ServiceWorkerStorage::DidDeleteRegistration(
680     const GURL& origin,
681     const StatusCallback& callback,
682     bool origin_is_deletable,
683     ServiceWorkerStatusCode status) {
684   if (origin_is_deletable)
685     registered_origins_.erase(origin);
686   callback.Run(status);
687 }
688
689 scoped_refptr<ServiceWorkerRegistration>
690 ServiceWorkerStorage::CreateRegistration(
691     const ServiceWorkerDatabase::RegistrationData& data) {
692   scoped_refptr<ServiceWorkerRegistration> registration(
693       new ServiceWorkerRegistration(
694           data.scope, data.script, data.registration_id, context_));
695
696   scoped_refptr<ServiceWorkerVersion> version =
697       context_->GetLiveVersion(data.version_id);
698   if (!version) {
699     version = new ServiceWorkerVersion(registration, data.version_id, context_);
700     version->SetStatus(data.GetVersionStatus());
701   }
702
703   if (version->status() == ServiceWorkerVersion::ACTIVE)
704     registration->set_active_version(version);
705   else if (version->status() == ServiceWorkerVersion::INSTALLED)
706     registration->set_pending_version(version);
707   else
708     NOTREACHED();
709   // TODO(michaeln): Hmmm, what if DeleteReg was invoked after
710   // the Find result we're returning here? NOTREACHED condition?
711
712   return registration;
713 }
714
715 ServiceWorkerRegistration*
716 ServiceWorkerStorage::FindInstallingRegistrationForDocument(
717     const GURL& document_url) {
718   // TODO(michaeln): if there are multiple matches the one with
719   // the longest scope should win, and these should on equal footing
720   // with the stored registrations in FindRegistrationForDocument().
721   for (RegistrationRefsById::const_iterator it =
722            installing_registrations_.begin();
723        it != installing_registrations_.end(); ++it) {
724     if (ServiceWorkerUtils::ScopeMatches(
725             it->second->pattern(), document_url)) {
726       return it->second;
727     }
728   }
729   return NULL;
730 }
731
732 ServiceWorkerRegistration*
733 ServiceWorkerStorage::FindInstallingRegistrationForPattern(
734     const GURL& scope) {
735   for (RegistrationRefsById::const_iterator it =
736            installing_registrations_.begin();
737        it != installing_registrations_.end(); ++it) {
738     if (it->second->pattern() == scope)
739       return it->second;
740   }
741   return NULL;
742 }
743
744 ServiceWorkerRegistration*
745 ServiceWorkerStorage::FindInstallingRegistrationForId(
746     int64 registration_id) {
747   RegistrationRefsById::const_iterator found =
748       installing_registrations_.find(registration_id);
749   if (found == installing_registrations_.end())
750     return NULL;
751   return found->second;
752 }
753
754 ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() {
755   if (disk_cache_)
756     return disk_cache_.get();
757
758   // TODO(michaeln): Store data on disk and do error checking.
759   disk_cache_.reset(new ServiceWorkerDiskCache);
760   int rv = disk_cache_->InitWithMemBackend(
761       kMaxMemDiskCacheSize,
762       base::Bind(&EmptyCompletionCallback));
763   DCHECK_EQ(net::OK, rv);
764   return disk_cache_.get();
765 }
766
767 }  // namespace content