Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_cache.cc
1 // Copyright 2014 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_cache.h"
6
7 #include <string>
8
9 #include "base/files/file_path.h"
10 #include "base/guid.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/strings/string_util.h"
13 #include "content/browser/service_worker/service_worker_cache.pb.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/disk_cache/disk_cache.h"
18 #include "net/url_request/url_request_context.h"
19 #include "storage/browser/blob/blob_data_handle.h"
20 #include "storage/browser/blob/blob_storage_context.h"
21 #include "storage/browser/blob/blob_url_request_job_factory.h"
22 #include "storage/browser/quota/quota_manager_proxy.h"
23 #include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
24
25 namespace content {
26
27 namespace {
28
29 typedef scoped_ptr<disk_cache::Backend> ScopedBackendPtr;
30 typedef base::Callback<void(bool)> BoolCallback;
31 typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
32     EntryBoolCallback;
33 typedef base::Callback<void(scoped_ptr<ServiceWorkerCacheMetadata>)>
34     MetadataCallback;
35
36 enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
37
38 // The maximum size of an individual cache. Ultimately cache size is controlled
39 // per-origin.
40 const int kMaxCacheBytes = 512 * 1024 * 1024;
41
42 // Buffer size for cache and blob reading/writing.
43 const int kBufferSize = 1024 * 512;
44
45 void NotReachedCompletionCallback(int rv) {
46   NOTREACHED();
47 }
48
49 blink::WebServiceWorkerResponseType ProtoResponseTypeToWebResponseType(
50     ServiceWorkerCacheResponse::ResponseType response_type) {
51   switch (response_type) {
52     case ServiceWorkerCacheResponse::BASIC_TYPE:
53       return blink::WebServiceWorkerResponseTypeBasic;
54     case ServiceWorkerCacheResponse::CORS_TYPE:
55       return blink::WebServiceWorkerResponseTypeCORS;
56     case ServiceWorkerCacheResponse::DEFAULT_TYPE:
57       return blink::WebServiceWorkerResponseTypeDefault;
58     case ServiceWorkerCacheResponse::ERROR_TYPE:
59       return blink::WebServiceWorkerResponseTypeError;
60     case ServiceWorkerCacheResponse::OPAQUE_TYPE:
61       return blink::WebServiceWorkerResponseTypeOpaque;
62   }
63   NOTREACHED();
64   return blink::WebServiceWorkerResponseTypeOpaque;
65 }
66
67 ServiceWorkerCacheResponse::ResponseType WebResponseTypeToProtoResponseType(
68     blink::WebServiceWorkerResponseType response_type) {
69   switch (response_type) {
70     case blink::WebServiceWorkerResponseTypeBasic:
71       return ServiceWorkerCacheResponse::BASIC_TYPE;
72     case blink::WebServiceWorkerResponseTypeCORS:
73       return ServiceWorkerCacheResponse::CORS_TYPE;
74     case blink::WebServiceWorkerResponseTypeDefault:
75       return ServiceWorkerCacheResponse::DEFAULT_TYPE;
76     case blink::WebServiceWorkerResponseTypeError:
77       return ServiceWorkerCacheResponse::ERROR_TYPE;
78     case blink::WebServiceWorkerResponseTypeOpaque:
79       return ServiceWorkerCacheResponse::OPAQUE_TYPE;
80   }
81   NOTREACHED();
82   return ServiceWorkerCacheResponse::OPAQUE_TYPE;
83 }
84
85 struct ResponseReadContext {
86   ResponseReadContext(scoped_refptr<net::IOBufferWithSize> buff,
87                       scoped_refptr<storage::BlobData> blob)
88       : buffer(buff), blob_data(blob), total_bytes_read(0) {}
89
90   scoped_refptr<net::IOBufferWithSize> buffer;
91   scoped_refptr<storage::BlobData> blob_data;
92   int total_bytes_read;
93
94   DISALLOW_COPY_AND_ASSIGN(ResponseReadContext);
95 };
96
97 // Match callbacks
98 void MatchDidOpenEntry(scoped_ptr<ServiceWorkerFetchRequest> request,
99                        const ServiceWorkerCache::ResponseCallback& callback,
100                        base::WeakPtr<storage::BlobStorageContext> blob_storage,
101                        scoped_ptr<disk_cache::Entry*> entryptr,
102                        int rv);
103 void MatchDidReadMetadata(
104     scoped_ptr<ServiceWorkerFetchRequest> request,
105     const ServiceWorkerCache::ResponseCallback& callback,
106     base::WeakPtr<storage::BlobStorageContext> blob_storage,
107     disk_cache::ScopedEntryPtr entry,
108     scoped_ptr<ServiceWorkerCacheMetadata> headers);
109 void MatchDidReadResponseBodyData(
110     scoped_ptr<ServiceWorkerFetchRequest> request,
111     const ServiceWorkerCache::ResponseCallback& callback,
112     base::WeakPtr<storage::BlobStorageContext> blob_storage,
113     disk_cache::ScopedEntryPtr entry,
114     scoped_ptr<ServiceWorkerResponse> response,
115     scoped_ptr<ResponseReadContext> response_context,
116     int rv);
117 void MatchDoneWithBody(scoped_ptr<ServiceWorkerFetchRequest> request,
118                        const ServiceWorkerCache::ResponseCallback& callback,
119                        base::WeakPtr<storage::BlobStorageContext> blob_storage,
120                        scoped_ptr<ServiceWorkerResponse> response,
121                        scoped_ptr<ResponseReadContext> response_context);
122
123 // Delete callbacks
124 void DeleteDidOpenEntry(
125     const GURL& origin,
126     scoped_ptr<ServiceWorkerFetchRequest> request,
127     const ServiceWorkerCache::ErrorCallback& callback,
128     scoped_ptr<disk_cache::Entry*> entryptr,
129     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
130     int rv);
131
132 // Copy headers out of a cache entry and into a protobuf. The callback is
133 // guaranteed to be run.
134 void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback);
135 void ReadMetadataDidReadMetadata(
136     disk_cache::Entry* entry,
137     const MetadataCallback& callback,
138     const scoped_refptr<net::IOBufferWithSize>& buffer,
139     int rv);
140
141 // CreateBackend callbacks
142 void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback& callback,
143                             scoped_ptr<ScopedBackendPtr> backend_ptr,
144                             base::WeakPtr<ServiceWorkerCache> cache,
145                             int rv);
146
147 void MatchDidOpenEntry(scoped_ptr<ServiceWorkerFetchRequest> request,
148                        const ServiceWorkerCache::ResponseCallback& callback,
149                        base::WeakPtr<storage::BlobStorageContext> blob_storage,
150                        scoped_ptr<disk_cache::Entry*> entryptr,
151                        int rv) {
152   if (rv != net::OK) {
153     callback.Run(ServiceWorkerCache::ErrorTypeNotFound,
154                  scoped_ptr<ServiceWorkerResponse>(),
155                  scoped_ptr<storage::BlobDataHandle>());
156     return;
157   }
158
159   DCHECK(entryptr);
160   disk_cache::ScopedEntryPtr entry(*entryptr);
161
162   // Copy the entry pointer before passing it in base::Bind.
163   disk_cache::Entry* tmp_entry_ptr = entry.get();
164
165   MetadataCallback headers_callback = base::Bind(MatchDidReadMetadata,
166                                                  base::Passed(request.Pass()),
167                                                  callback,
168                                                  blob_storage,
169                                                  base::Passed(entry.Pass()));
170
171   ReadMetadata(tmp_entry_ptr, headers_callback);
172 }
173
174 bool VaryMatches(const ServiceWorkerHeaderMap& request,
175                  const ServiceWorkerHeaderMap& cached_request,
176                  const ServiceWorkerHeaderMap& response) {
177   ServiceWorkerHeaderMap::const_iterator vary_iter = response.find("vary");
178   if (vary_iter == response.end())
179     return true;
180
181   std::vector<std::string> vary_keys;
182   Tokenize(vary_iter->second, ",", &vary_keys);
183   for (std::vector<std::string>::const_iterator it = vary_keys.begin();
184        it != vary_keys.end();
185        ++it) {
186     std::string trimmed;
187     base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &trimmed);
188     if (trimmed == "*")
189       return false;
190
191     ServiceWorkerHeaderMap::const_iterator request_iter = request.find(trimmed);
192     ServiceWorkerHeaderMap::const_iterator cached_request_iter =
193         cached_request.find(trimmed);
194
195     // If the header exists in one but not the other, no match.
196     if ((request_iter == request.end()) !=
197         (cached_request_iter == cached_request.end()))
198       return false;
199
200     // If the header exists in one, it exists in both. Verify that the values
201     // are equal.
202     if (request_iter != request.end() &&
203         request_iter->second != cached_request_iter->second)
204       return false;
205   }
206
207   return true;
208 }
209
210 void MatchDidReadMetadata(
211     scoped_ptr<ServiceWorkerFetchRequest> request,
212     const ServiceWorkerCache::ResponseCallback& callback,
213     base::WeakPtr<storage::BlobStorageContext> blob_storage,
214     disk_cache::ScopedEntryPtr entry,
215     scoped_ptr<ServiceWorkerCacheMetadata> metadata) {
216   if (!metadata) {
217     callback.Run(ServiceWorkerCache::ErrorTypeStorage,
218                  scoped_ptr<ServiceWorkerResponse>(),
219                  scoped_ptr<storage::BlobDataHandle>());
220     return;
221   }
222
223   scoped_ptr<ServiceWorkerResponse> response(new ServiceWorkerResponse(
224       request->url,
225       metadata->response().status_code(),
226       metadata->response().status_text(),
227       ProtoResponseTypeToWebResponseType(metadata->response().response_type()),
228       ServiceWorkerHeaderMap(),
229       "",
230       0));
231
232   if (metadata->response().has_url())
233     response->url = GURL(metadata->response().url());
234
235   for (int i = 0; i < metadata->response().headers_size(); ++i) {
236     const ServiceWorkerCacheHeaderMap header = metadata->response().headers(i);
237     response->headers.insert(std::make_pair(header.name(), header.value()));
238   }
239
240   ServiceWorkerHeaderMap cached_request_headers;
241   for (int i = 0; i < metadata->request().headers_size(); ++i) {
242     const ServiceWorkerCacheHeaderMap header = metadata->request().headers(i);
243     cached_request_headers[header.name()] = header.value();
244   }
245
246   if (!VaryMatches(
247           request->headers, cached_request_headers, response->headers)) {
248     callback.Run(ServiceWorkerCache::ErrorTypeNotFound,
249                  scoped_ptr<ServiceWorkerResponse>(),
250                  scoped_ptr<storage::BlobDataHandle>());
251     return;
252   }
253
254   if (entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
255     callback.Run(ServiceWorkerCache::ErrorTypeOK,
256                  response.Pass(),
257                  scoped_ptr<storage::BlobDataHandle>());
258     return;
259   }
260
261   // Stream the response body into a blob.
262   if (!blob_storage) {
263     callback.Run(ServiceWorkerCache::ErrorTypeStorage,
264                  scoped_ptr<ServiceWorkerResponse>(),
265                  scoped_ptr<storage::BlobDataHandle>());
266     return;
267   }
268
269   response->blob_uuid = base::GenerateGUID();
270
271   scoped_refptr<storage::BlobData> blob_data =
272       new storage::BlobData(response->blob_uuid);
273   scoped_refptr<net::IOBufferWithSize> response_body_buffer(
274       new net::IOBufferWithSize(kBufferSize));
275
276   scoped_ptr<ResponseReadContext> read_context(
277       new ResponseReadContext(response_body_buffer, blob_data));
278
279   // Copy the entry pointer before passing it in base::Bind.
280   disk_cache::Entry* tmp_entry_ptr = entry.get();
281
282   net::CompletionCallback read_callback =
283       base::Bind(MatchDidReadResponseBodyData,
284                  base::Passed(request.Pass()),
285                  callback,
286                  blob_storage,
287                  base::Passed(entry.Pass()),
288                  base::Passed(response.Pass()),
289                  base::Passed(read_context.Pass()));
290
291   int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY,
292                                         0,
293                                         response_body_buffer.get(),
294                                         response_body_buffer->size(),
295                                         read_callback);
296
297   if (read_rv != net::ERR_IO_PENDING)
298     read_callback.Run(read_rv);
299 }
300
301 void MatchDidReadResponseBodyData(
302     scoped_ptr<ServiceWorkerFetchRequest> request,
303     const ServiceWorkerCache::ResponseCallback& callback,
304     base::WeakPtr<storage::BlobStorageContext> blob_storage,
305     disk_cache::ScopedEntryPtr entry,
306     scoped_ptr<ServiceWorkerResponse> response,
307     scoped_ptr<ResponseReadContext> response_context,
308     int rv) {
309   if (rv < 0) {
310     callback.Run(ServiceWorkerCache::ErrorTypeStorage,
311                  scoped_ptr<ServiceWorkerResponse>(),
312                  scoped_ptr<storage::BlobDataHandle>());
313     return;
314   }
315
316   if (rv == 0) {
317     response->blob_uuid = response_context->blob_data->uuid();
318     response->blob_size = response_context->total_bytes_read;
319     MatchDoneWithBody(request.Pass(),
320                       callback,
321                       blob_storage,
322                       response.Pass(),
323                       response_context.Pass());
324     return;
325   }
326
327   // TODO(jkarlin): This copying of the the entire cache response into memory is
328   // awful. Create a new interface around SimpleCache that provides access the
329   // data directly from the file. See bug http://crbug.com/403493.
330   response_context->blob_data->AppendData(response_context->buffer->data(), rv);
331   response_context->total_bytes_read += rv;
332   int total_bytes_read = response_context->total_bytes_read;
333
334   // Grab some pointers before passing them in bind.
335   net::IOBufferWithSize* buffer = response_context->buffer.get();
336   disk_cache::Entry* tmp_entry_ptr = entry.get();
337
338   net::CompletionCallback read_callback =
339       base::Bind(MatchDidReadResponseBodyData,
340                  base::Passed(request.Pass()),
341                  callback,
342                  blob_storage,
343                  base::Passed(entry.Pass()),
344                  base::Passed(response.Pass()),
345                  base::Passed(response_context.Pass()));
346
347   int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY,
348                                         total_bytes_read,
349                                         buffer,
350                                         buffer->size(),
351                                         read_callback);
352
353   if (read_rv != net::ERR_IO_PENDING)
354     read_callback.Run(read_rv);
355 }
356
357 void MatchDoneWithBody(scoped_ptr<ServiceWorkerFetchRequest> request,
358                        const ServiceWorkerCache::ResponseCallback& callback,
359                        base::WeakPtr<storage::BlobStorageContext> blob_storage,
360                        scoped_ptr<ServiceWorkerResponse> response,
361                        scoped_ptr<ResponseReadContext> response_context) {
362   if (!blob_storage) {
363     callback.Run(ServiceWorkerCache::ErrorTypeStorage,
364                  scoped_ptr<ServiceWorkerResponse>(),
365                  scoped_ptr<storage::BlobDataHandle>());
366     return;
367   }
368
369   scoped_ptr<storage::BlobDataHandle> blob_data_handle(
370       blob_storage->AddFinishedBlob(response_context->blob_data.get()));
371
372   callback.Run(ServiceWorkerCache::ErrorTypeOK,
373                response.Pass(),
374                blob_data_handle.Pass());
375 }
376
377 void DeleteDidOpenEntry(
378     const GURL& origin,
379     scoped_ptr<ServiceWorkerFetchRequest> request,
380     const ServiceWorkerCache::ErrorCallback& callback,
381     scoped_ptr<disk_cache::Entry*> entryptr,
382     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
383     int rv) {
384   if (rv != net::OK) {
385     callback.Run(ServiceWorkerCache::ErrorTypeNotFound);
386     return;
387   }
388
389   DCHECK(entryptr);
390   disk_cache::ScopedEntryPtr entry(*entryptr);
391
392   if (quota_manager_proxy.get()) {
393     quota_manager_proxy->NotifyStorageModified(
394         storage::QuotaClient::kServiceWorkerCache,
395         origin,
396         storage::kStorageTypeTemporary,
397         -1 * (entry->GetDataSize(INDEX_HEADERS) +
398               entry->GetDataSize(INDEX_RESPONSE_BODY)));
399   }
400
401   entry->Doom();
402   callback.Run(ServiceWorkerCache::ErrorTypeOK);
403 }
404
405 void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
406   DCHECK(entry);
407
408   scoped_refptr<net::IOBufferWithSize> buffer(
409       new net::IOBufferWithSize(entry->GetDataSize(INDEX_HEADERS)));
410
411   net::CompletionCallback read_header_callback =
412       base::Bind(ReadMetadataDidReadMetadata, entry, callback, buffer);
413
414   int read_rv = entry->ReadData(
415       INDEX_HEADERS, 0, buffer.get(), buffer->size(), read_header_callback);
416
417   if (read_rv != net::ERR_IO_PENDING)
418     read_header_callback.Run(read_rv);
419 }
420
421 void ReadMetadataDidReadMetadata(
422     disk_cache::Entry* entry,
423     const MetadataCallback& callback,
424     const scoped_refptr<net::IOBufferWithSize>& buffer,
425     int rv) {
426   if (rv != buffer->size()) {
427     callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
428     return;
429   }
430
431   scoped_ptr<ServiceWorkerCacheMetadata> metadata(
432       new ServiceWorkerCacheMetadata());
433
434   if (!metadata->ParseFromArray(buffer->data(), buffer->size())) {
435     callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
436     return;
437   }
438
439   callback.Run(metadata.Pass());
440 }
441
442 void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback& callback,
443                             scoped_ptr<ScopedBackendPtr> backend_ptr,
444                             base::WeakPtr<ServiceWorkerCache> cache,
445                             int rv) {
446   if (rv != net::OK || !cache) {
447     callback.Run(ServiceWorkerCache::ErrorTypeStorage);
448     return;
449   }
450
451   cache->set_backend(backend_ptr->Pass());
452   callback.Run(ServiceWorkerCache::ErrorTypeOK);
453 }
454
455 }  // namespace
456
457 // Streams data from a blob and writes it to a given disk_cache::Entry.
458 class ServiceWorkerCache::BlobReader : public net::URLRequest::Delegate {
459  public:
460   typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
461       EntryAndBoolCallback;
462
463   BlobReader()
464       : cache_entry_offset_(0),
465         buffer_(new net::IOBufferWithSize(kBufferSize)),
466         weak_ptr_factory_(this) {}
467
468   // |entry| is passed to the callback once complete.
469   void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
470                          net::URLRequestContext* request_context,
471                          scoped_ptr<storage::BlobDataHandle> blob_data_handle,
472                          const EntryAndBoolCallback& callback) {
473     DCHECK(entry);
474     entry_ = entry.Pass();
475     callback_ = callback;
476     blob_request_ = storage::BlobProtocolHandler::CreateBlobRequest(
477         blob_data_handle.Pass(), request_context, this);
478     blob_request_->Start();
479   }
480
481   // net::URLRequest::Delegate overrides for reading blobs.
482   void OnReceivedRedirect(net::URLRequest* request,
483                           const net::RedirectInfo& redirect_info,
484                           bool* defer_redirect) override {
485     NOTREACHED();
486   }
487   void OnAuthRequired(net::URLRequest* request,
488                       net::AuthChallengeInfo* auth_info) override {
489     NOTREACHED();
490   }
491   void OnCertificateRequested(
492       net::URLRequest* request,
493       net::SSLCertRequestInfo* cert_request_info) override {
494     NOTREACHED();
495   }
496   void OnSSLCertificateError(net::URLRequest* request,
497                              const net::SSLInfo& ssl_info,
498                              bool fatal) override {
499     NOTREACHED();
500   }
501   void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override {
502     NOTREACHED();
503   }
504
505   void OnResponseStarted(net::URLRequest* request) override {
506     if (!request->status().is_success()) {
507       callback_.Run(entry_.Pass(), false);
508       return;
509     }
510     ReadFromBlob();
511   }
512
513   virtual void ReadFromBlob() {
514     int bytes_read = 0;
515     bool done =
516         blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read);
517     if (done)
518       OnReadCompleted(blob_request_.get(), bytes_read);
519   }
520
521   void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
522     if (!request->status().is_success()) {
523       callback_.Run(entry_.Pass(), false);
524       return;
525     }
526
527     if (bytes_read == 0) {
528       callback_.Run(entry_.Pass(), true);
529       return;
530     }
531
532     net::CompletionCallback cache_write_callback =
533         base::Bind(&BlobReader::DidWriteDataToEntry,
534                    weak_ptr_factory_.GetWeakPtr(),
535                    bytes_read);
536
537     int rv = entry_->WriteData(INDEX_RESPONSE_BODY,
538                                cache_entry_offset_,
539                                buffer_.get(),
540                                bytes_read,
541                                cache_write_callback,
542                                true /* truncate */);
543     if (rv != net::ERR_IO_PENDING)
544       cache_write_callback.Run(rv);
545   }
546
547   void DidWriteDataToEntry(int expected_bytes, int rv) {
548     if (rv != expected_bytes) {
549       callback_.Run(entry_.Pass(), false);
550       return;
551     }
552
553     cache_entry_offset_ += rv;
554     ReadFromBlob();
555   }
556
557  private:
558   int cache_entry_offset_;
559   disk_cache::ScopedEntryPtr entry_;
560   scoped_ptr<net::URLRequest> blob_request_;
561   EntryAndBoolCallback callback_;
562   scoped_refptr<net::IOBufferWithSize> buffer_;
563   base::WeakPtrFactory<BlobReader> weak_ptr_factory_;
564 };
565
566 // The state needed to pass between ServiceWorkerCache::Keys callbacks.
567 struct ServiceWorkerCache::KeysContext {
568   KeysContext(const ServiceWorkerCache::RequestsCallback& callback,
569               base::WeakPtr<ServiceWorkerCache> cache)
570       : original_callback(callback),
571         cache(cache),
572         out_keys(new ServiceWorkerCache::Requests()),
573         enumerated_entry(NULL) {}
574
575   ~KeysContext() {
576     for (size_t i = 0, max = entries.size(); i < max; ++i)
577       entries[i]->Close();
578     if (enumerated_entry)
579       enumerated_entry->Close();
580   }
581
582   // The callback passed to the Keys() function.
583   ServiceWorkerCache::RequestsCallback original_callback;
584
585   // The ServiceWorkerCache that Keys was called on.
586   base::WeakPtr<ServiceWorkerCache> cache;
587
588   // The vector of open entries in the backend.
589   Entries entries;
590
591   // The output of the Keys function.
592   scoped_ptr<ServiceWorkerCache::Requests> out_keys;
593
594   // Used for enumerating cache entries.
595   scoped_ptr<disk_cache::Backend::Iterator> backend_iterator;
596   disk_cache::Entry* enumerated_entry;
597
598   DISALLOW_COPY_AND_ASSIGN(KeysContext);
599 };
600
601 // The state needed to pass between ServiceWorkerCache::Put callbacks.
602 struct ServiceWorkerCache::PutContext {
603   PutContext(
604       const GURL& origin,
605       scoped_ptr<ServiceWorkerFetchRequest> request,
606       scoped_ptr<ServiceWorkerResponse> response,
607       scoped_ptr<storage::BlobDataHandle> blob_data_handle,
608       const ServiceWorkerCache::ResponseCallback& callback,
609       base::WeakPtr<ServiceWorkerCache> cache,
610       net::URLRequestContext* request_context,
611       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
612       : origin(origin),
613         request(request.Pass()),
614         response(response.Pass()),
615         blob_data_handle(blob_data_handle.Pass()),
616         callback(callback),
617         cache(cache),
618         request_context(request_context),
619         quota_manager_proxy(quota_manager_proxy),
620         cache_entry(NULL) {}
621   ~PutContext() {
622     if (cache_entry)
623       cache_entry->Close();
624   }
625
626   // Input parameters to the Put function.
627   GURL origin;
628   scoped_ptr<ServiceWorkerFetchRequest> request;
629   scoped_ptr<ServiceWorkerResponse> response;
630   scoped_ptr<storage::BlobDataHandle> blob_data_handle;
631   ServiceWorkerCache::ResponseCallback callback;
632   base::WeakPtr<ServiceWorkerCache> cache;
633   net::URLRequestContext* request_context;
634   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
635
636   // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
637   // CreateEntry.
638   disk_cache::Entry* cache_entry;
639
640   // The BlobDataHandle for the output ServiceWorkerResponse.
641   scoped_ptr<storage::BlobDataHandle> out_blob_data_handle;
642
643   DISALLOW_COPY_AND_ASSIGN(PutContext);
644 };
645
646 // static
647 scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache(
648     const GURL& origin,
649     net::URLRequestContext* request_context,
650     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
651     base::WeakPtr<storage::BlobStorageContext> blob_context) {
652   return make_scoped_refptr(new ServiceWorkerCache(origin,
653                                                    base::FilePath(),
654                                                    request_context,
655                                                    quota_manager_proxy,
656                                                    blob_context));
657 }
658
659 // static
660 scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache(
661     const GURL& origin,
662     const base::FilePath& path,
663     net::URLRequestContext* request_context,
664     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
665     base::WeakPtr<storage::BlobStorageContext> blob_context) {
666   return make_scoped_refptr(new ServiceWorkerCache(
667       origin, path, request_context, quota_manager_proxy, blob_context));
668 }
669
670 ServiceWorkerCache::~ServiceWorkerCache() {
671 }
672
673 base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() {
674   return weak_ptr_factory_.GetWeakPtr();
675 }
676
677 void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request,
678                              scoped_ptr<ServiceWorkerResponse> response,
679                              const ResponseCallback& callback) {
680   IncPendingOps();
681   ResponseCallback pending_callback =
682       base::Bind(&ServiceWorkerCache::PendingResponseCallback,
683                  weak_ptr_factory_.GetWeakPtr(), callback);
684   scoped_ptr<storage::BlobDataHandle> blob_data_handle;
685
686   if (!response->blob_uuid.empty()) {
687     if (!blob_storage_context_) {
688       pending_callback.Run(ErrorTypeStorage,
689                            scoped_ptr<ServiceWorkerResponse>(),
690                            scoped_ptr<storage::BlobDataHandle>());
691       return;
692     }
693     blob_data_handle =
694         blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid);
695     if (!blob_data_handle) {
696       pending_callback.Run(ErrorTypeStorage,
697                            scoped_ptr<ServiceWorkerResponse>(),
698                            scoped_ptr<storage::BlobDataHandle>());
699       return;
700     }
701   }
702
703   scoped_ptr<PutContext> put_context(new PutContext(
704       origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(),
705       pending_callback, weak_ptr_factory_.GetWeakPtr(), request_context_,
706       quota_manager_proxy_));
707
708   if (put_context->blob_data_handle) {
709     // Grab another handle to the blob for the callback response.
710     put_context->out_blob_data_handle =
711         blob_storage_context_->GetBlobDataFromUUID(
712             put_context->response->blob_uuid);
713   }
714
715   base::Closure continuation = base::Bind(&ServiceWorkerCache::PutImpl,
716                                           base::Passed(put_context.Pass()));
717
718   if (!initialized_) {
719     Init(continuation);
720     return;
721   }
722
723   continuation.Run();
724 }
725
726 void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request,
727                                const ResponseCallback& callback) {
728   IncPendingOps();
729   ResponseCallback pending_callback =
730       base::Bind(&ServiceWorkerCache::PendingResponseCallback,
731                  weak_ptr_factory_.GetWeakPtr(), callback);
732
733   if (!initialized_) {
734     Init(base::Bind(&ServiceWorkerCache::Match, weak_ptr_factory_.GetWeakPtr(),
735                     base::Passed(request.Pass()), pending_callback));
736     return;
737   }
738   if (!backend_) {
739     pending_callback.Run(ErrorTypeStorage, scoped_ptr<ServiceWorkerResponse>(),
740                          scoped_ptr<storage::BlobDataHandle>());
741     return;
742   }
743
744   scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
745
746   disk_cache::Entry** entry_ptr = entry.get();
747
748   ServiceWorkerFetchRequest* request_ptr = request.get();
749
750   net::CompletionCallback open_entry_callback = base::Bind(
751       MatchDidOpenEntry, base::Passed(request.Pass()), pending_callback,
752       blob_storage_context_, base::Passed(entry.Pass()));
753
754   int rv = backend_->OpenEntry(
755       request_ptr->url.spec(), entry_ptr, open_entry_callback);
756   if (rv != net::ERR_IO_PENDING)
757     open_entry_callback.Run(rv);
758 }
759
760 void ServiceWorkerCache::Delete(scoped_ptr<ServiceWorkerFetchRequest> request,
761                                 const ErrorCallback& callback) {
762   IncPendingOps();
763   ErrorCallback pending_callback =
764       base::Bind(&ServiceWorkerCache::PendingErrorCallback,
765                  weak_ptr_factory_.GetWeakPtr(), callback);
766
767   if (!initialized_) {
768     Init(base::Bind(&ServiceWorkerCache::Delete, weak_ptr_factory_.GetWeakPtr(),
769                     base::Passed(request.Pass()), pending_callback));
770     return;
771   }
772   if (!backend_) {
773     pending_callback.Run(ErrorTypeStorage);
774     return;
775   }
776
777   scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
778
779   disk_cache::Entry** entry_ptr = entry.get();
780
781   ServiceWorkerFetchRequest* request_ptr = request.get();
782
783   net::CompletionCallback open_entry_callback = base::Bind(
784       DeleteDidOpenEntry, origin_, base::Passed(request.Pass()),
785       pending_callback, base::Passed(entry.Pass()), quota_manager_proxy_);
786
787   int rv = backend_->OpenEntry(
788       request_ptr->url.spec(), entry_ptr, open_entry_callback);
789   if (rv != net::ERR_IO_PENDING)
790     open_entry_callback.Run(rv);
791 }
792
793 void ServiceWorkerCache::Keys(const RequestsCallback& callback) {
794   IncPendingOps();
795   RequestsCallback pending_callback =
796       base::Bind(&ServiceWorkerCache::PendingRequestsCallback,
797                  weak_ptr_factory_.GetWeakPtr(), callback);
798   if (!initialized_) {
799     Init(base::Bind(&ServiceWorkerCache::Keys, weak_ptr_factory_.GetWeakPtr(),
800                     pending_callback));
801     return;
802   }
803   if (!backend_) {
804     pending_callback.Run(ErrorTypeStorage, scoped_ptr<Requests>());
805     return;
806   }
807
808   // 1. Iterate through all of the entries, open them, and add them to a vector.
809   // 2. For each open entry:
810   //  2.1. Read the headers into a protobuf.
811   //  2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
812   //  2.3. Push the response into a vector of requests to be returned.
813   // 3. Return the vector of requests (keys).
814
815   // The entries have to be loaded into a vector first because enumeration loops
816   // forever if you read data from a cache entry while enumerating.
817
818   scoped_ptr<KeysContext> keys_context(
819       new KeysContext(pending_callback, weak_ptr_factory_.GetWeakPtr()));
820
821   keys_context->backend_iterator = backend_->CreateIterator();
822   disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
823   disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
824
825   net::CompletionCallback open_entry_callback =
826       base::Bind(KeysDidOpenNextEntry, base::Passed(keys_context.Pass()));
827
828   int rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
829
830   if (rv != net::ERR_IO_PENDING)
831     open_entry_callback.Run(rv);
832 }
833
834 void ServiceWorkerCache::Close(const base::Closure& callback) {
835   DCHECK(!initialized_ || backend_)
836       << "Don't call ServiceWorkerCache::Close() twice.";
837
838   if (pending_ops_ > 0) {
839     DCHECK(ops_complete_callback_.is_null());
840     initialized_ = true;  // So that future operations halt.
841     ops_complete_callback_ = base::Bind(
842         &ServiceWorkerCache::Close, weak_ptr_factory_.GetWeakPtr(), callback);
843     return;
844   }
845
846   initialized_ = true;
847   backend_.reset();
848   callback.Run();
849 }
850
851 int64 ServiceWorkerCache::MemoryBackedSize() const {
852   if (!backend_ || !memory_only_)
853     return 0;
854
855   scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
856       backend_->CreateIterator();
857   disk_cache::Entry* entry = nullptr;
858
859   int64 sum = 0;
860
861   std::vector<disk_cache::Entry*> entries;
862   int rv = net::OK;
863   while ((rv = backend_iter->OpenNextEntry(
864               &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
865     entries.push_back(entry);  // Open the entries without mutating them.
866   }
867   DCHECK(rv !=
868          net::ERR_IO_PENDING);  // Expect all memory ops to be synchronous.
869
870   for (disk_cache::Entry* entry : entries) {
871     sum += entry->GetDataSize(INDEX_HEADERS) +
872            entry->GetDataSize(INDEX_RESPONSE_BODY);
873     entry->Close();
874   }
875
876   return sum;
877 }
878
879 ServiceWorkerCache::ServiceWorkerCache(
880     const GURL& origin,
881     const base::FilePath& path,
882     net::URLRequestContext* request_context,
883     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
884     base::WeakPtr<storage::BlobStorageContext> blob_context)
885     : origin_(origin),
886       path_(path),
887       request_context_(request_context),
888       quota_manager_proxy_(quota_manager_proxy),
889       blob_storage_context_(blob_context),
890       initialized_(false),
891       memory_only_(path.empty()),
892       pending_ops_(0),
893       weak_ptr_factory_(this) {
894 }
895
896 // static
897 void ServiceWorkerCache::PutImpl(scoped_ptr<PutContext> put_context) {
898   if (!put_context->cache || !put_context->cache->backend_) {
899     put_context->callback.Run(ErrorTypeStorage,
900                               scoped_ptr<ServiceWorkerResponse>(),
901                               scoped_ptr<storage::BlobDataHandle>());
902     return;
903   }
904
905   scoped_ptr<ServiceWorkerFetchRequest> request_copy(
906       new ServiceWorkerFetchRequest(*put_context->request));
907   ServiceWorkerCache* cache_ptr = put_context->cache.get();
908
909   cache_ptr->Delete(request_copy.Pass(),
910                     base::Bind(PutDidDelete, base::Passed(put_context.Pass())));
911 }
912
913 // static
914 void ServiceWorkerCache::PutDidDelete(scoped_ptr<PutContext> put_context,
915                                       ErrorType delete_error) {
916   if (!put_context->cache || !put_context->cache->backend_) {
917     put_context->callback.Run(ErrorTypeStorage,
918                               scoped_ptr<ServiceWorkerResponse>(),
919                               scoped_ptr<storage::BlobDataHandle>());
920     return;
921   }
922
923   disk_cache::Entry** entry_ptr = &put_context->cache_entry;
924   ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
925   disk_cache::Backend* backend_ptr = put_context->cache->backend_.get();
926
927   net::CompletionCallback create_entry_callback =
928       base::Bind(PutDidCreateEntry, base::Passed(put_context.Pass()));
929
930   int create_rv = backend_ptr->CreateEntry(
931       request_ptr->url.spec(), entry_ptr, create_entry_callback);
932
933   if (create_rv != net::ERR_IO_PENDING)
934     create_entry_callback.Run(create_rv);
935 }
936
937 // static
938 void ServiceWorkerCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
939                                            int rv) {
940   if (rv != net::OK) {
941     put_context->callback.Run(ServiceWorkerCache::ErrorTypeExists,
942                               scoped_ptr<ServiceWorkerResponse>(),
943                               scoped_ptr<storage::BlobDataHandle>());
944     return;
945   }
946
947   DCHECK(put_context->cache_entry);
948
949   ServiceWorkerCacheMetadata metadata;
950   ServiceWorkerCacheRequest* request_metadata = metadata.mutable_request();
951   request_metadata->set_method(put_context->request->method);
952   for (ServiceWorkerHeaderMap::const_iterator it =
953            put_context->request->headers.begin();
954        it != put_context->request->headers.end();
955        ++it) {
956     ServiceWorkerCacheHeaderMap* header_map = request_metadata->add_headers();
957     header_map->set_name(it->first);
958     header_map->set_value(it->second);
959   }
960
961   ServiceWorkerCacheResponse* response_metadata = metadata.mutable_response();
962   response_metadata->set_status_code(put_context->response->status_code);
963   response_metadata->set_status_text(put_context->response->status_text);
964   response_metadata->set_response_type(
965       WebResponseTypeToProtoResponseType(put_context->response->response_type));
966   response_metadata->set_url(put_context->response->url.spec());
967   for (ServiceWorkerHeaderMap::const_iterator it =
968            put_context->response->headers.begin();
969        it != put_context->response->headers.end();
970        ++it) {
971     ServiceWorkerCacheHeaderMap* header_map = response_metadata->add_headers();
972     header_map->set_name(it->first);
973     header_map->set_value(it->second);
974   }
975
976   scoped_ptr<std::string> serialized(new std::string());
977   if (!metadata.SerializeToString(serialized.get())) {
978     put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
979                               scoped_ptr<ServiceWorkerResponse>(),
980                               scoped_ptr<storage::BlobDataHandle>());
981     return;
982   }
983
984   scoped_refptr<net::StringIOBuffer> buffer(
985       new net::StringIOBuffer(serialized.Pass()));
986
987   // Get a temporary copy of the entry pointer before passing it in base::Bind.
988   disk_cache::Entry* tmp_entry_ptr = put_context->cache_entry;
989
990   net::CompletionCallback write_headers_callback = base::Bind(
991       PutDidWriteHeaders, base::Passed(put_context.Pass()), buffer->size());
992
993   rv = tmp_entry_ptr->WriteData(INDEX_HEADERS,
994                                 0 /* offset */,
995                                 buffer.get(),
996                                 buffer->size(),
997                                 write_headers_callback,
998                                 true /* truncate */);
999
1000   if (rv != net::ERR_IO_PENDING)
1001     write_headers_callback.Run(rv);
1002 }
1003
1004 // static
1005 void ServiceWorkerCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
1006                                             int expected_bytes,
1007                                             int rv) {
1008   if (rv != expected_bytes) {
1009     put_context->cache_entry->Doom();
1010     put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
1011                               scoped_ptr<ServiceWorkerResponse>(),
1012                               scoped_ptr<storage::BlobDataHandle>());
1013     return;
1014   }
1015
1016   // The metadata is written, now for the response content. The data is streamed
1017   // from the blob into the cache entry.
1018
1019   if (put_context->response->blob_uuid.empty()) {
1020     if (put_context->quota_manager_proxy.get()) {
1021       put_context->quota_manager_proxy->NotifyStorageModified(
1022           storage::QuotaClient::kServiceWorkerCache,
1023           put_context->origin,
1024           storage::kStorageTypeTemporary,
1025           put_context->cache_entry->GetDataSize(INDEX_HEADERS));
1026     }
1027
1028     put_context->callback.Run(ServiceWorkerCache::ErrorTypeOK,
1029                               put_context->response.Pass(),
1030                               scoped_ptr<storage::BlobDataHandle>());
1031     return;
1032   }
1033
1034   DCHECK(put_context->blob_data_handle);
1035
1036   disk_cache::ScopedEntryPtr entry(put_context->cache_entry);
1037   put_context->cache_entry = NULL;
1038   scoped_ptr<BlobReader> reader(new BlobReader());
1039   BlobReader* reader_ptr = reader.get();
1040
1041   // Grab some pointers before passing put_context in Bind.
1042   net::URLRequestContext* request_context = put_context->request_context;
1043   scoped_ptr<storage::BlobDataHandle> blob_data_handle =
1044       put_context->blob_data_handle.Pass();
1045
1046   reader_ptr->StreamBlobToCache(entry.Pass(),
1047                                 request_context,
1048                                 blob_data_handle.Pass(),
1049                                 base::Bind(PutDidWriteBlobToCache,
1050                                            base::Passed(put_context.Pass()),
1051                                            base::Passed(reader.Pass())));
1052 }
1053
1054 // static
1055 void ServiceWorkerCache::PutDidWriteBlobToCache(
1056     scoped_ptr<PutContext> put_context,
1057     scoped_ptr<BlobReader> blob_reader,
1058     disk_cache::ScopedEntryPtr entry,
1059     bool success) {
1060   DCHECK(entry);
1061   put_context->cache_entry = entry.release();
1062
1063   if (!success) {
1064     put_context->cache_entry->Doom();
1065     put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
1066                               scoped_ptr<ServiceWorkerResponse>(),
1067                               scoped_ptr<storage::BlobDataHandle>());
1068     return;
1069   }
1070
1071   if (put_context->quota_manager_proxy.get()) {
1072     put_context->quota_manager_proxy->NotifyStorageModified(
1073         storage::QuotaClient::kServiceWorkerCache,
1074         put_context->origin,
1075         storage::kStorageTypeTemporary,
1076         put_context->cache_entry->GetDataSize(INDEX_HEADERS) +
1077             put_context->cache_entry->GetDataSize(INDEX_RESPONSE_BODY));
1078   }
1079
1080   put_context->callback.Run(ServiceWorkerCache::ErrorTypeOK,
1081                             put_context->response.Pass(),
1082                             put_context->out_blob_data_handle.Pass());
1083 }
1084
1085 // static
1086 void ServiceWorkerCache::KeysDidOpenNextEntry(
1087     scoped_ptr<KeysContext> keys_context,
1088     int rv) {
1089   if (rv == net::ERR_FAILED) {
1090     DCHECK(!keys_context->enumerated_entry);
1091     // Enumeration is complete, extract the requests from the entries.
1092     Entries::iterator iter = keys_context->entries.begin();
1093     KeysProcessNextEntry(keys_context.Pass(), iter);
1094     return;
1095   }
1096
1097   base::WeakPtr<ServiceWorkerCache> cache = keys_context->cache;
1098   if (rv < 0 || !cache) {
1099     keys_context->original_callback.Run(ErrorTypeStorage,
1100                                         scoped_ptr<Requests>());
1101     return;
1102   }
1103
1104   if (!cache->backend_) {
1105     keys_context->original_callback.Run(ErrorTypeNotFound,
1106                                         scoped_ptr<Requests>());
1107     return;
1108   }
1109
1110   // Store the entry.
1111   keys_context->entries.push_back(keys_context->enumerated_entry);
1112   keys_context->enumerated_entry = NULL;
1113
1114   // Enumerate the next entry.
1115   disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
1116   disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
1117   net::CompletionCallback open_entry_callback =
1118       base::Bind(KeysDidOpenNextEntry, base::Passed(keys_context.Pass()));
1119
1120   rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
1121
1122   if (rv != net::ERR_IO_PENDING)
1123     open_entry_callback.Run(rv);
1124 }
1125
1126 // static
1127 void ServiceWorkerCache::KeysProcessNextEntry(
1128     scoped_ptr<KeysContext> keys_context,
1129     const Entries::iterator& iter) {
1130   if (iter == keys_context->entries.end()) {
1131     // All done. Return all of the keys.
1132     keys_context->original_callback.Run(ErrorTypeOK,
1133                                         keys_context->out_keys.Pass());
1134     return;
1135   }
1136
1137   ReadMetadata(
1138       *iter,
1139       base::Bind(KeysDidReadMetadata, base::Passed(keys_context.Pass()), iter));
1140 }
1141
1142 // static
1143 void ServiceWorkerCache::KeysDidReadMetadata(
1144     scoped_ptr<KeysContext> keys_context,
1145     const Entries::iterator& iter,
1146     scoped_ptr<ServiceWorkerCacheMetadata> metadata) {
1147   disk_cache::Entry* entry = *iter;
1148
1149   if (metadata) {
1150     keys_context->out_keys->push_back(
1151         ServiceWorkerFetchRequest(GURL(entry->GetKey()),
1152                                   metadata->request().method(),
1153                                   ServiceWorkerHeaderMap(),
1154                                   GURL(),
1155                                   false));
1156
1157     ServiceWorkerHeaderMap& req_headers =
1158         keys_context->out_keys->back().headers;
1159
1160     for (int i = 0; i < metadata->request().headers_size(); ++i) {
1161       const ServiceWorkerCacheHeaderMap header = metadata->request().headers(i);
1162       req_headers.insert(std::make_pair(header.name(), header.value()));
1163     }
1164   } else {
1165     entry->Doom();
1166   }
1167
1168   KeysProcessNextEntry(keys_context.Pass(), iter + 1);
1169 }
1170
1171 void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) {
1172   DCHECK(!backend_);
1173
1174   // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
1175   net::CacheType cache_type = memory_only_ ? net::MEMORY_CACHE : net::APP_CACHE;
1176
1177   scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr());
1178
1179   // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
1180   ScopedBackendPtr* backend = backend_ptr.get();
1181
1182   net::CompletionCallback create_cache_callback =
1183       base::Bind(CreateBackendDidCreate,
1184                  callback,
1185                  base::Passed(backend_ptr.Pass()),
1186                  weak_ptr_factory_.GetWeakPtr());
1187
1188   // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
1189   // has for disk caches.
1190   int rv = disk_cache::CreateCacheBackend(
1191       cache_type,
1192       net::CACHE_BACKEND_SIMPLE,
1193       path_,
1194       kMaxCacheBytes,
1195       false, /* force */
1196       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(),
1197       NULL,
1198       backend,
1199       create_cache_callback);
1200   if (rv != net::ERR_IO_PENDING)
1201     create_cache_callback.Run(rv);
1202 }
1203
1204 void ServiceWorkerCache::Init(const base::Closure& callback) {
1205   DCHECK(!initialized_);
1206   init_callbacks_.push_back(callback);
1207
1208   // If this isn't the first call to Init then return as the initialization
1209   // has already started.
1210   if (init_callbacks_.size() > 1u)
1211     return;
1212
1213   CreateBackend(base::Bind(&ServiceWorkerCache::InitDone,
1214                            weak_ptr_factory_.GetWeakPtr()));
1215 }
1216
1217 void ServiceWorkerCache::InitDone(ErrorType error) {
1218   initialized_ = true;
1219   for (std::vector<base::Closure>::iterator it = init_callbacks_.begin();
1220        it != init_callbacks_.end();
1221        ++it) {
1222     it->Run();
1223   }
1224   init_callbacks_.clear();
1225 }
1226
1227 void ServiceWorkerCache::DecPendingOps() {
1228   DCHECK(pending_ops_ > 0);
1229   pending_ops_--;
1230   if (pending_ops_ == 0 && !ops_complete_callback_.is_null()) {
1231     ops_complete_callback_.Run();
1232     ops_complete_callback_.Reset();
1233   }
1234 }
1235
1236 void ServiceWorkerCache::PendingErrorCallback(const ErrorCallback& callback,
1237                                               ErrorType error) {
1238   callback.Run(error);
1239   DecPendingOps();
1240 }
1241
1242 void ServiceWorkerCache::PendingResponseCallback(
1243     const ResponseCallback& callback,
1244     ErrorType error,
1245     scoped_ptr<ServiceWorkerResponse> response,
1246     scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
1247   callback.Run(error, response.Pass(), blob_data_handle.Pass());
1248   DecPendingOps();
1249 }
1250
1251 void ServiceWorkerCache::PendingRequestsCallback(
1252     const RequestsCallback& callback,
1253     ErrorType error,
1254     scoped_ptr<Requests> requests) {
1255   callback.Run(error, requests.Pass());
1256   DecPendingOps();
1257 }
1258
1259 }  // namespace content