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/files/file_path.h"
10 #include "base/guid.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/profiler/scoped_tracker.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/io_buffer.h"
20 #include "net/base/net_errors.h"
21 #include "net/disk_cache/disk_cache.h"
22 #include "net/url_request/url_request_context.h"
23 #include "storage/browser/blob/blob_data_builder.h"
24 #include "storage/browser/blob/blob_data_handle.h"
25 #include "storage/browser/blob/blob_storage_context.h"
26 #include "storage/browser/blob/blob_url_request_job_factory.h"
27 #include "storage/browser/quota/quota_manager_proxy.h"
28 #include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
34 typedef base::Callback
<void(bool)> BoolCallback
;
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 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
220 tracked_objects::ScopedTracker
tracking_profile(
221 FROM_HERE_WITH_EXPLICIT_FUNCTION(
222 "423948 CacheStorageCache::BlobReader::OnResponseStarted"));
224 if (!request
->status().is_success()) {
225 callback_
.Run(entry_
.Pass(), false);
231 virtual void ReadFromBlob() {
234 blob_request_
->Read(buffer_
.get(), buffer_
->size(), &bytes_read
);
236 OnReadCompleted(blob_request_
.get(), bytes_read
);
239 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{
240 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
241 tracked_objects::ScopedTracker
tracking_profile(
242 FROM_HERE_WITH_EXPLICIT_FUNCTION(
243 "423948 CacheStorageCache::BlobReader::OnReadCompleted"));
245 if (!request
->status().is_success()) {
246 callback_
.Run(entry_
.Pass(), false);
250 if (bytes_read
== 0) {
251 callback_
.Run(entry_
.Pass(), true);
255 net::CompletionCallback cache_write_callback
=
256 base::Bind(&BlobReader::DidWriteDataToEntry
,
257 weak_ptr_factory_
.GetWeakPtr(), bytes_read
);
259 int rv
= entry_
->WriteData(INDEX_RESPONSE_BODY
, cache_entry_offset_
,
260 buffer_
.get(), bytes_read
, cache_write_callback
,
261 true /* truncate */);
262 if (rv
!= net::ERR_IO_PENDING
)
263 cache_write_callback
.Run(rv
);
266 void DidWriteDataToEntry(int expected_bytes
, int rv
) {
267 if (rv
!= expected_bytes
) {
268 callback_
.Run(entry_
.Pass(), false);
272 cache_entry_offset_
+= rv
;
277 int cache_entry_offset_
;
278 disk_cache::ScopedEntryPtr entry_
;
279 scoped_ptr
<net::URLRequest
> blob_request_
;
280 EntryAndBoolCallback callback_
;
281 scoped_refptr
<net::IOBufferWithSize
> buffer_
;
282 base::WeakPtrFactory
<BlobReader
> weak_ptr_factory_
;
285 // The state needed to pass between CacheStorageCache::Keys callbacks.
286 struct CacheStorageCache::KeysContext
{
287 KeysContext(const CacheStorageCache::RequestsCallback
& callback
)
288 : original_callback(callback
),
289 out_keys(new CacheStorageCache::Requests()),
290 enumerated_entry(NULL
) {}
293 for (size_t i
= 0, max
= entries
.size(); i
< max
; ++i
)
295 if (enumerated_entry
)
296 enumerated_entry
->Close();
299 // The callback passed to the Keys() function.
300 CacheStorageCache::RequestsCallback original_callback
;
302 // The vector of open entries in the backend.
305 // The output of the Keys function.
306 scoped_ptr
<CacheStorageCache::Requests
> out_keys
;
308 // Used for enumerating cache entries.
309 scoped_ptr
<disk_cache::Backend::Iterator
> backend_iterator
;
310 disk_cache::Entry
* enumerated_entry
;
312 DISALLOW_COPY_AND_ASSIGN(KeysContext
);
315 struct CacheStorageCache::MatchContext
{
316 MatchContext(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
317 const CacheStorageCache::ResponseCallback
& callback
,
318 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
)
319 : request(request
.Pass()),
320 original_callback(callback
),
321 blob_storage_context(blob_storage_context
),
323 total_bytes_read(0) {}
331 scoped_ptr
<ServiceWorkerFetchRequest
> request
;
332 CacheStorageCache::ResponseCallback original_callback
;
333 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
;
334 disk_cache::Entry
* entry
;
337 scoped_ptr
<ServiceWorkerResponse
> response
;
338 scoped_ptr
<storage::BlobDataBuilder
> blob_data
;
340 // For reading the cache entry data into a blob.
341 scoped_refptr
<net::IOBufferWithSize
> response_body_buffer
;
342 size_t total_bytes_read
;
344 DISALLOW_COPY_AND_ASSIGN(MatchContext
);
347 // The state needed to pass between CacheStorageCache::Put callbacks.
348 struct CacheStorageCache::PutContext
{
351 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
352 scoped_ptr
<ServiceWorkerResponse
> response
,
353 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
354 const CacheStorageCache::ResponseCallback
& callback
,
355 net::URLRequestContext
* request_context
,
356 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
)
358 request(request
.Pass()),
359 response(response
.Pass()),
360 blob_data_handle(blob_data_handle
.Pass()),
362 request_context(request_context
),
363 quota_manager_proxy(quota_manager_proxy
),
367 cache_entry
->Close();
370 // Input parameters to the Put function.
372 scoped_ptr
<ServiceWorkerFetchRequest
> request
;
373 scoped_ptr
<ServiceWorkerResponse
> response
;
374 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
375 CacheStorageCache::ResponseCallback callback
;
376 net::URLRequestContext
* request_context
;
377 scoped_refptr
<storage::QuotaManagerProxy
> quota_manager_proxy
;
379 // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
381 disk_cache::Entry
* cache_entry
;
383 // The BlobDataHandle for the output ServiceWorkerResponse.
384 scoped_ptr
<storage::BlobDataHandle
> out_blob_data_handle
;
386 DISALLOW_COPY_AND_ASSIGN(PutContext
);
390 scoped_refptr
<CacheStorageCache
> CacheStorageCache::CreateMemoryCache(
392 net::URLRequestContext
* request_context
,
393 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
394 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
395 return make_scoped_refptr(
396 new CacheStorageCache(origin
, base::FilePath(), request_context
,
397 quota_manager_proxy
, blob_context
));
401 scoped_refptr
<CacheStorageCache
> CacheStorageCache::CreatePersistentCache(
403 const base::FilePath
& path
,
404 net::URLRequestContext
* request_context
,
405 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
406 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
407 return make_scoped_refptr(new CacheStorageCache(
408 origin
, path
, request_context
, quota_manager_proxy
, blob_context
));
411 CacheStorageCache::~CacheStorageCache() {
414 base::WeakPtr
<CacheStorageCache
> CacheStorageCache::AsWeakPtr() {
415 return weak_ptr_factory_
.GetWeakPtr();
418 void CacheStorageCache::Put(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
419 scoped_ptr
<ServiceWorkerResponse
> response
,
420 const ResponseCallback
& callback
) {
421 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
423 if (!response
->blob_uuid
.empty()) {
424 if (!blob_storage_context_
) {
425 callback
.Run(ERROR_TYPE_STORAGE
, scoped_ptr
<ServiceWorkerResponse
>(),
426 scoped_ptr
<storage::BlobDataHandle
>());
430 blob_storage_context_
->GetBlobDataFromUUID(response
->blob_uuid
);
431 if (!blob_data_handle
) {
432 callback
.Run(ERROR_TYPE_STORAGE
, scoped_ptr
<ServiceWorkerResponse
>(),
433 scoped_ptr
<storage::BlobDataHandle
>());
438 ResponseCallback pending_callback
=
439 base::Bind(&CacheStorageCache::PendingResponseCallback
,
440 weak_ptr_factory_
.GetWeakPtr(), callback
);
442 scoped_ptr
<PutContext
> put_context(new PutContext(
443 origin_
, request
.Pass(), response
.Pass(), blob_data_handle
.Pass(),
444 pending_callback
, request_context_
, quota_manager_proxy_
));
446 if (put_context
->blob_data_handle
) {
447 // Grab another handle to the blob for the callback response.
448 put_context
->out_blob_data_handle
=
449 blob_storage_context_
->GetBlobDataFromUUID(
450 put_context
->response
->blob_uuid
);
453 if (backend_state_
== BACKEND_UNINITIALIZED
)
456 scheduler_
->ScheduleOperation(base::Bind(&CacheStorageCache::PutImpl
,
457 weak_ptr_factory_
.GetWeakPtr(),
458 base::Passed(put_context
.Pass())));
461 void CacheStorageCache::Match(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
462 const ResponseCallback
& callback
) {
463 switch (backend_state_
) {
464 case BACKEND_UNINITIALIZED
:
468 callback
.Run(ERROR_TYPE_STORAGE
, scoped_ptr
<ServiceWorkerResponse
>(),
469 scoped_ptr
<storage::BlobDataHandle
>());
476 ResponseCallback pending_callback
=
477 base::Bind(&CacheStorageCache::PendingResponseCallback
,
478 weak_ptr_factory_
.GetWeakPtr(), callback
);
479 scheduler_
->ScheduleOperation(
480 base::Bind(&CacheStorageCache::MatchImpl
, weak_ptr_factory_
.GetWeakPtr(),
481 base::Passed(request
.Pass()), pending_callback
));
484 void CacheStorageCache::Delete(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
485 const ErrorCallback
& callback
) {
486 switch (backend_state_
) {
487 case BACKEND_UNINITIALIZED
:
491 callback
.Run(ERROR_TYPE_STORAGE
);
497 ErrorCallback pending_callback
=
498 base::Bind(&CacheStorageCache::PendingErrorCallback
,
499 weak_ptr_factory_
.GetWeakPtr(), callback
);
500 scheduler_
->ScheduleOperation(
501 base::Bind(&CacheStorageCache::DeleteImpl
, weak_ptr_factory_
.GetWeakPtr(),
502 base::Passed(request
.Pass()), pending_callback
));
505 void CacheStorageCache::Keys(const RequestsCallback
& callback
) {
506 switch (backend_state_
) {
507 case BACKEND_UNINITIALIZED
:
511 callback
.Run(ERROR_TYPE_STORAGE
, scoped_ptr
<Requests
>());
518 RequestsCallback pending_callback
=
519 base::Bind(&CacheStorageCache::PendingRequestsCallback
,
520 weak_ptr_factory_
.GetWeakPtr(), callback
);
521 scheduler_
->ScheduleOperation(base::Bind(&CacheStorageCache::KeysImpl
,
522 weak_ptr_factory_
.GetWeakPtr(),
526 void CacheStorageCache::Close(const base::Closure
& callback
) {
527 DCHECK(backend_state_
!= BACKEND_CLOSED
)
528 << "Don't call CacheStorageCache::Close() twice.";
530 base::Closure pending_callback
=
531 base::Bind(&CacheStorageCache::PendingClosure
,
532 weak_ptr_factory_
.GetWeakPtr(), callback
);
534 scheduler_
->ScheduleOperation(base::Bind(&CacheStorageCache::CloseImpl
,
535 weak_ptr_factory_
.GetWeakPtr(),
539 int64
CacheStorageCache::MemoryBackedSize() const {
540 if (backend_state_
!= BACKEND_OPEN
|| !memory_only_
)
543 scoped_ptr
<disk_cache::Backend::Iterator
> backend_iter
=
544 backend_
->CreateIterator();
545 disk_cache::Entry
* entry
= nullptr;
549 std::vector
<disk_cache::Entry
*> entries
;
551 while ((rv
= backend_iter
->OpenNextEntry(
552 &entry
, base::Bind(NotReachedCompletionCallback
))) == net::OK
) {
553 entries
.push_back(entry
); // Open the entries without mutating them.
556 net::ERR_IO_PENDING
); // Expect all memory ops to be synchronous.
558 for (disk_cache::Entry
* entry
: entries
) {
559 sum
+= entry
->GetDataSize(INDEX_HEADERS
) +
560 entry
->GetDataSize(INDEX_RESPONSE_BODY
);
567 CacheStorageCache::CacheStorageCache(
569 const base::FilePath
& path
,
570 net::URLRequestContext
* request_context
,
571 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
572 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
575 request_context_(request_context
),
576 quota_manager_proxy_(quota_manager_proxy
),
577 blob_storage_context_(blob_context
),
578 backend_state_(BACKEND_UNINITIALIZED
),
579 scheduler_(new CacheStorageScheduler()),
580 initializing_(false),
581 memory_only_(path
.empty()),
582 weak_ptr_factory_(this) {
585 void CacheStorageCache::MatchImpl(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
586 const ResponseCallback
& callback
) {
587 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
588 if (backend_state_
!= BACKEND_OPEN
) {
589 callback
.Run(ERROR_TYPE_STORAGE
, scoped_ptr
<ServiceWorkerResponse
>(),
590 scoped_ptr
<storage::BlobDataHandle
>());
594 scoped_ptr
<MatchContext
> match_context(
595 new MatchContext(request
.Pass(), callback
, blob_storage_context_
));
597 disk_cache::Entry
** entry_ptr
= &match_context
->entry
;
598 ServiceWorkerFetchRequest
* request_ptr
= match_context
->request
.get();
600 net::CompletionCallback open_entry_callback
= base::Bind(
601 &CacheStorageCache::MatchDidOpenEntry
, weak_ptr_factory_
.GetWeakPtr(),
602 base::Passed(match_context
.Pass()));
604 int rv
= backend_
->OpenEntry(request_ptr
->url
.spec(), entry_ptr
,
605 open_entry_callback
);
606 if (rv
!= net::ERR_IO_PENDING
)
607 open_entry_callback
.Run(rv
);
610 void CacheStorageCache::MatchDidOpenEntry(
611 scoped_ptr
<MatchContext
> match_context
,
614 match_context
->original_callback
.Run(
615 CacheStorageCache::ERROR_TYPE_NOT_FOUND
,
616 scoped_ptr
<ServiceWorkerResponse
>(),
617 scoped_ptr
<storage::BlobDataHandle
>());
621 // Copy the entry pointer before passing it in base::Bind.
622 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
623 DCHECK(tmp_entry_ptr
);
625 MetadataCallback headers_callback
= base::Bind(
626 &CacheStorageCache::MatchDidReadMetadata
, weak_ptr_factory_
.GetWeakPtr(),
627 base::Passed(match_context
.Pass()));
629 ReadMetadata(tmp_entry_ptr
, headers_callback
);
632 void CacheStorageCache::MatchDidReadMetadata(
633 scoped_ptr
<MatchContext
> match_context
,
634 scoped_ptr
<CacheMetadata
> metadata
) {
636 match_context
->original_callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
637 scoped_ptr
<ServiceWorkerResponse
>(),
638 scoped_ptr
<storage::BlobDataHandle
>());
642 match_context
->response
.reset(new ServiceWorkerResponse(
643 match_context
->request
->url
, metadata
->response().status_code(),
644 metadata
->response().status_text(),
645 ProtoResponseTypeToWebResponseType(metadata
->response().response_type()),
646 ServiceWorkerHeaderMap(), "", 0, GURL()));
648 ServiceWorkerResponse
* response
= match_context
->response
.get();
650 if (metadata
->response().has_url())
651 response
->url
= GURL(metadata
->response().url());
653 for (int i
= 0; i
< metadata
->response().headers_size(); ++i
) {
654 const CacheHeaderMap header
= metadata
->response().headers(i
);
655 DCHECK(header
.name().find('\0') == std::string::npos
);
656 DCHECK(header
.value().find('\0') == std::string::npos
);
657 response
->headers
.insert(std::make_pair(header
.name(), header
.value()));
660 ServiceWorkerHeaderMap cached_request_headers
;
661 for (int i
= 0; i
< metadata
->request().headers_size(); ++i
) {
662 const CacheHeaderMap header
= metadata
->request().headers(i
);
663 DCHECK(header
.name().find('\0') == std::string::npos
);
664 DCHECK(header
.value().find('\0') == std::string::npos
);
665 cached_request_headers
[header
.name()] = header
.value();
668 if (!VaryMatches(match_context
->request
->headers
, cached_request_headers
,
669 response
->headers
)) {
670 match_context
->original_callback
.Run(
671 CacheStorageCache::ERROR_TYPE_NOT_FOUND
,
672 scoped_ptr
<ServiceWorkerResponse
>(),
673 scoped_ptr
<storage::BlobDataHandle
>());
677 if (match_context
->entry
->GetDataSize(INDEX_RESPONSE_BODY
) == 0) {
678 match_context
->original_callback
.Run(CacheStorageCache::ERROR_TYPE_OK
,
679 match_context
->response
.Pass(),
680 scoped_ptr
<storage::BlobDataHandle
>());
684 // Stream the response body into a blob.
685 if (!match_context
->blob_storage_context
) {
686 match_context
->original_callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
687 scoped_ptr
<ServiceWorkerResponse
>(),
688 scoped_ptr
<storage::BlobDataHandle
>());
692 response
->blob_uuid
= base::GenerateGUID();
694 match_context
->blob_data
.reset(
695 new storage::BlobDataBuilder(response
->blob_uuid
));
696 match_context
->response_body_buffer
= new net::IOBufferWithSize(kBufferSize
);
698 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
699 net::IOBufferWithSize
* response_body_buffer
=
700 match_context
->response_body_buffer
.get();
702 net::CompletionCallback read_callback
= base::Bind(
703 &CacheStorageCache::MatchDidReadResponseBodyData
,
704 weak_ptr_factory_
.GetWeakPtr(), base::Passed(match_context
.Pass()));
707 tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
, 0, response_body_buffer
,
708 response_body_buffer
->size(), read_callback
);
710 if (read_rv
!= net::ERR_IO_PENDING
)
711 read_callback
.Run(read_rv
);
714 void CacheStorageCache::MatchDidReadResponseBodyData(
715 scoped_ptr
<MatchContext
> match_context
,
718 match_context
->original_callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
719 scoped_ptr
<ServiceWorkerResponse
>(),
720 scoped_ptr
<storage::BlobDataHandle
>());
725 match_context
->response
->blob_uuid
= match_context
->blob_data
->uuid();
726 match_context
->response
->blob_size
= match_context
->total_bytes_read
;
727 MatchDoneWithBody(match_context
.Pass());
731 // TODO(jkarlin): This copying of the the entire cache response into memory is
732 // awful. Create a new interface around SimpleCache that provides access the
733 // data directly from the file. See bug http://crbug.com/403493.
734 match_context
->blob_data
->AppendData(
735 match_context
->response_body_buffer
->data(), rv
);
736 match_context
->total_bytes_read
+= rv
;
737 int total_bytes_read
= match_context
->total_bytes_read
;
739 // Grab some pointers before passing match_context in bind.
740 net::IOBufferWithSize
* buffer
= match_context
->response_body_buffer
.get();
741 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
743 net::CompletionCallback read_callback
= base::Bind(
744 &CacheStorageCache::MatchDidReadResponseBodyData
,
745 weak_ptr_factory_
.GetWeakPtr(), base::Passed(match_context
.Pass()));
747 int read_rv
= tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
, total_bytes_read
,
748 buffer
, buffer
->size(), read_callback
);
750 if (read_rv
!= net::ERR_IO_PENDING
)
751 read_callback
.Run(read_rv
);
754 void CacheStorageCache::MatchDoneWithBody(
755 scoped_ptr
<MatchContext
> match_context
) {
756 if (!match_context
->blob_storage_context
) {
757 match_context
->original_callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
758 scoped_ptr
<ServiceWorkerResponse
>(),
759 scoped_ptr
<storage::BlobDataHandle
>());
763 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle(
764 match_context
->blob_storage_context
->AddFinishedBlob(
765 match_context
->blob_data
.get()));
767 match_context
->original_callback
.Run(CacheStorageCache::ERROR_TYPE_OK
,
768 match_context
->response
.Pass(),
769 blob_data_handle
.Pass());
772 void CacheStorageCache::PutImpl(scoped_ptr
<PutContext
> put_context
) {
773 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
774 if (backend_state_
!= BACKEND_OPEN
) {
775 put_context
->callback
.Run(ERROR_TYPE_STORAGE
,
776 scoped_ptr
<ServiceWorkerResponse
>(),
777 scoped_ptr
<storage::BlobDataHandle
>());
781 scoped_ptr
<ServiceWorkerFetchRequest
> request_copy(
782 new ServiceWorkerFetchRequest(*put_context
->request
));
784 DeleteImpl(request_copy
.Pass(), base::Bind(&CacheStorageCache::PutDidDelete
,
785 weak_ptr_factory_
.GetWeakPtr(),
786 base::Passed(put_context
.Pass())));
789 void CacheStorageCache::PutDidDelete(scoped_ptr
<PutContext
> put_context
,
790 ErrorType delete_error
) {
791 if (backend_state_
!= BACKEND_OPEN
) {
792 put_context
->callback
.Run(ERROR_TYPE_STORAGE
,
793 scoped_ptr
<ServiceWorkerResponse
>(),
794 scoped_ptr
<storage::BlobDataHandle
>());
798 disk_cache::Entry
** entry_ptr
= &put_context
->cache_entry
;
799 ServiceWorkerFetchRequest
* request_ptr
= put_context
->request
.get();
800 disk_cache::Backend
* backend_ptr
= backend_
.get();
802 net::CompletionCallback create_entry_callback
= base::Bind(
803 &CacheStorageCache::PutDidCreateEntry
, weak_ptr_factory_
.GetWeakPtr(),
804 base::Passed(put_context
.Pass()));
806 int create_rv
= backend_ptr
->CreateEntry(request_ptr
->url
.spec(), entry_ptr
,
807 create_entry_callback
);
809 if (create_rv
!= net::ERR_IO_PENDING
)
810 create_entry_callback
.Run(create_rv
);
813 void CacheStorageCache::PutDidCreateEntry(scoped_ptr
<PutContext
> put_context
,
816 put_context
->callback
.Run(CacheStorageCache::ERROR_TYPE_EXISTS
,
817 scoped_ptr
<ServiceWorkerResponse
>(),
818 scoped_ptr
<storage::BlobDataHandle
>());
822 DCHECK(put_context
->cache_entry
);
824 CacheMetadata metadata
;
825 CacheRequest
* request_metadata
= metadata
.mutable_request();
826 request_metadata
->set_method(put_context
->request
->method
);
827 for (ServiceWorkerHeaderMap::const_iterator it
=
828 put_context
->request
->headers
.begin();
829 it
!= put_context
->request
->headers
.end(); ++it
) {
830 DCHECK(it
->first
.find('\0') == std::string::npos
);
831 DCHECK(it
->second
.find('\0') == std::string::npos
);
832 CacheHeaderMap
* header_map
= request_metadata
->add_headers();
833 header_map
->set_name(it
->first
);
834 header_map
->set_value(it
->second
);
837 CacheResponse
* response_metadata
= metadata
.mutable_response();
838 response_metadata
->set_status_code(put_context
->response
->status_code
);
839 response_metadata
->set_status_text(put_context
->response
->status_text
);
840 response_metadata
->set_response_type(
841 WebResponseTypeToProtoResponseType(put_context
->response
->response_type
));
842 response_metadata
->set_url(put_context
->response
->url
.spec());
843 for (ServiceWorkerHeaderMap::const_iterator it
=
844 put_context
->response
->headers
.begin();
845 it
!= put_context
->response
->headers
.end(); ++it
) {
846 DCHECK(it
->first
.find('\0') == std::string::npos
);
847 DCHECK(it
->second
.find('\0') == std::string::npos
);
848 CacheHeaderMap
* header_map
= response_metadata
->add_headers();
849 header_map
->set_name(it
->first
);
850 header_map
->set_value(it
->second
);
853 scoped_ptr
<std::string
> serialized(new std::string());
854 if (!metadata
.SerializeToString(serialized
.get())) {
855 put_context
->callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
856 scoped_ptr
<ServiceWorkerResponse
>(),
857 scoped_ptr
<storage::BlobDataHandle
>());
861 scoped_refptr
<net::StringIOBuffer
> buffer(
862 new net::StringIOBuffer(serialized
.Pass()));
864 // Get a temporary copy of the entry pointer before passing it in base::Bind.
865 disk_cache::Entry
* tmp_entry_ptr
= put_context
->cache_entry
;
867 net::CompletionCallback write_headers_callback
= base::Bind(
868 &CacheStorageCache::PutDidWriteHeaders
, weak_ptr_factory_
.GetWeakPtr(),
869 base::Passed(put_context
.Pass()), buffer
->size());
871 rv
= tmp_entry_ptr
->WriteData(INDEX_HEADERS
, 0 /* offset */, buffer
.get(),
872 buffer
->size(), write_headers_callback
,
873 true /* truncate */);
875 if (rv
!= net::ERR_IO_PENDING
)
876 write_headers_callback
.Run(rv
);
879 void CacheStorageCache::PutDidWriteHeaders(scoped_ptr
<PutContext
> put_context
,
882 if (rv
!= expected_bytes
) {
883 put_context
->cache_entry
->Doom();
884 put_context
->callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
885 scoped_ptr
<ServiceWorkerResponse
>(),
886 scoped_ptr
<storage::BlobDataHandle
>());
890 // The metadata is written, now for the response content. The data is streamed
891 // from the blob into the cache entry.
893 if (put_context
->response
->blob_uuid
.empty()) {
894 if (put_context
->quota_manager_proxy
.get()) {
895 put_context
->quota_manager_proxy
->NotifyStorageModified(
896 storage::QuotaClient::kServiceWorkerCache
, put_context
->origin
,
897 storage::kStorageTypeTemporary
,
898 put_context
->cache_entry
->GetDataSize(INDEX_HEADERS
));
901 put_context
->callback
.Run(CacheStorageCache::ERROR_TYPE_OK
,
902 put_context
->response
.Pass(),
903 scoped_ptr
<storage::BlobDataHandle
>());
907 DCHECK(put_context
->blob_data_handle
);
909 disk_cache::ScopedEntryPtr
entry(put_context
->cache_entry
);
910 put_context
->cache_entry
= NULL
;
911 scoped_ptr
<BlobReader
> reader(new BlobReader());
912 BlobReader
* reader_ptr
= reader
.get();
914 // Grab some pointers before passing put_context in Bind.
915 net::URLRequestContext
* request_context
= put_context
->request_context
;
916 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
=
917 put_context
->blob_data_handle
.Pass();
919 reader_ptr
->StreamBlobToCache(
920 entry
.Pass(), request_context
, blob_data_handle
.Pass(),
921 base::Bind(&CacheStorageCache::PutDidWriteBlobToCache
,
922 weak_ptr_factory_
.GetWeakPtr(),
923 base::Passed(put_context
.Pass()),
924 base::Passed(reader
.Pass())));
927 void CacheStorageCache::PutDidWriteBlobToCache(
928 scoped_ptr
<PutContext
> put_context
,
929 scoped_ptr
<BlobReader
> blob_reader
,
930 disk_cache::ScopedEntryPtr entry
,
933 put_context
->cache_entry
= entry
.release();
936 put_context
->cache_entry
->Doom();
937 put_context
->callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
,
938 scoped_ptr
<ServiceWorkerResponse
>(),
939 scoped_ptr
<storage::BlobDataHandle
>());
943 if (put_context
->quota_manager_proxy
.get()) {
944 put_context
->quota_manager_proxy
->NotifyStorageModified(
945 storage::QuotaClient::kServiceWorkerCache
, put_context
->origin
,
946 storage::kStorageTypeTemporary
,
947 put_context
->cache_entry
->GetDataSize(INDEX_HEADERS
) +
948 put_context
->cache_entry
->GetDataSize(INDEX_RESPONSE_BODY
));
951 put_context
->callback
.Run(CacheStorageCache::ERROR_TYPE_OK
,
952 put_context
->response
.Pass(),
953 put_context
->out_blob_data_handle
.Pass());
956 void CacheStorageCache::DeleteImpl(
957 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
958 const ErrorCallback
& callback
) {
959 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
960 if (backend_state_
!= BACKEND_OPEN
) {
961 callback
.Run(ERROR_TYPE_STORAGE
);
964 scoped_ptr
<disk_cache::Entry
*> entry(new disk_cache::Entry
*);
966 disk_cache::Entry
** entry_ptr
= entry
.get();
968 ServiceWorkerFetchRequest
* request_ptr
= request
.get();
970 net::CompletionCallback open_entry_callback
= base::Bind(
971 &CacheStorageCache::DeleteDidOpenEntry
, weak_ptr_factory_
.GetWeakPtr(),
972 origin_
, base::Passed(request
.Pass()), callback
,
973 base::Passed(entry
.Pass()), quota_manager_proxy_
);
975 int rv
= backend_
->OpenEntry(request_ptr
->url
.spec(), entry_ptr
,
976 open_entry_callback
);
977 if (rv
!= net::ERR_IO_PENDING
)
978 open_entry_callback
.Run(rv
);
981 void CacheStorageCache::DeleteDidOpenEntry(
983 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
984 const CacheStorageCache::ErrorCallback
& callback
,
985 scoped_ptr
<disk_cache::Entry
*> entry_ptr
,
986 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
989 callback
.Run(CacheStorageCache::ERROR_TYPE_NOT_FOUND
);
994 disk_cache::ScopedEntryPtr
entry(*entry_ptr
);
996 if (quota_manager_proxy
.get()) {
997 quota_manager_proxy
->NotifyStorageModified(
998 storage::QuotaClient::kServiceWorkerCache
, origin
,
999 storage::kStorageTypeTemporary
,
1000 -1 * (entry
->GetDataSize(INDEX_HEADERS
) +
1001 entry
->GetDataSize(INDEX_RESPONSE_BODY
)));
1005 callback
.Run(CacheStorageCache::ERROR_TYPE_OK
);
1008 void CacheStorageCache::KeysImpl(const RequestsCallback
& callback
) {
1009 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
1010 if (backend_state_
!= BACKEND_OPEN
) {
1011 callback
.Run(ERROR_TYPE_STORAGE
, scoped_ptr
<Requests
>());
1015 // 1. Iterate through all of the entries, open them, and add them to a vector.
1016 // 2. For each open entry:
1017 // 2.1. Read the headers into a protobuf.
1018 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
1019 // 2.3. Push the response into a vector of requests to be returned.
1020 // 3. Return the vector of requests (keys).
1022 // The entries have to be loaded into a vector first because enumeration loops
1023 // forever if you read data from a cache entry while enumerating.
1025 scoped_ptr
<KeysContext
> keys_context(new KeysContext(callback
));
1027 keys_context
->backend_iterator
= backend_
->CreateIterator();
1028 disk_cache::Backend::Iterator
& iterator
= *keys_context
->backend_iterator
;
1029 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
1031 net::CompletionCallback open_entry_callback
= base::Bind(
1032 &CacheStorageCache::KeysDidOpenNextEntry
, weak_ptr_factory_
.GetWeakPtr(),
1033 base::Passed(keys_context
.Pass()));
1035 int rv
= iterator
.OpenNextEntry(enumerated_entry
, open_entry_callback
);
1037 if (rv
!= net::ERR_IO_PENDING
)
1038 open_entry_callback
.Run(rv
);
1041 void CacheStorageCache::KeysDidOpenNextEntry(
1042 scoped_ptr
<KeysContext
> keys_context
,
1044 if (rv
== net::ERR_FAILED
) {
1045 DCHECK(!keys_context
->enumerated_entry
);
1046 // Enumeration is complete, extract the requests from the entries.
1047 Entries::iterator iter
= keys_context
->entries
.begin();
1048 KeysProcessNextEntry(keys_context
.Pass(), iter
);
1053 keys_context
->original_callback
.Run(ERROR_TYPE_STORAGE
,
1054 scoped_ptr
<Requests
>());
1058 if (backend_state_
!= BACKEND_OPEN
) {
1059 keys_context
->original_callback
.Run(ERROR_TYPE_NOT_FOUND
,
1060 scoped_ptr
<Requests
>());
1065 keys_context
->entries
.push_back(keys_context
->enumerated_entry
);
1066 keys_context
->enumerated_entry
= NULL
;
1068 // Enumerate the next entry.
1069 disk_cache::Backend::Iterator
& iterator
= *keys_context
->backend_iterator
;
1070 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
1071 net::CompletionCallback open_entry_callback
= base::Bind(
1072 &CacheStorageCache::KeysDidOpenNextEntry
, weak_ptr_factory_
.GetWeakPtr(),
1073 base::Passed(keys_context
.Pass()));
1075 rv
= iterator
.OpenNextEntry(enumerated_entry
, open_entry_callback
);
1077 if (rv
!= net::ERR_IO_PENDING
)
1078 open_entry_callback
.Run(rv
);
1081 void CacheStorageCache::KeysProcessNextEntry(
1082 scoped_ptr
<KeysContext
> keys_context
,
1083 const Entries::iterator
& iter
) {
1084 if (iter
== keys_context
->entries
.end()) {
1085 // All done. Return all of the keys.
1086 keys_context
->original_callback
.Run(ERROR_TYPE_OK
,
1087 keys_context
->out_keys
.Pass());
1091 ReadMetadata(*iter
, base::Bind(&CacheStorageCache::KeysDidReadMetadata
,
1092 weak_ptr_factory_
.GetWeakPtr(),
1093 base::Passed(keys_context
.Pass()), iter
));
1096 void CacheStorageCache::KeysDidReadMetadata(
1097 scoped_ptr
<KeysContext
> keys_context
,
1098 const Entries::iterator
& iter
,
1099 scoped_ptr
<CacheMetadata
> metadata
) {
1100 disk_cache::Entry
* entry
= *iter
;
1103 keys_context
->out_keys
->push_back(ServiceWorkerFetchRequest(
1104 GURL(entry
->GetKey()), metadata
->request().method(),
1105 ServiceWorkerHeaderMap(), Referrer(), false));
1107 ServiceWorkerHeaderMap
& req_headers
=
1108 keys_context
->out_keys
->back().headers
;
1110 for (int i
= 0; i
< metadata
->request().headers_size(); ++i
) {
1111 const CacheHeaderMap header
= metadata
->request().headers(i
);
1112 DCHECK(header
.name().find('\0') == std::string::npos
);
1113 DCHECK(header
.value().find('\0') == std::string::npos
);
1114 req_headers
.insert(std::make_pair(header
.name(), header
.value()));
1120 KeysProcessNextEntry(keys_context
.Pass(), iter
+ 1);
1123 void CacheStorageCache::CloseImpl(const base::Closure
& callback
) {
1124 DCHECK(backend_state_
!= BACKEND_CLOSED
);
1126 backend_state_
= BACKEND_CLOSED
;
1131 void CacheStorageCache::CreateBackend(const ErrorCallback
& callback
) {
1134 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
1135 net::CacheType cache_type
= memory_only_
? net::MEMORY_CACHE
: net::APP_CACHE
;
1137 scoped_ptr
<ScopedBackendPtr
> backend_ptr(new ScopedBackendPtr());
1139 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
1140 ScopedBackendPtr
* backend
= backend_ptr
.get();
1142 net::CompletionCallback create_cache_callback
=
1143 base::Bind(&CacheStorageCache::CreateBackendDidCreate
,
1144 weak_ptr_factory_
.GetWeakPtr(), callback
,
1145 base::Passed(backend_ptr
.Pass()));
1147 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
1148 // has for disk caches.
1149 int rv
= disk_cache::CreateCacheBackend(
1150 cache_type
, net::CACHE_BACKEND_SIMPLE
, path_
, kMaxCacheBytes
,
1152 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE
).get(),
1153 NULL
, backend
, create_cache_callback
);
1154 if (rv
!= net::ERR_IO_PENDING
)
1155 create_cache_callback
.Run(rv
);
1158 void CacheStorageCache::CreateBackendDidCreate(
1159 const CacheStorageCache::ErrorCallback
& callback
,
1160 scoped_ptr
<ScopedBackendPtr
> backend_ptr
,
1162 if (rv
!= net::OK
) {
1163 callback
.Run(CacheStorageCache::ERROR_TYPE_STORAGE
);
1167 backend_
= backend_ptr
->Pass();
1168 callback
.Run(CacheStorageCache::ERROR_TYPE_OK
);
1171 void CacheStorageCache::InitBackend() {
1172 DCHECK(backend_state_
== BACKEND_UNINITIALIZED
);
1177 DCHECK(!scheduler_
->ScheduledOperations());
1178 initializing_
= true;
1180 scheduler_
->ScheduleOperation(base::Bind(
1181 &CacheStorageCache::CreateBackend
, weak_ptr_factory_
.GetWeakPtr(),
1182 base::Bind(&CacheStorageCache::InitDone
,
1183 weak_ptr_factory_
.GetWeakPtr())));
1186 void CacheStorageCache::InitDone(ErrorType error
) {
1187 initializing_
= false;
1188 backend_state_
= (error
== ERROR_TYPE_OK
&& backend_
&&
1189 backend_state_
== BACKEND_UNINITIALIZED
)
1193 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", error
,
1194 ErrorType::ERROR_TYPE_LAST
+ 1);
1196 scheduler_
->CompleteOperationAndRunNext();
1199 void CacheStorageCache::PendingClosure(const base::Closure
& callback
) {
1200 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1204 scheduler_
->CompleteOperationAndRunNext();
1207 void CacheStorageCache::PendingErrorCallback(const ErrorCallback
& callback
,
1209 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1211 callback
.Run(error
);
1213 scheduler_
->CompleteOperationAndRunNext();
1216 void CacheStorageCache::PendingResponseCallback(
1217 const ResponseCallback
& callback
,
1219 scoped_ptr
<ServiceWorkerResponse
> response
,
1220 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
) {
1221 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1223 callback
.Run(error
, response
.Pass(), blob_data_handle
.Pass());
1225 scheduler_
->CompleteOperationAndRunNext();
1228 void CacheStorageCache::PendingRequestsCallback(
1229 const RequestsCallback
& callback
,
1231 scoped_ptr
<Requests
> requests
) {
1232 base::WeakPtr
<CacheStorageCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1234 callback
.Run(error
, requests
.Pass());
1236 scheduler_
->CompleteOperationAndRunNext();
1239 } // namespace content