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.
5 #include "content/browser/cache_storage/cache_storage_cache.h"
9 #include "base/barrier_closure.h"
10 #include "base/files/file_path.h"
11 #include "base/guid.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_util.h"
15 #include "content/browser/cache_storage/cache_storage.pb.h"
16 #include "content/browser/cache_storage/cache_storage_scheduler.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/common/referrer.h"
19 #include "net/base/completion_callback.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/net_errors.h"
22 #include "net/disk_cache/disk_cache.h"
23 #include "net/url_request/url_request_context.h"
24 #include "storage/browser/blob/blob_data_builder.h"
25 #include "storage/browser/blob/blob_data_handle.h"
26 #include "storage/browser/blob/blob_storage_context.h"
27 #include "storage/browser/blob/blob_url_request_job_factory.h"
28 #include "storage/browser/quota/quota_manager_proxy.h"
29 #include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
35 typedef base::Callback
<void(disk_cache::ScopedEntryPtr
, bool)>
37 typedef base::Callback
<void(scoped_ptr
<CacheMetadata
>)> MetadataCallback
;
39 enum EntryIndex
{ INDEX_HEADERS
= 0, INDEX_RESPONSE_BODY
};
41 // The maximum size of an individual cache. Ultimately cache size is controlled
43 const int kMaxCacheBytes
= 512 * 1024 * 1024;
45 // Buffer size for cache and blob reading/writing.
46 const int kBufferSize
= 1024 * 512;
48 void NotReachedCompletionCallback(int rv
) {
52 blink::WebServiceWorkerResponseType
ProtoResponseTypeToWebResponseType(
53 CacheResponse::ResponseType response_type
) {
54 switch (response_type
) {
55 case CacheResponse::BASIC_TYPE
:
56 return blink::WebServiceWorkerResponseTypeBasic
;
57 case CacheResponse::CORS_TYPE
:
58 return blink::WebServiceWorkerResponseTypeCORS
;
59 case CacheResponse::DEFAULT_TYPE
:
60 return blink::WebServiceWorkerResponseTypeDefault
;
61 case CacheResponse::ERROR_TYPE
:
62 return blink::WebServiceWorkerResponseTypeError
;
63 case CacheResponse::OPAQUE_TYPE
:
64 return blink::WebServiceWorkerResponseTypeOpaque
;
67 return blink::WebServiceWorkerResponseTypeOpaque
;
70 CacheResponse::ResponseType
WebResponseTypeToProtoResponseType(
71 blink::WebServiceWorkerResponseType response_type
) {
72 switch (response_type
) {
73 case blink::WebServiceWorkerResponseTypeBasic
:
74 return CacheResponse::BASIC_TYPE
;
75 case blink::WebServiceWorkerResponseTypeCORS
:
76 return CacheResponse::CORS_TYPE
;
77 case blink::WebServiceWorkerResponseTypeDefault
:
78 return CacheResponse::DEFAULT_TYPE
;
79 case blink::WebServiceWorkerResponseTypeError
:
80 return CacheResponse::ERROR_TYPE
;
81 case blink::WebServiceWorkerResponseTypeOpaque
:
82 return CacheResponse::OPAQUE_TYPE
;
85 return CacheResponse::OPAQUE_TYPE
;
88 // Copy headers out of a cache entry and into a protobuf. The callback is
89 // guaranteed to be run.
90 void ReadMetadata(disk_cache::Entry
* entry
, const MetadataCallback
& callback
);
91 void ReadMetadataDidReadMetadata(
92 disk_cache::Entry
* entry
,
93 const MetadataCallback
& callback
,
94 const scoped_refptr
<net::IOBufferWithSize
>& buffer
,
97 bool VaryMatches(const ServiceWorkerHeaderMap
& request
,
98 const ServiceWorkerHeaderMap
& cached_request
,
99 const ServiceWorkerHeaderMap
& response
) {
100 ServiceWorkerHeaderMap::const_iterator vary_iter
= response
.find("vary");
101 if (vary_iter
== response
.end())
104 std::vector
<std::string
> vary_keys
;
105 Tokenize(vary_iter
->second
, ",", &vary_keys
);
106 for (std::vector
<std::string
>::const_iterator it
= vary_keys
.begin();
107 it
!= vary_keys
.end(); ++it
) {
109 base::TrimWhitespaceASCII(*it
, base::TRIM_ALL
, &trimmed
);
113 ServiceWorkerHeaderMap::const_iterator request_iter
= request
.find(trimmed
);
114 ServiceWorkerHeaderMap::const_iterator cached_request_iter
=
115 cached_request
.find(trimmed
);
117 // If the header exists in one but not the other, no match.
118 if ((request_iter
== request
.end()) !=
119 (cached_request_iter
== cached_request
.end()))
122 // If the header exists in one, it exists in both. Verify that the values
124 if (request_iter
!= request
.end() &&
125 request_iter
->second
!= cached_request_iter
->second
)
132 void ReadMetadata(disk_cache::Entry
* entry
, const MetadataCallback
& callback
) {
135 scoped_refptr
<net::IOBufferWithSize
> buffer(
136 new net::IOBufferWithSize(entry
->GetDataSize(INDEX_HEADERS
)));
138 net::CompletionCallback read_header_callback
=
139 base::Bind(ReadMetadataDidReadMetadata
, entry
, callback
, buffer
);
141 int read_rv
= entry
->ReadData(INDEX_HEADERS
, 0, buffer
.get(), buffer
->size(),
142 read_header_callback
);
144 if (read_rv
!= net::ERR_IO_PENDING
)
145 read_header_callback
.Run(read_rv
);
148 void ReadMetadataDidReadMetadata(
149 disk_cache::Entry
* entry
,
150 const MetadataCallback
& callback
,
151 const scoped_refptr
<net::IOBufferWithSize
>& buffer
,
153 if (rv
!= buffer
->size()) {
154 callback
.Run(scoped_ptr
<CacheMetadata
>());
158 scoped_ptr
<CacheMetadata
> metadata(new CacheMetadata());
160 if (!metadata
->ParseFromArray(buffer
->data(), buffer
->size())) {
161 callback
.Run(scoped_ptr
<CacheMetadata
>());
165 callback
.Run(metadata
.Pass());
170 // Streams data from a blob and writes it to a given disk_cache::Entry.
171 class CacheStorageCache::BlobReader
: public net::URLRequest::Delegate
{
173 typedef base::Callback
<void(disk_cache::ScopedEntryPtr
, bool)>
174 EntryAndBoolCallback
;
177 : cache_entry_offset_(0),
178 buffer_(new net::IOBufferWithSize(kBufferSize
)),
179 weak_ptr_factory_(this) {}
181 // |entry| is passed to the callback once complete.
182 void StreamBlobToCache(disk_cache::ScopedEntryPtr entry
,
183 net::URLRequestContext
* request_context
,
184 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
185 const EntryAndBoolCallback
& callback
) {
187 entry_
= entry
.Pass();
188 callback_
= callback
;
189 blob_request_
= storage::BlobProtocolHandler::CreateBlobRequest(
190 blob_data_handle
.Pass(), request_context
, this);
191 blob_request_
->Start();
194 // net::URLRequest::Delegate overrides for reading blobs.
195 void OnReceivedRedirect(net::URLRequest
* request
,
196 const net::RedirectInfo
& redirect_info
,
197 bool* defer_redirect
) override
{
200 void OnAuthRequired(net::URLRequest
* request
,
201 net::AuthChallengeInfo
* auth_info
) override
{
204 void OnCertificateRequested(
205 net::URLRequest
* request
,
206 net::SSLCertRequestInfo
* cert_request_info
) override
{
209 void OnSSLCertificateError(net::URLRequest
* request
,
210 const net::SSLInfo
& ssl_info
,
211 bool fatal
) override
{
214 void OnBeforeNetworkStart(net::URLRequest
* request
, bool* defer
) override
{
218 void OnResponseStarted(net::URLRequest
* request
) override
{
219 if (!request
->status().is_success()) {
220 callback_
.Run(entry_
.Pass(), false);
226 virtual void ReadFromBlob() {
229 blob_request_
->Read(buffer_
.get(), buffer_
->size(), &bytes_read
);
231 OnReadCompleted(blob_request_
.get(), bytes_read
);
234 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{
235 if (!request
->status().is_success()) {
236 callback_
.Run(entry_
.Pass(), false);
240 if (bytes_read
== 0) {
241 callback_
.Run(entry_
.Pass(), true);
245 net::CompletionCallback cache_write_callback
=
246 base::Bind(&BlobReader::DidWriteDataToEntry
,
247 weak_ptr_factory_
.GetWeakPtr(), bytes_read
);
249 int rv
= entry_
->WriteData(INDEX_RESPONSE_BODY
, cache_entry_offset_
,
250 buffer_
.get(), bytes_read
, cache_write_callback
,
251 true /* truncate */);
252 if (rv
!= net::ERR_IO_PENDING
)
253 cache_write_callback
.Run(rv
);
256 void DidWriteDataToEntry(int expected_bytes
, int rv
) {
257 if (rv
!= expected_bytes
) {
258 callback_
.Run(entry_
.Pass(), false);
262 cache_entry_offset_
+= rv
;
267 int cache_entry_offset_
;
268 disk_cache::ScopedEntryPtr entry_
;
269 scoped_ptr
<net::URLRequest
> blob_request_
;
270 EntryAndBoolCallback callback_
;
271 scoped_refptr
<net::IOBufferWithSize
> buffer_
;
272 base::WeakPtrFactory
<BlobReader
> weak_ptr_factory_
;
275 // The state needed to pass between CacheStorageCache::Keys callbacks.
276 struct CacheStorageCache::KeysContext
{
277 explicit KeysContext(const CacheStorageCache::RequestsCallback
& callback
)
278 : original_callback(callback
),
279 out_keys(new CacheStorageCache::Requests()),
280 enumerated_entry(NULL
) {}
283 for (size_t i
= 0, max
= entries
.size(); i
< max
; ++i
)
285 if (enumerated_entry
)
286 enumerated_entry
->Close();
289 // The callback passed to the Keys() function.
290 CacheStorageCache::RequestsCallback original_callback
;
292 // The vector of open entries in the backend.
295 // The output of the Keys function.
296 scoped_ptr
<CacheStorageCache::Requests
> out_keys
;
298 // Used for enumerating cache entries.
299 scoped_ptr
<disk_cache::Backend::Iterator
> backend_iterator
;
300 disk_cache::Entry
* enumerated_entry
;
302 DISALLOW_COPY_AND_ASSIGN(KeysContext
);
305 struct CacheStorageCache::MatchContext
{
306 MatchContext(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
307 const CacheStorageCache::ResponseCallback
& callback
,
308 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
)
309 : request(request
.Pass()),
310 original_callback(callback
),
311 blob_storage_context(blob_storage_context
),
313 total_bytes_read(0) {}
321 scoped_ptr
<ServiceWorkerFetchRequest
> request
;
322 CacheStorageCache::ResponseCallback original_callback
;
323 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
;
324 disk_cache::Entry
* entry
;
327 scoped_ptr
<ServiceWorkerResponse
> response
;
328 scoped_ptr
<storage::BlobDataBuilder
> blob_data
;
330 // For reading the cache entry data into a blob.
331 scoped_refptr
<net::IOBufferWithSize
> response_body_buffer
;
332 size_t total_bytes_read
;
334 DISALLOW_COPY_AND_ASSIGN(MatchContext
);
337 // The state needed to pass between CacheStorageCache::Put callbacks.
338 struct CacheStorageCache::PutContext
{
341 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
342 scoped_ptr
<ServiceWorkerResponse
> response
,
343 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
344 const CacheStorageCache::ErrorCallback
& callback
,
345 net::URLRequestContext
* request_context
,
346 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
)
348 request(request
.Pass()),
349 response(response
.Pass()),
350 blob_data_handle(blob_data_handle
.Pass()),
352 request_context(request_context
),
353 quota_manager_proxy(quota_manager_proxy
),
357 cache_entry
->Close();
360 // Input parameters to the Put function.
362 scoped_ptr
<ServiceWorkerFetchRequest
> request
;
363 scoped_ptr
<ServiceWorkerResponse
> response
;
364 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
365 CacheStorageCache::ErrorCallback callback
;
366 net::URLRequestContext
* request_context
;
367 scoped_refptr
<storage::QuotaManagerProxy
> quota_manager_proxy
;
369 // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
371 disk_cache::Entry
* cache_entry
;
373 DISALLOW_COPY_AND_ASSIGN(PutContext
);
377 scoped_refptr
<CacheStorageCache
> CacheStorageCache::CreateMemoryCache(
379 net::URLRequestContext
* request_context
,
380 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
381 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
382 return make_scoped_refptr(
383 new CacheStorageCache(origin
, base::FilePath(), request_context
,
384 quota_manager_proxy
, blob_context
));
388 scoped_refptr
<CacheStorageCache
> CacheStorageCache::CreatePersistentCache(
390 const base::FilePath
& path
,
391 net::URLRequestContext
* request_context
,
392 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
393 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
394 return make_scoped_refptr(new CacheStorageCache(
395 origin
, path
, request_context
, quota_manager_proxy
, blob_context
));
398 CacheStorageCache::~CacheStorageCache() {
401 base::WeakPtr
<CacheStorageCache
> CacheStorageCache::AsWeakPtr() {
402 return weak_ptr_factory_
.GetWeakPtr();
405 void CacheStorageCache::Match(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
406 const ResponseCallback
& callback
) {
407 switch (backend_state_
) {
408 case BACKEND_UNINITIALIZED
:
412 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
413 scoped_ptr
<ServiceWorkerResponse
>(),
414 scoped_ptr
<storage::BlobDataHandle
>());
421 ResponseCallback pending_callback
=
422 base::Bind(&CacheStorageCache::PendingResponseCallback
,
423 weak_ptr_factory_
.GetWeakPtr(), callback
);
424 scheduler_
->ScheduleOperation(
425 base::Bind(&CacheStorageCache::MatchImpl
, weak_ptr_factory_
.GetWeakPtr(),
426 base::Passed(request
.Pass()), pending_callback
));
429 void CacheStorageCache::BatchOperation(
430 const std::vector
<CacheStorageBatchOperation
>& operations
,
431 const ErrorCallback
& callback
) {
432 switch (backend_state_
) {
433 case BACKEND_UNINITIALIZED
:
437 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
444 scoped_ptr
<ErrorCallback
> callback_copy(new ErrorCallback(callback
));
445 ErrorCallback
* callback_ptr
= callback_copy
.get();
446 base::Closure barrier_closure
= base::BarrierClosure(
447 operations
.size(), base::Bind(&CacheStorageCache::BatchDidAllOperations
,
448 this, base::Passed(callback_copy
.Pass())));
449 ErrorCallback completion_callback
=
450 base::Bind(&CacheStorageCache::BatchDidOneOperation
, this,
451 barrier_closure
, callback_ptr
);
453 for (const auto& operation
: operations
) {
454 switch (operation
.operation_type
) {
455 case CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
:
456 Put(operation
, completion_callback
);
458 case CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE
:
459 DCHECK_EQ(1u, operations
.size());
460 Delete(operation
, completion_callback
);
462 case CACHE_STORAGE_CACHE_OPERATION_TYPE_UNDEFINED
:
464 // TODO(nhiroki): This should return "TypeError".
465 // http://crbug.com/425505
466 completion_callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
472 void CacheStorageCache::BatchDidOneOperation(
473 const base::Closure
& barrier_closure
,
474 ErrorCallback
* callback
,
475 CacheStorageError error
) {
476 if (callback
->is_null() || error
== CACHE_STORAGE_OK
) {
477 barrier_closure
.Run();
480 callback
->Run(error
);
481 callback
->Reset(); // Only call the callback once.
483 barrier_closure
.Run();
486 void CacheStorageCache::BatchDidAllOperations(
487 scoped_ptr
<ErrorCallback
> callback
) {
488 if (callback
->is_null())
490 callback
->Run(CACHE_STORAGE_OK
);
493 void CacheStorageCache::Keys(const RequestsCallback
& callback
) {
494 switch (backend_state_
) {
495 case BACKEND_UNINITIALIZED
:
499 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
, scoped_ptr
<Requests
>());
506 RequestsCallback pending_callback
=
507 base::Bind(&CacheStorageCache::PendingRequestsCallback
,
508 weak_ptr_factory_
.GetWeakPtr(), callback
);
509 scheduler_
->ScheduleOperation(base::Bind(&CacheStorageCache::KeysImpl
,
510 weak_ptr_factory_
.GetWeakPtr(),
514 void CacheStorageCache::Close(const base::Closure
& callback
) {
515 DCHECK_NE(BACKEND_CLOSED
, backend_state_
)
516 << "Was CacheStorageCache::Close() called twice?";
518 base::Closure pending_callback
=
519 base::Bind(&CacheStorageCache::PendingClosure
,
520 weak_ptr_factory_
.GetWeakPtr(), callback
);
522 scheduler_
->ScheduleOperation(base::Bind(&CacheStorageCache::CloseImpl
,
523 weak_ptr_factory_
.GetWeakPtr(),
527 int64
CacheStorageCache::MemoryBackedSize() const {
528 if (backend_state_
!= BACKEND_OPEN
|| !memory_only_
)
531 scoped_ptr
<disk_cache::Backend::Iterator
> backend_iter
=
532 backend_
->CreateIterator();
533 disk_cache::Entry
* entry
= nullptr;
537 std::vector
<disk_cache::Entry
*> entries
;
539 while ((rv
= backend_iter
->OpenNextEntry(
540 &entry
, base::Bind(NotReachedCompletionCallback
))) == net::OK
) {
541 entries
.push_back(entry
); // Open the entries without mutating them.
543 DCHECK_NE(net::ERR_IO_PENDING
, rv
)
544 << "Memory cache operations should be synchronous.";
546 for (disk_cache::Entry
* entry
: entries
) {
547 sum
+= entry
->GetDataSize(INDEX_HEADERS
) +
548 entry
->GetDataSize(INDEX_RESPONSE_BODY
);
555 CacheStorageCache::CacheStorageCache(
557 const base::FilePath
& path
,
558 net::URLRequestContext
* request_context
,
559 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
560 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
563 request_context_(request_context
),
564 quota_manager_proxy_(quota_manager_proxy
),
565 blob_storage_context_(blob_context
),
566 backend_state_(BACKEND_UNINITIALIZED
),
567 scheduler_(new CacheStorageScheduler()),
568 initializing_(false),
569 memory_only_(path
.empty()),
570 weak_ptr_factory_(this) {
573 void CacheStorageCache::MatchImpl(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
574 const ResponseCallback
& callback
) {
575 DCHECK_NE(BACKEND_UNINITIALIZED
, backend_state_
);
576 if (backend_state_
!= BACKEND_OPEN
) {
577 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
578 scoped_ptr
<ServiceWorkerResponse
>(),
579 scoped_ptr
<storage::BlobDataHandle
>());
583 scoped_ptr
<MatchContext
> match_context(
584 new MatchContext(request
.Pass(), callback
, blob_storage_context_
));
586 disk_cache::Entry
** entry_ptr
= &match_context
->entry
;
587 ServiceWorkerFetchRequest
* request_ptr
= match_context
->request
.get();
589 net::CompletionCallback open_entry_callback
= base::Bind(
590 &CacheStorageCache::MatchDidOpenEntry
, weak_ptr_factory_
.GetWeakPtr(),
591 base::Passed(match_context
.Pass()));
593 int rv
= backend_
->OpenEntry(request_ptr
->url
.spec(), entry_ptr
,
594 open_entry_callback
);
595 if (rv
!= net::ERR_IO_PENDING
)
596 open_entry_callback
.Run(rv
);
599 void CacheStorageCache::MatchDidOpenEntry(
600 scoped_ptr
<MatchContext
> match_context
,
603 match_context
->original_callback
.Run(CACHE_STORAGE_ERROR_NOT_FOUND
,
604 scoped_ptr
<ServiceWorkerResponse
>(),
605 scoped_ptr
<storage::BlobDataHandle
>());
609 // Copy the entry pointer before passing it in base::Bind.
610 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
611 DCHECK(tmp_entry_ptr
);
613 MetadataCallback headers_callback
= base::Bind(
614 &CacheStorageCache::MatchDidReadMetadata
, weak_ptr_factory_
.GetWeakPtr(),
615 base::Passed(match_context
.Pass()));
617 ReadMetadata(tmp_entry_ptr
, headers_callback
);
620 void CacheStorageCache::MatchDidReadMetadata(
621 scoped_ptr
<MatchContext
> match_context
,
622 scoped_ptr
<CacheMetadata
> metadata
) {
624 match_context
->original_callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
625 scoped_ptr
<ServiceWorkerResponse
>(),
626 scoped_ptr
<storage::BlobDataHandle
>());
630 match_context
->response
.reset(new ServiceWorkerResponse(
631 match_context
->request
->url
, metadata
->response().status_code(),
632 metadata
->response().status_text(),
633 ProtoResponseTypeToWebResponseType(metadata
->response().response_type()),
634 ServiceWorkerHeaderMap(), "", 0, GURL()));
636 ServiceWorkerResponse
* response
= match_context
->response
.get();
638 if (metadata
->response().has_url())
639 response
->url
= GURL(metadata
->response().url());
641 for (int i
= 0; i
< metadata
->response().headers_size(); ++i
) {
642 const CacheHeaderMap header
= metadata
->response().headers(i
);
643 DCHECK_EQ(std::string::npos
, header
.name().find('\0'));
644 DCHECK_EQ(std::string::npos
, header
.value().find('\0'));
645 response
->headers
.insert(std::make_pair(header
.name(), header
.value()));
648 ServiceWorkerHeaderMap cached_request_headers
;
649 for (int i
= 0; i
< metadata
->request().headers_size(); ++i
) {
650 const CacheHeaderMap header
= metadata
->request().headers(i
);
651 DCHECK_EQ(std::string::npos
, header
.name().find('\0'));
652 DCHECK_EQ(std::string::npos
, header
.value().find('\0'));
653 cached_request_headers
[header
.name()] = header
.value();
656 if (!VaryMatches(match_context
->request
->headers
, cached_request_headers
,
657 response
->headers
)) {
658 match_context
->original_callback
.Run(CACHE_STORAGE_ERROR_NOT_FOUND
,
659 scoped_ptr
<ServiceWorkerResponse
>(),
660 scoped_ptr
<storage::BlobDataHandle
>());
664 if (match_context
->entry
->GetDataSize(INDEX_RESPONSE_BODY
) == 0) {
665 match_context
->original_callback
.Run(CACHE_STORAGE_OK
,
666 match_context
->response
.Pass(),
667 scoped_ptr
<storage::BlobDataHandle
>());
671 // Stream the response body into a blob.
672 if (!match_context
->blob_storage_context
) {
673 match_context
->original_callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
674 scoped_ptr
<ServiceWorkerResponse
>(),
675 scoped_ptr
<storage::BlobDataHandle
>());
679 response
->blob_uuid
= base::GenerateGUID();
681 match_context
->blob_data
.reset(
682 new storage::BlobDataBuilder(response
->blob_uuid
));
683 match_context
->response_body_buffer
= new net::IOBufferWithSize(kBufferSize
);
685 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
686 net::IOBufferWithSize
* response_body_buffer
=
687 match_context
->response_body_buffer
.get();
689 net::CompletionCallback read_callback
= base::Bind(
690 &CacheStorageCache::MatchDidReadResponseBodyData
,
691 weak_ptr_factory_
.GetWeakPtr(), base::Passed(match_context
.Pass()));
694 tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
, 0, response_body_buffer
,
695 response_body_buffer
->size(), read_callback
);
697 if (read_rv
!= net::ERR_IO_PENDING
)
698 read_callback
.Run(read_rv
);
701 void CacheStorageCache::MatchDidReadResponseBodyData(
702 scoped_ptr
<MatchContext
> match_context
,
705 match_context
->original_callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
706 scoped_ptr
<ServiceWorkerResponse
>(),
707 scoped_ptr
<storage::BlobDataHandle
>());
712 match_context
->response
->blob_uuid
= match_context
->blob_data
->uuid();
713 match_context
->response
->blob_size
= match_context
->total_bytes_read
;
714 MatchDoneWithBody(match_context
.Pass());
718 // TODO(jkarlin): This copying of the the entire cache response into memory is
719 // awful. Create a new interface around SimpleCache that provides access the
720 // data directly from the file. See bug http://crbug.com/403493.
721 match_context
->blob_data
->AppendData(
722 match_context
->response_body_buffer
->data(), rv
);
723 match_context
->total_bytes_read
+= rv
;
724 int total_bytes_read
= match_context
->total_bytes_read
;
726 // Grab some pointers before passing match_context in bind.
727 net::IOBufferWithSize
* buffer
= match_context
->response_body_buffer
.get();
728 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
730 net::CompletionCallback read_callback
= base::Bind(
731 &CacheStorageCache::MatchDidReadResponseBodyData
,
732 weak_ptr_factory_
.GetWeakPtr(), base::Passed(match_context
.Pass()));
734 int read_rv
= tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
, total_bytes_read
,
735 buffer
, buffer
->size(), read_callback
);
737 if (read_rv
!= net::ERR_IO_PENDING
)
738 read_callback
.Run(read_rv
);
741 void CacheStorageCache::MatchDoneWithBody(
742 scoped_ptr
<MatchContext
> match_context
) {
743 if (!match_context
->blob_storage_context
) {
744 match_context
->original_callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
745 scoped_ptr
<ServiceWorkerResponse
>(),
746 scoped_ptr
<storage::BlobDataHandle
>());
750 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle(
751 match_context
->blob_storage_context
->AddFinishedBlob(
752 match_context
->blob_data
.get()));
754 match_context
->original_callback
.Run(CACHE_STORAGE_OK
,
755 match_context
->response
.Pass(),
756 blob_data_handle
.Pass());
759 void CacheStorageCache::Put(const CacheStorageBatchOperation
& operation
,
760 const ErrorCallback
& callback
) {
761 DCHECK(BACKEND_OPEN
== backend_state_
|| initializing_
);
762 DCHECK_EQ(CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT
, operation
.operation_type
);
764 scoped_ptr
<ServiceWorkerFetchRequest
> request(new ServiceWorkerFetchRequest(
765 operation
.request
.url
, operation
.request
.method
,
766 operation
.request
.headers
, operation
.request
.referrer
,
767 operation
.request
.is_reload
));
769 // We don't support streaming for cache.
770 DCHECK(operation
.response
.stream_url
.is_empty());
771 scoped_ptr
<ServiceWorkerResponse
> response(new ServiceWorkerResponse(
772 operation
.response
.url
, operation
.response
.status_code
,
773 operation
.response
.status_text
, operation
.response
.response_type
,
774 operation
.response
.headers
, operation
.response
.blob_uuid
,
775 operation
.response
.blob_size
, operation
.response
.stream_url
));
777 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
779 if (!response
->blob_uuid
.empty()) {
780 if (!blob_storage_context_
) {
781 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
785 blob_storage_context_
->GetBlobDataFromUUID(response
->blob_uuid
);
786 if (!blob_data_handle
) {
787 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
792 ErrorCallback pending_callback
=
793 base::Bind(&CacheStorageCache::PendingErrorCallback
,
794 weak_ptr_factory_
.GetWeakPtr(), callback
);
796 scoped_ptr
<PutContext
> put_context(new PutContext(
797 origin_
, request
.Pass(), response
.Pass(), blob_data_handle
.Pass(),
798 pending_callback
, request_context_
, quota_manager_proxy_
));
800 scheduler_
->ScheduleOperation(base::Bind(&CacheStorageCache::PutImpl
,
801 weak_ptr_factory_
.GetWeakPtr(),
802 base::Passed(put_context
.Pass())));
805 void CacheStorageCache::PutImpl(scoped_ptr
<PutContext
> put_context
) {
806 DCHECK_NE(BACKEND_UNINITIALIZED
, backend_state_
);
807 if (backend_state_
!= BACKEND_OPEN
) {
808 put_context
->callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
812 scoped_ptr
<ServiceWorkerFetchRequest
> request_copy(
813 new ServiceWorkerFetchRequest(*put_context
->request
));
815 DeleteImpl(request_copy
.Pass(), base::Bind(&CacheStorageCache::PutDidDelete
,
816 weak_ptr_factory_
.GetWeakPtr(),
817 base::Passed(put_context
.Pass())));
820 void CacheStorageCache::PutDidDelete(scoped_ptr
<PutContext
> put_context
,
821 CacheStorageError delete_error
) {
822 if (backend_state_
!= BACKEND_OPEN
) {
823 put_context
->callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
827 disk_cache::Entry
** entry_ptr
= &put_context
->cache_entry
;
828 ServiceWorkerFetchRequest
* request_ptr
= put_context
->request
.get();
829 disk_cache::Backend
* backend_ptr
= backend_
.get();
831 net::CompletionCallback create_entry_callback
= base::Bind(
832 &CacheStorageCache::PutDidCreateEntry
, weak_ptr_factory_
.GetWeakPtr(),
833 base::Passed(put_context
.Pass()));
835 int create_rv
= backend_ptr
->CreateEntry(request_ptr
->url
.spec(), entry_ptr
,
836 create_entry_callback
);
838 if (create_rv
!= net::ERR_IO_PENDING
)
839 create_entry_callback
.Run(create_rv
);
842 void CacheStorageCache::PutDidCreateEntry(scoped_ptr
<PutContext
> put_context
,
845 put_context
->callback
.Run(CACHE_STORAGE_ERROR_EXISTS
);
849 DCHECK(put_context
->cache_entry
);
851 CacheMetadata metadata
;
852 CacheRequest
* request_metadata
= metadata
.mutable_request();
853 request_metadata
->set_method(put_context
->request
->method
);
854 for (ServiceWorkerHeaderMap::const_iterator it
=
855 put_context
->request
->headers
.begin();
856 it
!= put_context
->request
->headers
.end(); ++it
) {
857 DCHECK_EQ(std::string::npos
, it
->first
.find('\0'));
858 DCHECK_EQ(std::string::npos
, it
->second
.find('\0'));
859 CacheHeaderMap
* header_map
= request_metadata
->add_headers();
860 header_map
->set_name(it
->first
);
861 header_map
->set_value(it
->second
);
864 CacheResponse
* response_metadata
= metadata
.mutable_response();
865 response_metadata
->set_status_code(put_context
->response
->status_code
);
866 response_metadata
->set_status_text(put_context
->response
->status_text
);
867 response_metadata
->set_response_type(
868 WebResponseTypeToProtoResponseType(put_context
->response
->response_type
));
869 response_metadata
->set_url(put_context
->response
->url
.spec());
870 for (ServiceWorkerHeaderMap::const_iterator it
=
871 put_context
->response
->headers
.begin();
872 it
!= put_context
->response
->headers
.end(); ++it
) {
873 DCHECK_EQ(std::string::npos
, it
->first
.find('\0'));
874 DCHECK_EQ(std::string::npos
, it
->second
.find('\0'));
875 CacheHeaderMap
* header_map
= response_metadata
->add_headers();
876 header_map
->set_name(it
->first
);
877 header_map
->set_value(it
->second
);
880 scoped_ptr
<std::string
> serialized(new std::string());
881 if (!metadata
.SerializeToString(serialized
.get())) {
882 put_context
->callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
886 scoped_refptr
<net::StringIOBuffer
> buffer(
887 new net::StringIOBuffer(serialized
.Pass()));
889 // Get a temporary copy of the entry pointer before passing it in base::Bind.
890 disk_cache::Entry
* tmp_entry_ptr
= put_context
->cache_entry
;
892 net::CompletionCallback write_headers_callback
= base::Bind(
893 &CacheStorageCache::PutDidWriteHeaders
, weak_ptr_factory_
.GetWeakPtr(),
894 base::Passed(put_context
.Pass()), buffer
->size());
896 rv
= tmp_entry_ptr
->WriteData(INDEX_HEADERS
, 0 /* offset */, buffer
.get(),
897 buffer
->size(), write_headers_callback
,
898 true /* truncate */);
900 if (rv
!= net::ERR_IO_PENDING
)
901 write_headers_callback
.Run(rv
);
904 void CacheStorageCache::PutDidWriteHeaders(scoped_ptr
<PutContext
> put_context
,
907 if (rv
!= expected_bytes
) {
908 put_context
->cache_entry
->Doom();
909 put_context
->callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
913 // The metadata is written, now for the response content. The data is streamed
914 // from the blob into the cache entry.
916 if (put_context
->response
->blob_uuid
.empty()) {
917 if (put_context
->quota_manager_proxy
.get()) {
918 put_context
->quota_manager_proxy
->NotifyStorageModified(
919 storage::QuotaClient::kServiceWorkerCache
, put_context
->origin
,
920 storage::kStorageTypeTemporary
,
921 put_context
->cache_entry
->GetDataSize(INDEX_HEADERS
));
924 put_context
->callback
.Run(CACHE_STORAGE_OK
);
928 DCHECK(put_context
->blob_data_handle
);
930 disk_cache::ScopedEntryPtr
entry(put_context
->cache_entry
);
931 put_context
->cache_entry
= NULL
;
932 scoped_ptr
<BlobReader
> reader(new BlobReader());
933 BlobReader
* reader_ptr
= reader
.get();
935 // Grab some pointers before passing put_context in Bind.
936 net::URLRequestContext
* request_context
= put_context
->request_context
;
937 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
=
938 put_context
->blob_data_handle
.Pass();
940 reader_ptr
->StreamBlobToCache(
941 entry
.Pass(), request_context
, blob_data_handle
.Pass(),
942 base::Bind(&CacheStorageCache::PutDidWriteBlobToCache
,
943 weak_ptr_factory_
.GetWeakPtr(),
944 base::Passed(put_context
.Pass()),
945 base::Passed(reader
.Pass())));
948 void CacheStorageCache::PutDidWriteBlobToCache(
949 scoped_ptr
<PutContext
> put_context
,
950 scoped_ptr
<BlobReader
> blob_reader
,
951 disk_cache::ScopedEntryPtr entry
,
954 put_context
->cache_entry
= entry
.release();
957 put_context
->cache_entry
->Doom();
958 put_context
->callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
962 if (put_context
->quota_manager_proxy
.get()) {
963 put_context
->quota_manager_proxy
->NotifyStorageModified(
964 storage::QuotaClient::kServiceWorkerCache
, put_context
->origin
,
965 storage::kStorageTypeTemporary
,
966 put_context
->cache_entry
->GetDataSize(INDEX_HEADERS
) +
967 put_context
->cache_entry
->GetDataSize(INDEX_RESPONSE_BODY
));
970 put_context
->callback
.Run(CACHE_STORAGE_OK
);
973 void CacheStorageCache::Delete(const CacheStorageBatchOperation
& operation
,
974 const ErrorCallback
& callback
) {
975 DCHECK(BACKEND_OPEN
== backend_state_
|| initializing_
);
976 DCHECK_EQ(CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE
,
977 operation
.operation_type
);
979 scoped_ptr
<ServiceWorkerFetchRequest
> request(new ServiceWorkerFetchRequest(
980 operation
.request
.url
, operation
.request
.method
,
981 operation
.request
.headers
, operation
.request
.referrer
,
982 operation
.request
.is_reload
));
984 ErrorCallback pending_callback
=
985 base::Bind(&CacheStorageCache::PendingErrorCallback
,
986 weak_ptr_factory_
.GetWeakPtr(), callback
);
987 scheduler_
->ScheduleOperation(
988 base::Bind(&CacheStorageCache::DeleteImpl
, weak_ptr_factory_
.GetWeakPtr(),
989 base::Passed(request
.Pass()), pending_callback
));
992 void CacheStorageCache::DeleteImpl(
993 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
994 const ErrorCallback
& callback
) {
995 DCHECK_NE(BACKEND_UNINITIALIZED
, backend_state_
);
996 if (backend_state_
!= BACKEND_OPEN
) {
997 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
1000 scoped_ptr
<disk_cache::Entry
*> entry(new disk_cache::Entry
*);
1002 disk_cache::Entry
** entry_ptr
= entry
.get();
1004 ServiceWorkerFetchRequest
* request_ptr
= request
.get();
1006 net::CompletionCallback open_entry_callback
= base::Bind(
1007 &CacheStorageCache::DeleteDidOpenEntry
, weak_ptr_factory_
.GetWeakPtr(),
1008 origin_
, base::Passed(request
.Pass()), callback
,
1009 base::Passed(entry
.Pass()), quota_manager_proxy_
);
1011 int rv
= backend_
->OpenEntry(request_ptr
->url
.spec(), entry_ptr
,
1012 open_entry_callback
);
1013 if (rv
!= net::ERR_IO_PENDING
)
1014 open_entry_callback
.Run(rv
);
1017 void CacheStorageCache::DeleteDidOpenEntry(
1019 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
1020 const CacheStorageCache::ErrorCallback
& callback
,
1021 scoped_ptr
<disk_cache::Entry
*> entry_ptr
,
1022 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
1024 if (rv
!= net::OK
) {
1025 callback
.Run(CACHE_STORAGE_ERROR_NOT_FOUND
);
1030 disk_cache::ScopedEntryPtr
entry(*entry_ptr
);
1032 if (quota_manager_proxy
.get()) {
1033 quota_manager_proxy
->NotifyStorageModified(
1034 storage::QuotaClient::kServiceWorkerCache
, origin
,
1035 storage::kStorageTypeTemporary
,
1036 -1 * (entry
->GetDataSize(INDEX_HEADERS
) +
1037 entry
->GetDataSize(INDEX_RESPONSE_BODY
)));
1041 callback
.Run(CACHE_STORAGE_OK
);
1044 void CacheStorageCache::KeysImpl(const RequestsCallback
& callback
) {
1045 DCHECK_NE(BACKEND_UNINITIALIZED
, backend_state_
);
1046 if (backend_state_
!= BACKEND_OPEN
) {
1047 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
, scoped_ptr
<Requests
>());
1051 // 1. Iterate through all of the entries, open them, and add them to a vector.
1052 // 2. For each open entry:
1053 // 2.1. Read the headers into a protobuf.
1054 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
1055 // 2.3. Push the response into a vector of requests to be returned.
1056 // 3. Return the vector of requests (keys).
1058 // The entries have to be loaded into a vector first because enumeration loops
1059 // forever if you read data from a cache entry while enumerating.
1061 scoped_ptr
<KeysContext
> keys_context(new KeysContext(callback
));
1063 keys_context
->backend_iterator
= backend_
->CreateIterator();
1064 disk_cache::Backend::Iterator
& iterator
= *keys_context
->backend_iterator
;
1065 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
1067 net::CompletionCallback open_entry_callback
= base::Bind(
1068 &CacheStorageCache::KeysDidOpenNextEntry
, weak_ptr_factory_
.GetWeakPtr(),
1069 base::Passed(keys_context
.Pass()));
1071 int rv
= iterator
.OpenNextEntry(enumerated_entry
, open_entry_callback
);
1073 if (rv
!= net::ERR_IO_PENDING
)
1074 open_entry_callback
.Run(rv
);
1077 void CacheStorageCache::KeysDidOpenNextEntry(
1078 scoped_ptr
<KeysContext
> keys_context
,
1080 if (rv
== net::ERR_FAILED
) {
1081 DCHECK(!keys_context
->enumerated_entry
);
1082 // Enumeration is complete, extract the requests from the entries.
1083 Entries::iterator iter
= keys_context
->entries
.begin();
1084 KeysProcessNextEntry(keys_context
.Pass(), iter
);
1089 keys_context
->original_callback
.Run(CACHE_STORAGE_ERROR_STORAGE
,
1090 scoped_ptr
<Requests
>());
1094 if (backend_state_
!= BACKEND_OPEN
) {
1095 keys_context
->original_callback
.Run(CACHE_STORAGE_ERROR_NOT_FOUND
,
1096 scoped_ptr
<Requests
>());
1101 keys_context
->entries
.push_back(keys_context
->enumerated_entry
);
1102 keys_context
->enumerated_entry
= NULL
;
1104 // Enumerate the next entry.
1105 disk_cache::Backend::Iterator
& iterator
= *keys_context
->backend_iterator
;
1106 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
1107 net::CompletionCallback open_entry_callback
= base::Bind(
1108 &CacheStorageCache::KeysDidOpenNextEntry
, weak_ptr_factory_
.GetWeakPtr(),
1109 base::Passed(keys_context
.Pass()));
1111 rv
= iterator
.OpenNextEntry(enumerated_entry
, open_entry_callback
);
1113 if (rv
!= net::ERR_IO_PENDING
)
1114 open_entry_callback
.Run(rv
);
1117 void CacheStorageCache::KeysProcessNextEntry(
1118 scoped_ptr
<KeysContext
> keys_context
,
1119 const Entries::iterator
& iter
) {
1120 if (iter
== keys_context
->entries
.end()) {
1121 // All done. Return all of the keys.
1122 keys_context
->original_callback
.Run(CACHE_STORAGE_OK
,
1123 keys_context
->out_keys
.Pass());
1127 ReadMetadata(*iter
, base::Bind(&CacheStorageCache::KeysDidReadMetadata
,
1128 weak_ptr_factory_
.GetWeakPtr(),
1129 base::Passed(keys_context
.Pass()), iter
));
1132 void CacheStorageCache::KeysDidReadMetadata(
1133 scoped_ptr
<KeysContext
> keys_context
,
1134 const Entries::iterator
& iter
,
1135 scoped_ptr
<CacheMetadata
> metadata
) {
1136 disk_cache::Entry
* entry
= *iter
;
1139 keys_context
->out_keys
->push_back(ServiceWorkerFetchRequest(
1140 GURL(entry
->GetKey()), metadata
->request().method(),
1141 ServiceWorkerHeaderMap(), Referrer(), false));
1143 ServiceWorkerHeaderMap
& req_headers
=
1144 keys_context
->out_keys
->back().headers
;
1146 for (int i
= 0; i
< metadata
->request().headers_size(); ++i
) {
1147 const CacheHeaderMap header
= metadata
->request().headers(i
);
1148 DCHECK_EQ(std::string::npos
, header
.name().find('\0'));
1149 DCHECK_EQ(std::string::npos
, header
.value().find('\0'));
1150 req_headers
.insert(std::make_pair(header
.name(), header
.value()));
1156 KeysProcessNextEntry(keys_context
.Pass(), iter
+ 1);
1159 void CacheStorageCache::CloseImpl(const base::Closure
& callback
) {
1160 DCHECK_NE(BACKEND_CLOSED
, backend_state_
);
1162 backend_state_
= BACKEND_CLOSED
;
1167 void CacheStorageCache::CreateBackend(const ErrorCallback
& callback
) {
1170 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
1171 net::CacheType cache_type
= memory_only_
? net::MEMORY_CACHE
: net::APP_CACHE
;
1173 scoped_ptr
<ScopedBackendPtr
> backend_ptr(new ScopedBackendPtr());
1175 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
1176 ScopedBackendPtr
* backend
= backend_ptr
.get();
1178 net::CompletionCallback create_cache_callback
=
1179 base::Bind(&CacheStorageCache::CreateBackendDidCreate
,
1180 weak_ptr_factory_
.GetWeakPtr(), callback
,
1181 base::Passed(backend_ptr
.Pass()));
1183 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
1184 // has for disk caches.
1185 int rv
= disk_cache::CreateCacheBackend(
1186 cache_type
, net::CACHE_BACKEND_SIMPLE
, path_
, kMaxCacheBytes
,
1188 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE
).get(),
1189 NULL
, backend
, create_cache_callback
);
1190 if (rv
!= net::ERR_IO_PENDING
)
1191 create_cache_callback
.Run(rv
);
1194 void CacheStorageCache::CreateBackendDidCreate(
1195 const CacheStorageCache::ErrorCallback
& callback
,
1196 scoped_ptr
<ScopedBackendPtr
> backend_ptr
,
1198 if (rv
!= net::OK
) {
1199 callback
.Run(CACHE_STORAGE_ERROR_STORAGE
);
1203 backend_
= backend_ptr
->Pass();
1204 callback
.Run(CACHE_STORAGE_OK
);
1207 void CacheStorageCache::InitBackend() {
1208 DCHECK_EQ(BACKEND_UNINITIALIZED
, backend_state_
);
1213 DCHECK(!scheduler_
->ScheduledOperations());
1214 initializing_
= true;
1216 scheduler_
->ScheduleOperation(base::Bind(
1217 &CacheStorageCache::CreateBackend
, weak_ptr_factory_
.GetWeakPtr(),
1218 base::Bind(&CacheStorageCache::InitDone
,
1219 weak_ptr_factory_
.GetWeakPtr())));
1222 void CacheStorageCache::InitDone(CacheStorageError error
) {
1223 initializing_
= false;
1224 backend_state_
= (error
== CACHE_STORAGE_OK
&& backend_
&&
1225 backend_state_
== BACKEND_UNINITIALIZED
)
1229 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", error
,
1230 CACHE_STORAGE_ERROR_LAST
+ 1);
1232 scheduler_
->CompleteOperationAndRunNext();
1235 void CacheStorageCache::PendingClosure(const base::Closure
& callback
) {
1236 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1240 scheduler_
->CompleteOperationAndRunNext();
1243 void CacheStorageCache::PendingErrorCallback(const ErrorCallback
& callback
,
1244 CacheStorageError error
) {
1245 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1247 callback
.Run(error
);
1249 scheduler_
->CompleteOperationAndRunNext();
1252 void CacheStorageCache::PendingResponseCallback(
1253 const ResponseCallback
& callback
,
1254 CacheStorageError error
,
1255 scoped_ptr
<ServiceWorkerResponse
> response
,
1256 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
) {
1257 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1259 callback
.Run(error
, response
.Pass(), blob_data_handle
.Pass());
1261 scheduler_
->CompleteOperationAndRunNext();
1264 void CacheStorageCache::PendingRequestsCallback(
1265 const RequestsCallback
& callback
,
1266 CacheStorageError error
,
1267 scoped_ptr
<Requests
> requests
) {
1268 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1270 callback
.Run(error
, requests
.Pass());
1272 scheduler_
->CompleteOperationAndRunNext();
1275 } // namespace content