Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / cache_storage / cache_storage_cache.cc
blob4dae870722156f6d7a23e4cc2f9ae1911c089c62
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"
7 #include <string>
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"
30 namespace content {
32 namespace {
34 typedef base::Callback<void(bool)> BoolCallback;
35 typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
36 EntryBoolCallback;
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
42 // per-origin.
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) {
49 NOTREACHED();
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;
66 NOTREACHED();
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;
84 NOTREACHED();
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,
95 int rv);
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())
102 return true;
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) {
108 std::string trimmed;
109 base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &trimmed);
110 if (trimmed == "*")
111 return false;
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()))
120 return false;
122 // If the header exists in one, it exists in both. Verify that the values
123 // are equal.
124 if (request_iter != request.end() &&
125 request_iter->second != cached_request_iter->second)
126 return false;
129 return true;
132 void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
133 DCHECK(entry);
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,
152 int rv) {
153 if (rv != buffer->size()) {
154 callback.Run(scoped_ptr<CacheMetadata>());
155 return;
158 scoped_ptr<CacheMetadata> metadata(new CacheMetadata());
160 if (!metadata->ParseFromArray(buffer->data(), buffer->size())) {
161 callback.Run(scoped_ptr<CacheMetadata>());
162 return;
165 callback.Run(metadata.Pass());
168 } // namespace
170 // Streams data from a blob and writes it to a given disk_cache::Entry.
171 class CacheStorageCache::BlobReader : public net::URLRequest::Delegate {
172 public:
173 typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
174 EntryAndBoolCallback;
176 BlobReader()
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) {
186 DCHECK(entry);
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 {
198 NOTREACHED();
200 void OnAuthRequired(net::URLRequest* request,
201 net::AuthChallengeInfo* auth_info) override {
202 NOTREACHED();
204 void OnCertificateRequested(
205 net::URLRequest* request,
206 net::SSLCertRequestInfo* cert_request_info) override {
207 NOTREACHED();
209 void OnSSLCertificateError(net::URLRequest* request,
210 const net::SSLInfo& ssl_info,
211 bool fatal) override {
212 NOTREACHED();
214 void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override {
215 NOTREACHED();
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);
226 return;
228 ReadFromBlob();
231 virtual void ReadFromBlob() {
232 int bytes_read = 0;
233 bool done =
234 blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read);
235 if (done)
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);
247 return;
250 if (bytes_read == 0) {
251 callback_.Run(entry_.Pass(), true);
252 return;
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);
269 return;
272 cache_entry_offset_ += rv;
273 ReadFromBlob();
276 private:
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) {}
292 ~KeysContext() {
293 for (size_t i = 0, max = entries.size(); i < max; ++i)
294 entries[i]->Close();
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.
303 Entries entries;
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),
322 entry(nullptr),
323 total_bytes_read(0) {}
325 ~MatchContext() {
326 if (entry)
327 entry->Close();
330 // Input
331 scoped_ptr<ServiceWorkerFetchRequest> request;
332 CacheStorageCache::ResponseCallback original_callback;
333 base::WeakPtr<storage::BlobStorageContext> blob_storage_context;
334 disk_cache::Entry* entry;
336 // Output
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 {
349 PutContext(
350 const GURL& origin,
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)
357 : origin(origin),
358 request(request.Pass()),
359 response(response.Pass()),
360 blob_data_handle(blob_data_handle.Pass()),
361 callback(callback),
362 request_context(request_context),
363 quota_manager_proxy(quota_manager_proxy),
364 cache_entry(NULL) {}
365 ~PutContext() {
366 if (cache_entry)
367 cache_entry->Close();
370 // Input parameters to the Put function.
371 GURL origin;
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
380 // CreateEntry.
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);
389 // static
390 scoped_refptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache(
391 const GURL& origin,
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));
400 // static
401 scoped_refptr<CacheStorageCache> CacheStorageCache::CreatePersistentCache(
402 const GURL& origin,
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>());
427 return;
429 blob_data_handle =
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>());
434 return;
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)
454 InitBackend();
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:
465 InitBackend();
466 break;
467 case BACKEND_CLOSED:
468 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<ServiceWorkerResponse>(),
469 scoped_ptr<storage::BlobDataHandle>());
470 return;
471 case BACKEND_OPEN:
472 DCHECK(backend_);
473 break;
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:
488 InitBackend();
489 break;
490 case BACKEND_CLOSED:
491 callback.Run(ERROR_TYPE_STORAGE);
492 return;
493 case BACKEND_OPEN:
494 DCHECK(backend_);
495 break;
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:
508 InitBackend();
509 break;
510 case BACKEND_CLOSED:
511 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<Requests>());
512 return;
513 case BACKEND_OPEN:
514 DCHECK(backend_);
515 break;
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(),
523 pending_callback));
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(),
536 pending_callback));
539 int64 CacheStorageCache::MemoryBackedSize() const {
540 if (backend_state_ != BACKEND_OPEN || !memory_only_)
541 return 0;
543 scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
544 backend_->CreateIterator();
545 disk_cache::Entry* entry = nullptr;
547 int64 sum = 0;
549 std::vector<disk_cache::Entry*> entries;
550 int rv = net::OK;
551 while ((rv = backend_iter->OpenNextEntry(
552 &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
553 entries.push_back(entry); // Open the entries without mutating them.
555 DCHECK(rv !=
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);
561 entry->Close();
564 return sum;
567 CacheStorageCache::CacheStorageCache(
568 const GURL& origin,
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)
573 : origin_(origin),
574 path_(path),
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>());
591 return;
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,
612 int rv) {
613 if (rv != net::OK) {
614 match_context->original_callback.Run(
615 CacheStorageCache::ERROR_TYPE_NOT_FOUND,
616 scoped_ptr<ServiceWorkerResponse>(),
617 scoped_ptr<storage::BlobDataHandle>());
618 return;
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) {
635 if (!metadata) {
636 match_context->original_callback.Run(CacheStorageCache::ERROR_TYPE_STORAGE,
637 scoped_ptr<ServiceWorkerResponse>(),
638 scoped_ptr<storage::BlobDataHandle>());
639 return;
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>());
674 return;
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>());
681 return;
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>());
689 return;
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()));
706 int read_rv =
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,
716 int rv) {
717 if (rv < 0) {
718 match_context->original_callback.Run(CacheStorageCache::ERROR_TYPE_STORAGE,
719 scoped_ptr<ServiceWorkerResponse>(),
720 scoped_ptr<storage::BlobDataHandle>());
721 return;
724 if (rv == 0) {
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());
728 return;
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>());
760 return;
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>());
778 return;
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>());
795 return;
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,
814 int rv) {
815 if (rv != net::OK) {
816 put_context->callback.Run(CacheStorageCache::ERROR_TYPE_EXISTS,
817 scoped_ptr<ServiceWorkerResponse>(),
818 scoped_ptr<storage::BlobDataHandle>());
819 return;
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>());
858 return;
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,
880 int expected_bytes,
881 int rv) {
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>());
887 return;
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>());
904 return;
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,
931 bool success) {
932 DCHECK(entry);
933 put_context->cache_entry = entry.release();
935 if (!success) {
936 put_context->cache_entry->Doom();
937 put_context->callback.Run(CacheStorageCache::ERROR_TYPE_STORAGE,
938 scoped_ptr<ServiceWorkerResponse>(),
939 scoped_ptr<storage::BlobDataHandle>());
940 return;
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);
962 return;
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(
982 const GURL& origin,
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,
987 int rv) {
988 if (rv != net::OK) {
989 callback.Run(CacheStorageCache::ERROR_TYPE_NOT_FOUND);
990 return;
993 DCHECK(entry_ptr);
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)));
1004 entry->Doom();
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>());
1012 return;
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,
1043 int rv) {
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);
1049 return;
1052 if (rv < 0) {
1053 keys_context->original_callback.Run(ERROR_TYPE_STORAGE,
1054 scoped_ptr<Requests>());
1055 return;
1058 if (backend_state_ != BACKEND_OPEN) {
1059 keys_context->original_callback.Run(ERROR_TYPE_NOT_FOUND,
1060 scoped_ptr<Requests>());
1061 return;
1064 // Store the entry.
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());
1088 return;
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;
1102 if (metadata) {
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()));
1116 } else {
1117 entry->Doom();
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;
1127 backend_.reset();
1128 callback.Run();
1131 void CacheStorageCache::CreateBackend(const ErrorCallback& callback) {
1132 DCHECK(!backend_);
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,
1151 false, /* force */
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,
1161 int rv) {
1162 if (rv != net::OK) {
1163 callback.Run(CacheStorageCache::ERROR_TYPE_STORAGE);
1164 return;
1167 backend_ = backend_ptr->Pass();
1168 callback.Run(CacheStorageCache::ERROR_TYPE_OK);
1171 void CacheStorageCache::InitBackend() {
1172 DCHECK(backend_state_ == BACKEND_UNINITIALIZED);
1174 if (initializing_)
1175 return;
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)
1190 ? BACKEND_OPEN
1191 : BACKEND_CLOSED;
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();
1202 callback.Run();
1203 if (cache)
1204 scheduler_->CompleteOperationAndRunNext();
1207 void CacheStorageCache::PendingErrorCallback(const ErrorCallback& callback,
1208 ErrorType error) {
1209 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1211 callback.Run(error);
1212 if (cache)
1213 scheduler_->CompleteOperationAndRunNext();
1216 void CacheStorageCache::PendingResponseCallback(
1217 const ResponseCallback& callback,
1218 ErrorType error,
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());
1224 if (cache)
1225 scheduler_->CompleteOperationAndRunNext();
1228 void CacheStorageCache::PendingRequestsCallback(
1229 const RequestsCallback& callback,
1230 ErrorType error,
1231 scoped_ptr<Requests> requests) {
1232 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1234 callback.Run(error, requests.Pass());
1235 if (cache)
1236 scheduler_->CompleteOperationAndRunNext();
1239 } // namespace content