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/service_worker/service_worker_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/profiler/scoped_tracker.h"
13 #include "base/strings/string_util.h"
14 #include "content/browser/service_worker/service_worker_cache.pb.h"
15 #include "content/browser/service_worker/service_worker_cache_scheduler.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/referrer.h"
18 #include "net/base/io_buffer.h"
19 #include "net/base/net_errors.h"
20 #include "net/disk_cache/disk_cache.h"
21 #include "net/url_request/url_request_context.h"
22 #include "storage/browser/blob/blob_data_builder.h"
23 #include "storage/browser/blob/blob_data_handle.h"
24 #include "storage/browser/blob/blob_storage_context.h"
25 #include "storage/browser/blob/blob_url_request_job_factory.h"
26 #include "storage/browser/quota/quota_manager_proxy.h"
27 #include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
33 typedef base::Callback
<void(bool)> BoolCallback
;
34 typedef base::Callback
<void(disk_cache::ScopedEntryPtr
, bool)>
36 typedef base::Callback
<void(scoped_ptr
<ServiceWorkerCacheMetadata
>)>
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 ServiceWorkerCacheResponse::ResponseType response_type
) {
54 switch (response_type
) {
55 case ServiceWorkerCacheResponse::BASIC_TYPE
:
56 return blink::WebServiceWorkerResponseTypeBasic
;
57 case ServiceWorkerCacheResponse::CORS_TYPE
:
58 return blink::WebServiceWorkerResponseTypeCORS
;
59 case ServiceWorkerCacheResponse::DEFAULT_TYPE
:
60 return blink::WebServiceWorkerResponseTypeDefault
;
61 case ServiceWorkerCacheResponse::ERROR_TYPE
:
62 return blink::WebServiceWorkerResponseTypeError
;
63 case ServiceWorkerCacheResponse::OPAQUE_TYPE
:
64 return blink::WebServiceWorkerResponseTypeOpaque
;
67 return blink::WebServiceWorkerResponseTypeOpaque
;
70 ServiceWorkerCacheResponse::ResponseType
WebResponseTypeToProtoResponseType(
71 blink::WebServiceWorkerResponseType response_type
) {
72 switch (response_type
) {
73 case blink::WebServiceWorkerResponseTypeBasic
:
74 return ServiceWorkerCacheResponse::BASIC_TYPE
;
75 case blink::WebServiceWorkerResponseTypeCORS
:
76 return ServiceWorkerCacheResponse::CORS_TYPE
;
77 case blink::WebServiceWorkerResponseTypeDefault
:
78 return ServiceWorkerCacheResponse::DEFAULT_TYPE
;
79 case blink::WebServiceWorkerResponseTypeError
:
80 return ServiceWorkerCacheResponse::ERROR_TYPE
;
81 case blink::WebServiceWorkerResponseTypeOpaque
:
82 return ServiceWorkerCacheResponse::OPAQUE_TYPE
;
85 return ServiceWorkerCacheResponse::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
,
98 bool VaryMatches(const ServiceWorkerHeaderMap
& request
,
99 const ServiceWorkerHeaderMap
& cached_request
,
100 const ServiceWorkerHeaderMap
& response
) {
101 ServiceWorkerHeaderMap::const_iterator vary_iter
= response
.find("vary");
102 if (vary_iter
== response
.end())
105 std::vector
<std::string
> vary_keys
;
106 Tokenize(vary_iter
->second
, ",", &vary_keys
);
107 for (std::vector
<std::string
>::const_iterator it
= vary_keys
.begin();
108 it
!= vary_keys
.end();
111 base::TrimWhitespaceASCII(*it
, base::TRIM_ALL
, &trimmed
);
115 ServiceWorkerHeaderMap::const_iterator request_iter
= request
.find(trimmed
);
116 ServiceWorkerHeaderMap::const_iterator cached_request_iter
=
117 cached_request
.find(trimmed
);
119 // If the header exists in one but not the other, no match.
120 if ((request_iter
== request
.end()) !=
121 (cached_request_iter
== cached_request
.end()))
124 // If the header exists in one, it exists in both. Verify that the values
126 if (request_iter
!= request
.end() &&
127 request_iter
->second
!= cached_request_iter
->second
)
135 void ReadMetadata(disk_cache::Entry
* entry
, const MetadataCallback
& callback
) {
138 scoped_refptr
<net::IOBufferWithSize
> buffer(
139 new net::IOBufferWithSize(entry
->GetDataSize(INDEX_HEADERS
)));
141 net::CompletionCallback read_header_callback
=
142 base::Bind(ReadMetadataDidReadMetadata
, entry
, callback
, buffer
);
144 int read_rv
= entry
->ReadData(
145 INDEX_HEADERS
, 0, buffer
.get(), buffer
->size(),
146 tracked_objects::ScopedTracker::TrackCallback(
147 FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 ReadMetadata"),
148 read_header_callback
));
150 if (read_rv
!= net::ERR_IO_PENDING
)
151 read_header_callback
.Run(read_rv
);
154 void ReadMetadataDidReadMetadata(
155 disk_cache::Entry
* entry
,
156 const MetadataCallback
& callback
,
157 const scoped_refptr
<net::IOBufferWithSize
>& buffer
,
159 if (rv
!= buffer
->size()) {
160 callback
.Run(scoped_ptr
<ServiceWorkerCacheMetadata
>());
164 scoped_ptr
<ServiceWorkerCacheMetadata
> metadata(
165 new ServiceWorkerCacheMetadata());
167 if (!metadata
->ParseFromArray(buffer
->data(), buffer
->size())) {
168 callback
.Run(scoped_ptr
<ServiceWorkerCacheMetadata
>());
172 callback
.Run(metadata
.Pass());
177 // Streams data from a blob and writes it to a given disk_cache::Entry.
178 class ServiceWorkerCache::BlobReader
: public net::URLRequest::Delegate
{
180 typedef base::Callback
<void(disk_cache::ScopedEntryPtr
, bool)>
181 EntryAndBoolCallback
;
184 : cache_entry_offset_(0),
185 buffer_(new net::IOBufferWithSize(kBufferSize
)),
186 weak_ptr_factory_(this) {}
188 // |entry| is passed to the callback once complete.
189 void StreamBlobToCache(disk_cache::ScopedEntryPtr entry
,
190 net::URLRequestContext
* request_context
,
191 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
192 const EntryAndBoolCallback
& callback
) {
194 entry_
= entry
.Pass();
195 callback_
= callback
;
196 blob_request_
= storage::BlobProtocolHandler::CreateBlobRequest(
197 blob_data_handle
.Pass(), request_context
, this);
198 blob_request_
->Start();
201 // net::URLRequest::Delegate overrides for reading blobs.
202 void OnReceivedRedirect(net::URLRequest
* request
,
203 const net::RedirectInfo
& redirect_info
,
204 bool* defer_redirect
) override
{
207 void OnAuthRequired(net::URLRequest
* request
,
208 net::AuthChallengeInfo
* auth_info
) override
{
211 void OnCertificateRequested(
212 net::URLRequest
* request
,
213 net::SSLCertRequestInfo
* cert_request_info
) override
{
216 void OnSSLCertificateError(net::URLRequest
* request
,
217 const net::SSLInfo
& ssl_info
,
218 bool fatal
) override
{
221 void OnBeforeNetworkStart(net::URLRequest
* request
, bool* defer
) override
{
225 void OnResponseStarted(net::URLRequest
* request
) override
{
226 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
227 tracked_objects::ScopedTracker
tracking_profile(
228 FROM_HERE_WITH_EXPLICIT_FUNCTION(
229 "423948 ServiceWorkerCache::BlobReader::OnResponseStarted"));
231 if (!request
->status().is_success()) {
232 callback_
.Run(entry_
.Pass(), false);
238 virtual void ReadFromBlob() {
241 blob_request_
->Read(buffer_
.get(), buffer_
->size(), &bytes_read
);
243 OnReadCompleted(blob_request_
.get(), bytes_read
);
246 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{
247 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
248 tracked_objects::ScopedTracker
tracking_profile(
249 FROM_HERE_WITH_EXPLICIT_FUNCTION(
250 "423948 ServiceWorkerCache::BlobReader::OnReadCompleted"));
252 if (!request
->status().is_success()) {
253 callback_
.Run(entry_
.Pass(), false);
257 if (bytes_read
== 0) {
258 callback_
.Run(entry_
.Pass(), true);
262 net::CompletionCallback cache_write_callback
=
263 base::Bind(&BlobReader::DidWriteDataToEntry
,
264 weak_ptr_factory_
.GetWeakPtr(),
267 int rv
= entry_
->WriteData(INDEX_RESPONSE_BODY
,
271 cache_write_callback
,
272 true /* truncate */);
273 if (rv
!= net::ERR_IO_PENDING
)
274 cache_write_callback
.Run(rv
);
277 void DidWriteDataToEntry(int expected_bytes
, int rv
) {
278 if (rv
!= expected_bytes
) {
279 callback_
.Run(entry_
.Pass(), false);
283 cache_entry_offset_
+= rv
;
288 int cache_entry_offset_
;
289 disk_cache::ScopedEntryPtr entry_
;
290 scoped_ptr
<net::URLRequest
> blob_request_
;
291 EntryAndBoolCallback callback_
;
292 scoped_refptr
<net::IOBufferWithSize
> buffer_
;
293 base::WeakPtrFactory
<BlobReader
> weak_ptr_factory_
;
296 // The state needed to pass between ServiceWorkerCache::Keys callbacks.
297 struct ServiceWorkerCache::KeysContext
{
298 KeysContext(const ServiceWorkerCache::RequestsCallback
& callback
)
299 : original_callback(callback
),
300 out_keys(new ServiceWorkerCache::Requests()),
301 enumerated_entry(NULL
) {}
304 for (size_t i
= 0, max
= entries
.size(); i
< max
; ++i
)
306 if (enumerated_entry
)
307 enumerated_entry
->Close();
310 // The callback passed to the Keys() function.
311 ServiceWorkerCache::RequestsCallback original_callback
;
313 // The vector of open entries in the backend.
316 // The output of the Keys function.
317 scoped_ptr
<ServiceWorkerCache::Requests
> out_keys
;
319 // Used for enumerating cache entries.
320 scoped_ptr
<disk_cache::Backend::Iterator
> backend_iterator
;
321 disk_cache::Entry
* enumerated_entry
;
323 DISALLOW_COPY_AND_ASSIGN(KeysContext
);
326 struct ServiceWorkerCache::MatchContext
{
327 MatchContext(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
328 const ServiceWorkerCache::ResponseCallback
& callback
,
329 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
)
330 : request(request
.Pass()),
331 original_callback(callback
),
332 blob_storage_context(blob_storage_context
),
334 total_bytes_read(0) {}
342 scoped_ptr
<ServiceWorkerFetchRequest
> request
;
343 ServiceWorkerCache::ResponseCallback original_callback
;
344 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
;
345 disk_cache::Entry
* entry
;
348 scoped_ptr
<ServiceWorkerResponse
> response
;
349 scoped_ptr
<storage::BlobDataBuilder
> blob_data
;
351 // For reading the cache entry data into a blob.
352 scoped_refptr
<net::IOBufferWithSize
> response_body_buffer
;
353 size_t total_bytes_read
;
355 DISALLOW_COPY_AND_ASSIGN(MatchContext
);
358 // The state needed to pass between ServiceWorkerCache::Put callbacks.
359 struct ServiceWorkerCache::PutContext
{
362 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
363 scoped_ptr
<ServiceWorkerResponse
> response
,
364 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
365 const ServiceWorkerCache::ResponseCallback
& callback
,
366 net::URLRequestContext
* request_context
,
367 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
)
369 request(request
.Pass()),
370 response(response
.Pass()),
371 blob_data_handle(blob_data_handle
.Pass()),
373 request_context(request_context
),
374 quota_manager_proxy(quota_manager_proxy
),
378 cache_entry
->Close();
381 // Input parameters to the Put function.
383 scoped_ptr
<ServiceWorkerFetchRequest
> request
;
384 scoped_ptr
<ServiceWorkerResponse
> response
;
385 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
386 ServiceWorkerCache::ResponseCallback callback
;
387 net::URLRequestContext
* request_context
;
388 scoped_refptr
<storage::QuotaManagerProxy
> quota_manager_proxy
;
390 // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
392 disk_cache::Entry
* cache_entry
;
394 // The BlobDataHandle for the output ServiceWorkerResponse.
395 scoped_ptr
<storage::BlobDataHandle
> out_blob_data_handle
;
397 DISALLOW_COPY_AND_ASSIGN(PutContext
);
401 scoped_refptr
<ServiceWorkerCache
> ServiceWorkerCache::CreateMemoryCache(
403 net::URLRequestContext
* request_context
,
404 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
405 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
406 return make_scoped_refptr(new ServiceWorkerCache(origin
,
414 scoped_refptr
<ServiceWorkerCache
> ServiceWorkerCache::CreatePersistentCache(
416 const base::FilePath
& path
,
417 net::URLRequestContext
* request_context
,
418 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
419 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
420 return make_scoped_refptr(new ServiceWorkerCache(
421 origin
, path
, request_context
, quota_manager_proxy
, blob_context
));
424 ServiceWorkerCache::~ServiceWorkerCache() {
427 base::WeakPtr
<ServiceWorkerCache
> ServiceWorkerCache::AsWeakPtr() {
428 return weak_ptr_factory_
.GetWeakPtr();
431 void ServiceWorkerCache::Put(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
432 scoped_ptr
<ServiceWorkerResponse
> response
,
433 const ResponseCallback
& callback
) {
434 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
436 if (!response
->blob_uuid
.empty()) {
437 if (!blob_storage_context_
) {
438 callback
.Run(ErrorTypeStorage
, scoped_ptr
<ServiceWorkerResponse
>(),
439 scoped_ptr
<storage::BlobDataHandle
>());
443 blob_storage_context_
->GetBlobDataFromUUID(response
->blob_uuid
);
444 if (!blob_data_handle
) {
445 callback
.Run(ErrorTypeStorage
, scoped_ptr
<ServiceWorkerResponse
>(),
446 scoped_ptr
<storage::BlobDataHandle
>());
451 ResponseCallback pending_callback
=
452 base::Bind(&ServiceWorkerCache::PendingResponseCallback
,
453 weak_ptr_factory_
.GetWeakPtr(), callback
);
455 scoped_ptr
<PutContext
> put_context(new PutContext(
456 origin_
, request
.Pass(), response
.Pass(), blob_data_handle
.Pass(),
457 pending_callback
, request_context_
, quota_manager_proxy_
));
459 if (put_context
->blob_data_handle
) {
460 // Grab another handle to the blob for the callback response.
461 put_context
->out_blob_data_handle
=
462 blob_storage_context_
->GetBlobDataFromUUID(
463 put_context
->response
->blob_uuid
);
466 if (backend_state_
== BACKEND_UNINITIALIZED
)
469 scheduler_
->ScheduleOperation(base::Bind(&ServiceWorkerCache::PutImpl
,
470 weak_ptr_factory_
.GetWeakPtr(),
471 base::Passed(put_context
.Pass())));
474 void ServiceWorkerCache::Match(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
475 const ResponseCallback
& callback
) {
476 switch (backend_state_
) {
477 case BACKEND_UNINITIALIZED
:
481 callback
.Run(ErrorTypeStorage
, scoped_ptr
<ServiceWorkerResponse
>(),
482 scoped_ptr
<storage::BlobDataHandle
>());
489 ResponseCallback pending_callback
=
490 base::Bind(&ServiceWorkerCache::PendingResponseCallback
,
491 weak_ptr_factory_
.GetWeakPtr(), callback
);
492 scheduler_
->ScheduleOperation(
493 base::Bind(&ServiceWorkerCache::MatchImpl
, weak_ptr_factory_
.GetWeakPtr(),
494 base::Passed(request
.Pass()), pending_callback
));
497 void ServiceWorkerCache::Delete(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
498 const ErrorCallback
& callback
) {
499 switch (backend_state_
) {
500 case BACKEND_UNINITIALIZED
:
504 callback
.Run(ErrorTypeStorage
);
510 ErrorCallback pending_callback
=
511 base::Bind(&ServiceWorkerCache::PendingErrorCallback
,
512 weak_ptr_factory_
.GetWeakPtr(), callback
);
513 scheduler_
->ScheduleOperation(base::Bind(
514 &ServiceWorkerCache::DeleteImpl
, weak_ptr_factory_
.GetWeakPtr(),
515 base::Passed(request
.Pass()), pending_callback
));
518 void ServiceWorkerCache::Keys(const RequestsCallback
& callback
) {
519 switch (backend_state_
) {
520 case BACKEND_UNINITIALIZED
:
524 callback
.Run(ErrorTypeStorage
, scoped_ptr
<Requests
>());
531 RequestsCallback pending_callback
=
532 base::Bind(&ServiceWorkerCache::PendingRequestsCallback
,
533 weak_ptr_factory_
.GetWeakPtr(), callback
);
534 scheduler_
->ScheduleOperation(base::Bind(&ServiceWorkerCache::KeysImpl
,
535 weak_ptr_factory_
.GetWeakPtr(),
539 void ServiceWorkerCache::Close(const base::Closure
& callback
) {
540 DCHECK(backend_state_
!= BACKEND_CLOSED
)
541 << "Don't call ServiceWorkerCache::Close() twice.";
543 base::Closure pending_callback
=
544 base::Bind(&ServiceWorkerCache::PendingClosure
,
545 weak_ptr_factory_
.GetWeakPtr(), callback
);
547 scheduler_
->ScheduleOperation(base::Bind(&ServiceWorkerCache::CloseImpl
,
548 weak_ptr_factory_
.GetWeakPtr(),
552 int64
ServiceWorkerCache::MemoryBackedSize() const {
553 if (backend_state_
!= BACKEND_OPEN
|| !memory_only_
)
556 scoped_ptr
<disk_cache::Backend::Iterator
> backend_iter
=
557 backend_
->CreateIterator();
558 disk_cache::Entry
* entry
= nullptr;
562 std::vector
<disk_cache::Entry
*> entries
;
564 while ((rv
= backend_iter
->OpenNextEntry(
565 &entry
, base::Bind(NotReachedCompletionCallback
))) == net::OK
) {
566 entries
.push_back(entry
); // Open the entries without mutating them.
569 net::ERR_IO_PENDING
); // Expect all memory ops to be synchronous.
571 for (disk_cache::Entry
* entry
: entries
) {
572 sum
+= entry
->GetDataSize(INDEX_HEADERS
) +
573 entry
->GetDataSize(INDEX_RESPONSE_BODY
);
580 ServiceWorkerCache::ServiceWorkerCache(
582 const base::FilePath
& path
,
583 net::URLRequestContext
* request_context
,
584 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
585 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
588 request_context_(request_context
),
589 quota_manager_proxy_(quota_manager_proxy
),
590 blob_storage_context_(blob_context
),
591 backend_state_(BACKEND_UNINITIALIZED
),
592 scheduler_(new ServiceWorkerCacheScheduler()),
593 initializing_(false),
594 memory_only_(path
.empty()),
595 weak_ptr_factory_(this) {
598 void ServiceWorkerCache::MatchImpl(
599 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
600 const ResponseCallback
& callback
) {
601 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
602 if (backend_state_
!= BACKEND_OPEN
) {
603 callback
.Run(ErrorTypeStorage
, scoped_ptr
<ServiceWorkerResponse
>(),
604 scoped_ptr
<storage::BlobDataHandle
>());
608 scoped_ptr
<MatchContext
> match_context(
609 new MatchContext(request
.Pass(), callback
, blob_storage_context_
));
611 disk_cache::Entry
** entry_ptr
= &match_context
->entry
;
612 ServiceWorkerFetchRequest
* request_ptr
= match_context
->request
.get();
614 net::CompletionCallback open_entry_callback
= base::Bind(
615 &ServiceWorkerCache::MatchDidOpenEntry
, weak_ptr_factory_
.GetWeakPtr(),
616 base::Passed(match_context
.Pass()));
618 int rv
= backend_
->OpenEntry(request_ptr
->url
.spec(), entry_ptr
,
619 open_entry_callback
);
620 if (rv
!= net::ERR_IO_PENDING
)
621 open_entry_callback
.Run(rv
);
624 void ServiceWorkerCache::MatchDidOpenEntry(
625 scoped_ptr
<MatchContext
> match_context
,
628 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeNotFound
,
629 scoped_ptr
<ServiceWorkerResponse
>(),
630 scoped_ptr
<storage::BlobDataHandle
>());
634 // Copy the entry pointer before passing it in base::Bind.
635 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
636 DCHECK(tmp_entry_ptr
);
638 MetadataCallback headers_callback
= base::Bind(
639 &ServiceWorkerCache::MatchDidReadMetadata
, weak_ptr_factory_
.GetWeakPtr(),
640 base::Passed(match_context
.Pass()));
642 ReadMetadata(tmp_entry_ptr
, headers_callback
);
645 void ServiceWorkerCache::MatchDidReadMetadata(
646 scoped_ptr
<MatchContext
> match_context
,
647 scoped_ptr
<ServiceWorkerCacheMetadata
> metadata
) {
649 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
650 scoped_ptr
<ServiceWorkerResponse
>(),
651 scoped_ptr
<storage::BlobDataHandle
>());
655 match_context
->response
.reset(new ServiceWorkerResponse(
656 match_context
->request
->url
, metadata
->response().status_code(),
657 metadata
->response().status_text(),
658 ProtoResponseTypeToWebResponseType(metadata
->response().response_type()),
659 ServiceWorkerHeaderMap(), "", 0, GURL()));
661 ServiceWorkerResponse
* response
= match_context
->response
.get();
663 if (metadata
->response().has_url())
664 response
->url
= GURL(metadata
->response().url());
666 for (int i
= 0; i
< metadata
->response().headers_size(); ++i
) {
667 const ServiceWorkerCacheHeaderMap header
= metadata
->response().headers(i
);
668 DCHECK(header
.name().find('\0') == std::string::npos
);
669 DCHECK(header
.value().find('\0') == std::string::npos
);
670 response
->headers
.insert(std::make_pair(header
.name(), header
.value()));
673 ServiceWorkerHeaderMap cached_request_headers
;
674 for (int i
= 0; i
< metadata
->request().headers_size(); ++i
) {
675 const ServiceWorkerCacheHeaderMap header
= metadata
->request().headers(i
);
676 DCHECK(header
.name().find('\0') == std::string::npos
);
677 DCHECK(header
.value().find('\0') == std::string::npos
);
678 cached_request_headers
[header
.name()] = header
.value();
681 if (!VaryMatches(match_context
->request
->headers
, cached_request_headers
,
682 response
->headers
)) {
683 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeNotFound
,
684 scoped_ptr
<ServiceWorkerResponse
>(),
685 scoped_ptr
<storage::BlobDataHandle
>());
689 if (match_context
->entry
->GetDataSize(INDEX_RESPONSE_BODY
) == 0) {
690 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeOK
,
691 match_context
->response
.Pass(),
692 scoped_ptr
<storage::BlobDataHandle
>());
696 // Stream the response body into a blob.
697 if (!match_context
->blob_storage_context
) {
698 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
699 scoped_ptr
<ServiceWorkerResponse
>(),
700 scoped_ptr
<storage::BlobDataHandle
>());
704 response
->blob_uuid
= base::GenerateGUID();
706 match_context
->blob_data
.reset(
707 new storage::BlobDataBuilder(response
->blob_uuid
));
708 match_context
->response_body_buffer
= new net::IOBufferWithSize(kBufferSize
);
710 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
711 net::IOBufferWithSize
* response_body_buffer
=
712 match_context
->response_body_buffer
.get();
714 net::CompletionCallback read_callback
= base::Bind(
715 &ServiceWorkerCache::MatchDidReadResponseBodyData
,
716 weak_ptr_factory_
.GetWeakPtr(), base::Passed(match_context
.Pass()));
719 tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
, 0, response_body_buffer
,
720 response_body_buffer
->size(), read_callback
);
722 if (read_rv
!= net::ERR_IO_PENDING
)
723 read_callback
.Run(read_rv
);
726 void ServiceWorkerCache::MatchDidReadResponseBodyData(
727 scoped_ptr
<MatchContext
> match_context
,
729 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
730 tracked_objects::ScopedTracker
tracking_profile(
731 FROM_HERE_WITH_EXPLICIT_FUNCTION(
732 "422516 ServiceWorkerCache::MatchDidReadResponseBodyData"));
735 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
736 scoped_ptr
<ServiceWorkerResponse
>(),
737 scoped_ptr
<storage::BlobDataHandle
>());
742 match_context
->response
->blob_uuid
= match_context
->blob_data
->uuid();
743 match_context
->response
->blob_size
= match_context
->total_bytes_read
;
744 MatchDoneWithBody(match_context
.Pass());
748 // TODO(jkarlin): This copying of the the entire cache response into memory is
749 // awful. Create a new interface around SimpleCache that provides access the
750 // data directly from the file. See bug http://crbug.com/403493.
751 match_context
->blob_data
->AppendData(
752 match_context
->response_body_buffer
->data(), rv
);
753 match_context
->total_bytes_read
+= rv
;
754 int total_bytes_read
= match_context
->total_bytes_read
;
756 // Grab some pointers before passing match_context in bind.
757 net::IOBufferWithSize
* buffer
= match_context
->response_body_buffer
.get();
758 disk_cache::Entry
* tmp_entry_ptr
= match_context
->entry
;
760 net::CompletionCallback read_callback
= base::Bind(
761 &ServiceWorkerCache::MatchDidReadResponseBodyData
,
762 weak_ptr_factory_
.GetWeakPtr(), base::Passed(match_context
.Pass()));
764 int read_rv
= tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
, total_bytes_read
,
765 buffer
, buffer
->size(), read_callback
);
767 if (read_rv
!= net::ERR_IO_PENDING
)
768 read_callback
.Run(read_rv
);
771 void ServiceWorkerCache::MatchDoneWithBody(
772 scoped_ptr
<MatchContext
> match_context
) {
773 if (!match_context
->blob_storage_context
) {
774 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
775 scoped_ptr
<ServiceWorkerResponse
>(),
776 scoped_ptr
<storage::BlobDataHandle
>());
780 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle(
781 match_context
->blob_storage_context
->AddFinishedBlob(
782 match_context
->blob_data
.get()));
784 match_context
->original_callback
.Run(ServiceWorkerCache::ErrorTypeOK
,
785 match_context
->response
.Pass(),
786 blob_data_handle
.Pass());
789 void ServiceWorkerCache::PutImpl(scoped_ptr
<PutContext
> put_context
) {
790 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
791 if (backend_state_
!= BACKEND_OPEN
) {
792 put_context
->callback
.Run(ErrorTypeStorage
,
793 scoped_ptr
<ServiceWorkerResponse
>(),
794 scoped_ptr
<storage::BlobDataHandle
>());
798 scoped_ptr
<ServiceWorkerFetchRequest
> request_copy(
799 new ServiceWorkerFetchRequest(*put_context
->request
));
801 DeleteImpl(request_copy
.Pass(), base::Bind(&ServiceWorkerCache::PutDidDelete
,
802 weak_ptr_factory_
.GetWeakPtr(),
803 base::Passed(put_context
.Pass())));
806 void ServiceWorkerCache::PutDidDelete(scoped_ptr
<PutContext
> put_context
,
807 ErrorType delete_error
) {
808 if (backend_state_
!= BACKEND_OPEN
) {
809 put_context
->callback
.Run(ErrorTypeStorage
,
810 scoped_ptr
<ServiceWorkerResponse
>(),
811 scoped_ptr
<storage::BlobDataHandle
>());
815 disk_cache::Entry
** entry_ptr
= &put_context
->cache_entry
;
816 ServiceWorkerFetchRequest
* request_ptr
= put_context
->request
.get();
817 disk_cache::Backend
* backend_ptr
= backend_
.get();
819 net::CompletionCallback create_entry_callback
= base::Bind(
820 &ServiceWorkerCache::PutDidCreateEntry
, weak_ptr_factory_
.GetWeakPtr(),
821 base::Passed(put_context
.Pass()));
823 int create_rv
= backend_ptr
->CreateEntry(
824 request_ptr
->url
.spec(), entry_ptr
, create_entry_callback
);
826 if (create_rv
!= net::ERR_IO_PENDING
)
827 create_entry_callback
.Run(create_rv
);
830 void ServiceWorkerCache::PutDidCreateEntry(scoped_ptr
<PutContext
> put_context
,
833 put_context
->callback
.Run(ServiceWorkerCache::ErrorTypeExists
,
834 scoped_ptr
<ServiceWorkerResponse
>(),
835 scoped_ptr
<storage::BlobDataHandle
>());
839 DCHECK(put_context
->cache_entry
);
841 ServiceWorkerCacheMetadata metadata
;
842 ServiceWorkerCacheRequest
* request_metadata
= metadata
.mutable_request();
843 request_metadata
->set_method(put_context
->request
->method
);
844 for (ServiceWorkerHeaderMap::const_iterator it
=
845 put_context
->request
->headers
.begin();
846 it
!= put_context
->request
->headers
.end();
848 DCHECK(it
->first
.find('\0') == std::string::npos
);
849 DCHECK(it
->second
.find('\0') == std::string::npos
);
850 ServiceWorkerCacheHeaderMap
* header_map
= request_metadata
->add_headers();
851 header_map
->set_name(it
->first
);
852 header_map
->set_value(it
->second
);
855 ServiceWorkerCacheResponse
* response_metadata
= metadata
.mutable_response();
856 response_metadata
->set_status_code(put_context
->response
->status_code
);
857 response_metadata
->set_status_text(put_context
->response
->status_text
);
858 response_metadata
->set_response_type(
859 WebResponseTypeToProtoResponseType(put_context
->response
->response_type
));
860 response_metadata
->set_url(put_context
->response
->url
.spec());
861 for (ServiceWorkerHeaderMap::const_iterator it
=
862 put_context
->response
->headers
.begin();
863 it
!= put_context
->response
->headers
.end();
865 DCHECK(it
->first
.find('\0') == std::string::npos
);
866 DCHECK(it
->second
.find('\0') == std::string::npos
);
867 ServiceWorkerCacheHeaderMap
* header_map
= response_metadata
->add_headers();
868 header_map
->set_name(it
->first
);
869 header_map
->set_value(it
->second
);
872 scoped_ptr
<std::string
> serialized(new std::string());
873 if (!metadata
.SerializeToString(serialized
.get())) {
874 put_context
->callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
875 scoped_ptr
<ServiceWorkerResponse
>(),
876 scoped_ptr
<storage::BlobDataHandle
>());
880 scoped_refptr
<net::StringIOBuffer
> buffer(
881 new net::StringIOBuffer(serialized
.Pass()));
883 // Get a temporary copy of the entry pointer before passing it in base::Bind.
884 disk_cache::Entry
* tmp_entry_ptr
= put_context
->cache_entry
;
886 net::CompletionCallback write_headers_callback
= base::Bind(
887 &ServiceWorkerCache::PutDidWriteHeaders
, weak_ptr_factory_
.GetWeakPtr(),
888 base::Passed(put_context
.Pass()), buffer
->size());
890 rv
= tmp_entry_ptr
->WriteData(INDEX_HEADERS
,
894 write_headers_callback
,
895 true /* truncate */);
897 if (rv
!= net::ERR_IO_PENDING
)
898 write_headers_callback
.Run(rv
);
901 void ServiceWorkerCache::PutDidWriteHeaders(scoped_ptr
<PutContext
> put_context
,
904 if (rv
!= expected_bytes
) {
905 put_context
->cache_entry
->Doom();
906 put_context
->callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
907 scoped_ptr
<ServiceWorkerResponse
>(),
908 scoped_ptr
<storage::BlobDataHandle
>());
912 // The metadata is written, now for the response content. The data is streamed
913 // from the blob into the cache entry.
915 if (put_context
->response
->blob_uuid
.empty()) {
916 if (put_context
->quota_manager_proxy
.get()) {
917 put_context
->quota_manager_proxy
->NotifyStorageModified(
918 storage::QuotaClient::kServiceWorkerCache
,
920 storage::kStorageTypeTemporary
,
921 put_context
->cache_entry
->GetDataSize(INDEX_HEADERS
));
924 put_context
->callback
.Run(ServiceWorkerCache::ErrorTypeOK
,
925 put_context
->response
.Pass(),
926 scoped_ptr
<storage::BlobDataHandle
>());
930 DCHECK(put_context
->blob_data_handle
);
932 disk_cache::ScopedEntryPtr
entry(put_context
->cache_entry
);
933 put_context
->cache_entry
= NULL
;
934 scoped_ptr
<BlobReader
> reader(new BlobReader());
935 BlobReader
* reader_ptr
= reader
.get();
937 // Grab some pointers before passing put_context in Bind.
938 net::URLRequestContext
* request_context
= put_context
->request_context
;
939 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
=
940 put_context
->blob_data_handle
.Pass();
942 reader_ptr
->StreamBlobToCache(
943 entry
.Pass(), request_context
, blob_data_handle
.Pass(),
944 base::Bind(&ServiceWorkerCache::PutDidWriteBlobToCache
,
945 weak_ptr_factory_
.GetWeakPtr(),
946 base::Passed(put_context
.Pass()),
947 base::Passed(reader
.Pass())));
950 void ServiceWorkerCache::PutDidWriteBlobToCache(
951 scoped_ptr
<PutContext
> put_context
,
952 scoped_ptr
<BlobReader
> blob_reader
,
953 disk_cache::ScopedEntryPtr entry
,
956 put_context
->cache_entry
= entry
.release();
959 put_context
->cache_entry
->Doom();
960 put_context
->callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
961 scoped_ptr
<ServiceWorkerResponse
>(),
962 scoped_ptr
<storage::BlobDataHandle
>());
966 if (put_context
->quota_manager_proxy
.get()) {
967 put_context
->quota_manager_proxy
->NotifyStorageModified(
968 storage::QuotaClient::kServiceWorkerCache
,
970 storage::kStorageTypeTemporary
,
971 put_context
->cache_entry
->GetDataSize(INDEX_HEADERS
) +
972 put_context
->cache_entry
->GetDataSize(INDEX_RESPONSE_BODY
));
975 put_context
->callback
.Run(ServiceWorkerCache::ErrorTypeOK
,
976 put_context
->response
.Pass(),
977 put_context
->out_blob_data_handle
.Pass());
980 void ServiceWorkerCache::DeleteImpl(
981 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
982 const ErrorCallback
& callback
) {
983 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
984 if (backend_state_
!= BACKEND_OPEN
) {
985 callback
.Run(ErrorTypeStorage
);
988 scoped_ptr
<disk_cache::Entry
*> entry(new disk_cache::Entry
*);
990 disk_cache::Entry
** entry_ptr
= entry
.get();
992 ServiceWorkerFetchRequest
* request_ptr
= request
.get();
994 net::CompletionCallback open_entry_callback
= base::Bind(
995 &ServiceWorkerCache::DeleteDidOpenEntry
, weak_ptr_factory_
.GetWeakPtr(),
996 origin_
, base::Passed(request
.Pass()), callback
,
997 base::Passed(entry
.Pass()), quota_manager_proxy_
);
999 int rv
= backend_
->OpenEntry(request_ptr
->url
.spec(), entry_ptr
,
1000 open_entry_callback
);
1001 if (rv
!= net::ERR_IO_PENDING
)
1002 open_entry_callback
.Run(rv
);
1005 void ServiceWorkerCache::DeleteDidOpenEntry(
1007 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
1008 const ServiceWorkerCache::ErrorCallback
& callback
,
1009 scoped_ptr
<disk_cache::Entry
*> entry_ptr
,
1010 const scoped_refptr
<storage::QuotaManagerProxy
>& quota_manager_proxy
,
1012 if (rv
!= net::OK
) {
1013 callback
.Run(ServiceWorkerCache::ErrorTypeNotFound
);
1018 disk_cache::ScopedEntryPtr
entry(*entry_ptr
);
1020 if (quota_manager_proxy
.get()) {
1021 quota_manager_proxy
->NotifyStorageModified(
1022 storage::QuotaClient::kServiceWorkerCache
, origin
,
1023 storage::kStorageTypeTemporary
,
1024 -1 * (entry
->GetDataSize(INDEX_HEADERS
) +
1025 entry
->GetDataSize(INDEX_RESPONSE_BODY
)));
1029 callback
.Run(ServiceWorkerCache::ErrorTypeOK
);
1032 void ServiceWorkerCache::KeysImpl(const RequestsCallback
& callback
) {
1033 DCHECK(backend_state_
!= BACKEND_UNINITIALIZED
);
1034 if (backend_state_
!= BACKEND_OPEN
) {
1035 callback
.Run(ErrorTypeStorage
, scoped_ptr
<Requests
>());
1039 // 1. Iterate through all of the entries, open them, and add them to a vector.
1040 // 2. For each open entry:
1041 // 2.1. Read the headers into a protobuf.
1042 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
1043 // 2.3. Push the response into a vector of requests to be returned.
1044 // 3. Return the vector of requests (keys).
1046 // The entries have to be loaded into a vector first because enumeration loops
1047 // forever if you read data from a cache entry while enumerating.
1049 scoped_ptr
<KeysContext
> keys_context(new KeysContext(callback
));
1051 keys_context
->backend_iterator
= backend_
->CreateIterator();
1052 disk_cache::Backend::Iterator
& iterator
= *keys_context
->backend_iterator
;
1053 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
1055 net::CompletionCallback open_entry_callback
= base::Bind(
1056 &ServiceWorkerCache::KeysDidOpenNextEntry
, weak_ptr_factory_
.GetWeakPtr(),
1057 base::Passed(keys_context
.Pass()));
1059 int rv
= iterator
.OpenNextEntry(enumerated_entry
, open_entry_callback
);
1061 if (rv
!= net::ERR_IO_PENDING
)
1062 open_entry_callback
.Run(rv
);
1065 void ServiceWorkerCache::KeysDidOpenNextEntry(
1066 scoped_ptr
<KeysContext
> keys_context
,
1068 if (rv
== net::ERR_FAILED
) {
1069 DCHECK(!keys_context
->enumerated_entry
);
1070 // Enumeration is complete, extract the requests from the entries.
1071 Entries::iterator iter
= keys_context
->entries
.begin();
1072 KeysProcessNextEntry(keys_context
.Pass(), iter
);
1077 keys_context
->original_callback
.Run(ErrorTypeStorage
,
1078 scoped_ptr
<Requests
>());
1082 if (backend_state_
!= BACKEND_OPEN
) {
1083 keys_context
->original_callback
.Run(ErrorTypeNotFound
,
1084 scoped_ptr
<Requests
>());
1089 keys_context
->entries
.push_back(keys_context
->enumerated_entry
);
1090 keys_context
->enumerated_entry
= NULL
;
1092 // Enumerate the next entry.
1093 disk_cache::Backend::Iterator
& iterator
= *keys_context
->backend_iterator
;
1094 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
1095 net::CompletionCallback open_entry_callback
= base::Bind(
1096 &ServiceWorkerCache::KeysDidOpenNextEntry
, weak_ptr_factory_
.GetWeakPtr(),
1097 base::Passed(keys_context
.Pass()));
1099 rv
= iterator
.OpenNextEntry(enumerated_entry
, open_entry_callback
);
1101 if (rv
!= net::ERR_IO_PENDING
)
1102 open_entry_callback
.Run(rv
);
1105 void ServiceWorkerCache::KeysProcessNextEntry(
1106 scoped_ptr
<KeysContext
> keys_context
,
1107 const Entries::iterator
& iter
) {
1108 if (iter
== keys_context
->entries
.end()) {
1109 // All done. Return all of the keys.
1110 keys_context
->original_callback
.Run(ErrorTypeOK
,
1111 keys_context
->out_keys
.Pass());
1115 ReadMetadata(*iter
, base::Bind(&ServiceWorkerCache::KeysDidReadMetadata
,
1116 weak_ptr_factory_
.GetWeakPtr(),
1117 base::Passed(keys_context
.Pass()), iter
));
1120 void ServiceWorkerCache::KeysDidReadMetadata(
1121 scoped_ptr
<KeysContext
> keys_context
,
1122 const Entries::iterator
& iter
,
1123 scoped_ptr
<ServiceWorkerCacheMetadata
> metadata
) {
1124 disk_cache::Entry
* entry
= *iter
;
1127 keys_context
->out_keys
->push_back(
1128 ServiceWorkerFetchRequest(GURL(entry
->GetKey()),
1129 metadata
->request().method(),
1130 ServiceWorkerHeaderMap(),
1134 ServiceWorkerHeaderMap
& req_headers
=
1135 keys_context
->out_keys
->back().headers
;
1137 for (int i
= 0; i
< metadata
->request().headers_size(); ++i
) {
1138 const ServiceWorkerCacheHeaderMap header
= metadata
->request().headers(i
);
1139 DCHECK(header
.name().find('\0') == std::string::npos
);
1140 DCHECK(header
.value().find('\0') == std::string::npos
);
1141 req_headers
.insert(std::make_pair(header
.name(), header
.value()));
1147 KeysProcessNextEntry(keys_context
.Pass(), iter
+ 1);
1150 void ServiceWorkerCache::CloseImpl(const base::Closure
& callback
) {
1151 DCHECK(backend_state_
!= BACKEND_CLOSED
);
1153 backend_state_
= BACKEND_CLOSED
;
1158 void ServiceWorkerCache::CreateBackend(const ErrorCallback
& callback
) {
1161 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
1162 net::CacheType cache_type
= memory_only_
? net::MEMORY_CACHE
: net::APP_CACHE
;
1164 scoped_ptr
<ScopedBackendPtr
> backend_ptr(new ScopedBackendPtr());
1166 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
1167 ScopedBackendPtr
* backend
= backend_ptr
.get();
1169 net::CompletionCallback create_cache_callback
=
1170 base::Bind(&ServiceWorkerCache::CreateBackendDidCreate
,
1171 weak_ptr_factory_
.GetWeakPtr(), callback
,
1172 base::Passed(backend_ptr
.Pass()));
1174 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
1175 // has for disk caches.
1176 int rv
= disk_cache::CreateCacheBackend(
1178 net::CACHE_BACKEND_SIMPLE
,
1182 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE
).get(),
1185 create_cache_callback
);
1186 if (rv
!= net::ERR_IO_PENDING
)
1187 create_cache_callback
.Run(rv
);
1190 void ServiceWorkerCache::CreateBackendDidCreate(
1191 const ServiceWorkerCache::ErrorCallback
& callback
,
1192 scoped_ptr
<ScopedBackendPtr
> backend_ptr
,
1194 if (rv
!= net::OK
) {
1195 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
);
1199 backend_
= backend_ptr
->Pass();
1200 callback
.Run(ServiceWorkerCache::ErrorTypeOK
);
1203 void ServiceWorkerCache::InitBackend() {
1204 DCHECK(backend_state_
== BACKEND_UNINITIALIZED
);
1209 DCHECK(scheduler_
->Empty());
1210 initializing_
= true;
1212 scheduler_
->ScheduleOperation(base::Bind(
1213 &ServiceWorkerCache::CreateBackend
, weak_ptr_factory_
.GetWeakPtr(),
1214 base::Bind(&ServiceWorkerCache::InitDone
,
1215 weak_ptr_factory_
.GetWeakPtr())));
1218 void ServiceWorkerCache::InitDone(ErrorType error
) {
1219 initializing_
= false;
1220 backend_state_
= (error
== ErrorTypeOK
&& backend_
&&
1221 backend_state_
== BACKEND_UNINITIALIZED
)
1224 scheduler_
->CompleteOperationAndRunNext();
1227 void ServiceWorkerCache::PendingClosure(const base::Closure
& callback
) {
1228 base::WeakPtr
<ServiceWorkerCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1232 scheduler_
->CompleteOperationAndRunNext();
1235 void ServiceWorkerCache::PendingErrorCallback(const ErrorCallback
& callback
,
1237 base::WeakPtr
<ServiceWorkerCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1239 callback
.Run(error
);
1241 scheduler_
->CompleteOperationAndRunNext();
1244 void ServiceWorkerCache::PendingResponseCallback(
1245 const ResponseCallback
& callback
,
1247 scoped_ptr
<ServiceWorkerResponse
> response
,
1248 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
) {
1249 base::WeakPtr
<ServiceWorkerCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1251 callback
.Run(error
, response
.Pass(), blob_data_handle
.Pass());
1253 scheduler_
->CompleteOperationAndRunNext();
1256 void ServiceWorkerCache::PendingRequestsCallback(
1257 const RequestsCallback
& callback
,
1259 scoped_ptr
<Requests
> requests
) {
1260 base::WeakPtr
<ServiceWorkerCache
> cache
= weak_ptr_factory_
.GetWeakPtr();
1262 callback
.Run(error
, requests
.Pass());
1264 scheduler_
->CompleteOperationAndRunNext();
1267 } // namespace content