Revert "content: Remove use of MessageLoopProxy and deprecated MessageLoop APIs"
[chromium-blink-merge.git] / content / browser / cache_storage / cache_storage_cache.cc
blob279dfc3d8663dc7a602cfba62935048ff105fff9
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/barrier_closure.h"
10 #include "base/files/file_path.h"
11 #include "base/guid.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_util.h"
15 #include "content/browser/cache_storage/cache_storage.pb.h"
16 #include "content/browser/cache_storage/cache_storage_scheduler.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/common/referrer.h"
19 #include "net/base/completion_callback.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/net_errors.h"
22 #include "net/disk_cache/disk_cache.h"
23 #include "net/url_request/url_request_context.h"
24 #include "storage/browser/blob/blob_data_builder.h"
25 #include "storage/browser/blob/blob_data_handle.h"
26 #include "storage/browser/blob/blob_storage_context.h"
27 #include "storage/browser/blob/blob_url_request_job_factory.h"
28 #include "storage/browser/quota/quota_manager_proxy.h"
29 #include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
31 namespace content {
33 namespace {
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 if (!request->status().is_success()) {
220 callback_.Run(entry_.Pass(), false);
221 return;
223 ReadFromBlob();
226 virtual void ReadFromBlob() {
227 int bytes_read = 0;
228 bool done =
229 blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read);
230 if (done)
231 OnReadCompleted(blob_request_.get(), bytes_read);
234 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
235 if (!request->status().is_success()) {
236 callback_.Run(entry_.Pass(), false);
237 return;
240 if (bytes_read == 0) {
241 callback_.Run(entry_.Pass(), true);
242 return;
245 net::CompletionCallback cache_write_callback =
246 base::Bind(&BlobReader::DidWriteDataToEntry,
247 weak_ptr_factory_.GetWeakPtr(), bytes_read);
249 int rv = entry_->WriteData(INDEX_RESPONSE_BODY, cache_entry_offset_,
250 buffer_.get(), bytes_read, cache_write_callback,
251 true /* truncate */);
252 if (rv != net::ERR_IO_PENDING)
253 cache_write_callback.Run(rv);
256 void DidWriteDataToEntry(int expected_bytes, int rv) {
257 if (rv != expected_bytes) {
258 callback_.Run(entry_.Pass(), false);
259 return;
262 cache_entry_offset_ += rv;
263 ReadFromBlob();
266 private:
267 int cache_entry_offset_;
268 disk_cache::ScopedEntryPtr entry_;
269 scoped_ptr<net::URLRequest> blob_request_;
270 EntryAndBoolCallback callback_;
271 scoped_refptr<net::IOBufferWithSize> buffer_;
272 base::WeakPtrFactory<BlobReader> weak_ptr_factory_;
275 // The state needed to pass between CacheStorageCache::Keys callbacks.
276 struct CacheStorageCache::KeysContext {
277 explicit KeysContext(const CacheStorageCache::RequestsCallback& callback)
278 : original_callback(callback),
279 out_keys(new CacheStorageCache::Requests()),
280 enumerated_entry(NULL) {}
282 ~KeysContext() {
283 for (size_t i = 0, max = entries.size(); i < max; ++i)
284 entries[i]->Close();
285 if (enumerated_entry)
286 enumerated_entry->Close();
289 // The callback passed to the Keys() function.
290 CacheStorageCache::RequestsCallback original_callback;
292 // The vector of open entries in the backend.
293 Entries entries;
295 // The output of the Keys function.
296 scoped_ptr<CacheStorageCache::Requests> out_keys;
298 // Used for enumerating cache entries.
299 scoped_ptr<disk_cache::Backend::Iterator> backend_iterator;
300 disk_cache::Entry* enumerated_entry;
302 DISALLOW_COPY_AND_ASSIGN(KeysContext);
305 struct CacheStorageCache::MatchContext {
306 MatchContext(scoped_ptr<ServiceWorkerFetchRequest> request,
307 const CacheStorageCache::ResponseCallback& callback,
308 base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
309 : request(request.Pass()),
310 original_callback(callback),
311 blob_storage_context(blob_storage_context),
312 entry(nullptr),
313 total_bytes_read(0) {}
315 ~MatchContext() {
316 if (entry)
317 entry->Close();
320 // Input
321 scoped_ptr<ServiceWorkerFetchRequest> request;
322 CacheStorageCache::ResponseCallback original_callback;
323 base::WeakPtr<storage::BlobStorageContext> blob_storage_context;
324 disk_cache::Entry* entry;
326 // Output
327 scoped_ptr<ServiceWorkerResponse> response;
328 scoped_ptr<storage::BlobDataBuilder> blob_data;
330 // For reading the cache entry data into a blob.
331 scoped_refptr<net::IOBufferWithSize> response_body_buffer;
332 size_t total_bytes_read;
334 DISALLOW_COPY_AND_ASSIGN(MatchContext);
337 // The state needed to pass between CacheStorageCache::Put callbacks.
338 struct CacheStorageCache::PutContext {
339 PutContext(
340 const GURL& origin,
341 scoped_ptr<ServiceWorkerFetchRequest> request,
342 scoped_ptr<ServiceWorkerResponse> response,
343 scoped_ptr<storage::BlobDataHandle> blob_data_handle,
344 const CacheStorageCache::ErrorCallback& callback,
345 net::URLRequestContext* request_context,
346 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
347 : origin(origin),
348 request(request.Pass()),
349 response(response.Pass()),
350 blob_data_handle(blob_data_handle.Pass()),
351 callback(callback),
352 request_context(request_context),
353 quota_manager_proxy(quota_manager_proxy),
354 cache_entry(NULL) {}
355 ~PutContext() {
356 if (cache_entry)
357 cache_entry->Close();
360 // Input parameters to the Put function.
361 GURL origin;
362 scoped_ptr<ServiceWorkerFetchRequest> request;
363 scoped_ptr<ServiceWorkerResponse> response;
364 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
365 CacheStorageCache::ErrorCallback callback;
366 net::URLRequestContext* request_context;
367 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
369 // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
370 // CreateEntry.
371 disk_cache::Entry* cache_entry;
373 DISALLOW_COPY_AND_ASSIGN(PutContext);
376 // static
377 scoped_refptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache(
378 const GURL& origin,
379 net::URLRequestContext* request_context,
380 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
381 base::WeakPtr<storage::BlobStorageContext> blob_context) {
382 return make_scoped_refptr(
383 new CacheStorageCache(origin, base::FilePath(), request_context,
384 quota_manager_proxy, blob_context));
387 // static
388 scoped_refptr<CacheStorageCache> CacheStorageCache::CreatePersistentCache(
389 const GURL& origin,
390 const base::FilePath& path,
391 net::URLRequestContext* request_context,
392 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
393 base::WeakPtr<storage::BlobStorageContext> blob_context) {
394 return make_scoped_refptr(new CacheStorageCache(
395 origin, path, request_context, quota_manager_proxy, blob_context));
398 CacheStorageCache::~CacheStorageCache() {
401 base::WeakPtr<CacheStorageCache> CacheStorageCache::AsWeakPtr() {
402 return weak_ptr_factory_.GetWeakPtr();
405 void CacheStorageCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request,
406 const ResponseCallback& callback) {
407 switch (backend_state_) {
408 case BACKEND_UNINITIALIZED:
409 InitBackend();
410 break;
411 case BACKEND_CLOSED:
412 callback.Run(CACHE_STORAGE_ERROR_STORAGE,
413 scoped_ptr<ServiceWorkerResponse>(),
414 scoped_ptr<storage::BlobDataHandle>());
415 return;
416 case BACKEND_OPEN:
417 DCHECK(backend_);
418 break;
421 ResponseCallback pending_callback =
422 base::Bind(&CacheStorageCache::PendingResponseCallback,
423 weak_ptr_factory_.GetWeakPtr(), callback);
424 scheduler_->ScheduleOperation(
425 base::Bind(&CacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(),
426 base::Passed(request.Pass()), pending_callback));
429 void CacheStorageCache::BatchOperation(
430 const std::vector<CacheStorageBatchOperation>& operations,
431 const ErrorCallback& callback) {
432 switch (backend_state_) {
433 case BACKEND_UNINITIALIZED:
434 InitBackend();
435 break;
436 case BACKEND_CLOSED:
437 callback.Run(CACHE_STORAGE_ERROR_STORAGE);
438 return;
439 case BACKEND_OPEN:
440 DCHECK(backend_);
441 break;
444 scoped_ptr<ErrorCallback> callback_copy(new ErrorCallback(callback));
445 ErrorCallback* callback_ptr = callback_copy.get();
446 base::Closure barrier_closure = base::BarrierClosure(
447 operations.size(), base::Bind(&CacheStorageCache::BatchDidAllOperations,
448 this, base::Passed(callback_copy.Pass())));
449 ErrorCallback completion_callback =
450 base::Bind(&CacheStorageCache::BatchDidOneOperation, this,
451 barrier_closure, callback_ptr);
453 for (const auto& operation : operations) {
454 switch (operation.operation_type) {
455 case CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT:
456 Put(operation, completion_callback);
457 break;
458 case CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE:
459 DCHECK_EQ(1u, operations.size());
460 Delete(operation, completion_callback);
461 break;
462 case CACHE_STORAGE_CACHE_OPERATION_TYPE_UNDEFINED:
463 NOTREACHED();
464 // TODO(nhiroki): This should return "TypeError".
465 // http://crbug.com/425505
466 completion_callback.Run(CACHE_STORAGE_ERROR_STORAGE);
467 break;
472 void CacheStorageCache::BatchDidOneOperation(
473 const base::Closure& barrier_closure,
474 ErrorCallback* callback,
475 CacheStorageError error) {
476 if (callback->is_null() || error == CACHE_STORAGE_OK) {
477 barrier_closure.Run();
478 return;
480 callback->Run(error);
481 callback->Reset(); // Only call the callback once.
483 barrier_closure.Run();
486 void CacheStorageCache::BatchDidAllOperations(
487 scoped_ptr<ErrorCallback> callback) {
488 if (callback->is_null())
489 return;
490 callback->Run(CACHE_STORAGE_OK);
493 void CacheStorageCache::Keys(const RequestsCallback& callback) {
494 switch (backend_state_) {
495 case BACKEND_UNINITIALIZED:
496 InitBackend();
497 break;
498 case BACKEND_CLOSED:
499 callback.Run(CACHE_STORAGE_ERROR_STORAGE, scoped_ptr<Requests>());
500 return;
501 case BACKEND_OPEN:
502 DCHECK(backend_);
503 break;
506 RequestsCallback pending_callback =
507 base::Bind(&CacheStorageCache::PendingRequestsCallback,
508 weak_ptr_factory_.GetWeakPtr(), callback);
509 scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::KeysImpl,
510 weak_ptr_factory_.GetWeakPtr(),
511 pending_callback));
514 void CacheStorageCache::Close(const base::Closure& callback) {
515 DCHECK_NE(BACKEND_CLOSED, backend_state_)
516 << "Was CacheStorageCache::Close() called twice?";
518 base::Closure pending_callback =
519 base::Bind(&CacheStorageCache::PendingClosure,
520 weak_ptr_factory_.GetWeakPtr(), callback);
522 scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::CloseImpl,
523 weak_ptr_factory_.GetWeakPtr(),
524 pending_callback));
527 int64 CacheStorageCache::MemoryBackedSize() const {
528 if (backend_state_ != BACKEND_OPEN || !memory_only_)
529 return 0;
531 scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
532 backend_->CreateIterator();
533 disk_cache::Entry* entry = nullptr;
535 int64 sum = 0;
537 std::vector<disk_cache::Entry*> entries;
538 int rv = net::OK;
539 while ((rv = backend_iter->OpenNextEntry(
540 &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
541 entries.push_back(entry); // Open the entries without mutating them.
543 DCHECK_NE(net::ERR_IO_PENDING, rv)
544 << "Memory cache operations should be synchronous.";
546 for (disk_cache::Entry* entry : entries) {
547 sum += entry->GetDataSize(INDEX_HEADERS) +
548 entry->GetDataSize(INDEX_RESPONSE_BODY);
549 entry->Close();
552 return sum;
555 CacheStorageCache::CacheStorageCache(
556 const GURL& origin,
557 const base::FilePath& path,
558 net::URLRequestContext* request_context,
559 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
560 base::WeakPtr<storage::BlobStorageContext> blob_context)
561 : origin_(origin),
562 path_(path),
563 request_context_(request_context),
564 quota_manager_proxy_(quota_manager_proxy),
565 blob_storage_context_(blob_context),
566 backend_state_(BACKEND_UNINITIALIZED),
567 scheduler_(new CacheStorageScheduler()),
568 initializing_(false),
569 memory_only_(path.empty()),
570 weak_ptr_factory_(this) {
573 void CacheStorageCache::MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
574 const ResponseCallback& callback) {
575 DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
576 if (backend_state_ != BACKEND_OPEN) {
577 callback.Run(CACHE_STORAGE_ERROR_STORAGE,
578 scoped_ptr<ServiceWorkerResponse>(),
579 scoped_ptr<storage::BlobDataHandle>());
580 return;
583 scoped_ptr<MatchContext> match_context(
584 new MatchContext(request.Pass(), callback, blob_storage_context_));
586 disk_cache::Entry** entry_ptr = &match_context->entry;
587 ServiceWorkerFetchRequest* request_ptr = match_context->request.get();
589 net::CompletionCallback open_entry_callback = base::Bind(
590 &CacheStorageCache::MatchDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
591 base::Passed(match_context.Pass()));
593 int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr,
594 open_entry_callback);
595 if (rv != net::ERR_IO_PENDING)
596 open_entry_callback.Run(rv);
599 void CacheStorageCache::MatchDidOpenEntry(
600 scoped_ptr<MatchContext> match_context,
601 int rv) {
602 if (rv != net::OK) {
603 match_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
604 scoped_ptr<ServiceWorkerResponse>(),
605 scoped_ptr<storage::BlobDataHandle>());
606 return;
609 // Copy the entry pointer before passing it in base::Bind.
610 disk_cache::Entry* tmp_entry_ptr = match_context->entry;
611 DCHECK(tmp_entry_ptr);
613 MetadataCallback headers_callback = base::Bind(
614 &CacheStorageCache::MatchDidReadMetadata, weak_ptr_factory_.GetWeakPtr(),
615 base::Passed(match_context.Pass()));
617 ReadMetadata(tmp_entry_ptr, headers_callback);
620 void CacheStorageCache::MatchDidReadMetadata(
621 scoped_ptr<MatchContext> match_context,
622 scoped_ptr<CacheMetadata> metadata) {
623 if (!metadata) {
624 match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
625 scoped_ptr<ServiceWorkerResponse>(),
626 scoped_ptr<storage::BlobDataHandle>());
627 return;
630 match_context->response.reset(new ServiceWorkerResponse(
631 match_context->request->url, metadata->response().status_code(),
632 metadata->response().status_text(),
633 ProtoResponseTypeToWebResponseType(metadata->response().response_type()),
634 ServiceWorkerHeaderMap(), "", 0, GURL()));
636 ServiceWorkerResponse* response = match_context->response.get();
638 if (metadata->response().has_url())
639 response->url = GURL(metadata->response().url());
641 for (int i = 0; i < metadata->response().headers_size(); ++i) {
642 const CacheHeaderMap header = metadata->response().headers(i);
643 DCHECK_EQ(std::string::npos, header.name().find('\0'));
644 DCHECK_EQ(std::string::npos, header.value().find('\0'));
645 response->headers.insert(std::make_pair(header.name(), header.value()));
648 ServiceWorkerHeaderMap cached_request_headers;
649 for (int i = 0; i < metadata->request().headers_size(); ++i) {
650 const CacheHeaderMap header = metadata->request().headers(i);
651 DCHECK_EQ(std::string::npos, header.name().find('\0'));
652 DCHECK_EQ(std::string::npos, header.value().find('\0'));
653 cached_request_headers[header.name()] = header.value();
656 if (!VaryMatches(match_context->request->headers, cached_request_headers,
657 response->headers)) {
658 match_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
659 scoped_ptr<ServiceWorkerResponse>(),
660 scoped_ptr<storage::BlobDataHandle>());
661 return;
664 if (match_context->entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
665 match_context->original_callback.Run(CACHE_STORAGE_OK,
666 match_context->response.Pass(),
667 scoped_ptr<storage::BlobDataHandle>());
668 return;
671 // Stream the response body into a blob.
672 if (!match_context->blob_storage_context) {
673 match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
674 scoped_ptr<ServiceWorkerResponse>(),
675 scoped_ptr<storage::BlobDataHandle>());
676 return;
679 response->blob_uuid = base::GenerateGUID();
681 match_context->blob_data.reset(
682 new storage::BlobDataBuilder(response->blob_uuid));
683 match_context->response_body_buffer = new net::IOBufferWithSize(kBufferSize);
685 disk_cache::Entry* tmp_entry_ptr = match_context->entry;
686 net::IOBufferWithSize* response_body_buffer =
687 match_context->response_body_buffer.get();
689 net::CompletionCallback read_callback = base::Bind(
690 &CacheStorageCache::MatchDidReadResponseBodyData,
691 weak_ptr_factory_.GetWeakPtr(), base::Passed(match_context.Pass()));
693 int read_rv =
694 tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, 0, response_body_buffer,
695 response_body_buffer->size(), read_callback);
697 if (read_rv != net::ERR_IO_PENDING)
698 read_callback.Run(read_rv);
701 void CacheStorageCache::MatchDidReadResponseBodyData(
702 scoped_ptr<MatchContext> match_context,
703 int rv) {
704 if (rv < 0) {
705 match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
706 scoped_ptr<ServiceWorkerResponse>(),
707 scoped_ptr<storage::BlobDataHandle>());
708 return;
711 if (rv == 0) {
712 match_context->response->blob_uuid = match_context->blob_data->uuid();
713 match_context->response->blob_size = match_context->total_bytes_read;
714 MatchDoneWithBody(match_context.Pass());
715 return;
718 // TODO(jkarlin): This copying of the the entire cache response into memory is
719 // awful. Create a new interface around SimpleCache that provides access the
720 // data directly from the file. See bug http://crbug.com/403493.
721 match_context->blob_data->AppendData(
722 match_context->response_body_buffer->data(), rv);
723 match_context->total_bytes_read += rv;
724 int total_bytes_read = match_context->total_bytes_read;
726 // Grab some pointers before passing match_context in bind.
727 net::IOBufferWithSize* buffer = match_context->response_body_buffer.get();
728 disk_cache::Entry* tmp_entry_ptr = match_context->entry;
730 net::CompletionCallback read_callback = base::Bind(
731 &CacheStorageCache::MatchDidReadResponseBodyData,
732 weak_ptr_factory_.GetWeakPtr(), base::Passed(match_context.Pass()));
734 int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, total_bytes_read,
735 buffer, buffer->size(), read_callback);
737 if (read_rv != net::ERR_IO_PENDING)
738 read_callback.Run(read_rv);
741 void CacheStorageCache::MatchDoneWithBody(
742 scoped_ptr<MatchContext> match_context) {
743 if (!match_context->blob_storage_context) {
744 match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
745 scoped_ptr<ServiceWorkerResponse>(),
746 scoped_ptr<storage::BlobDataHandle>());
747 return;
750 scoped_ptr<storage::BlobDataHandle> blob_data_handle(
751 match_context->blob_storage_context->AddFinishedBlob(
752 match_context->blob_data.get()));
754 match_context->original_callback.Run(CACHE_STORAGE_OK,
755 match_context->response.Pass(),
756 blob_data_handle.Pass());
759 void CacheStorageCache::Put(const CacheStorageBatchOperation& operation,
760 const ErrorCallback& callback) {
761 DCHECK(BACKEND_OPEN == backend_state_ || initializing_);
762 DCHECK_EQ(CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT, operation.operation_type);
764 scoped_ptr<ServiceWorkerFetchRequest> request(new ServiceWorkerFetchRequest(
765 operation.request.url, operation.request.method,
766 operation.request.headers, operation.request.referrer,
767 operation.request.is_reload));
769 // We don't support streaming for cache.
770 DCHECK(operation.response.stream_url.is_empty());
771 scoped_ptr<ServiceWorkerResponse> response(new ServiceWorkerResponse(
772 operation.response.url, operation.response.status_code,
773 operation.response.status_text, operation.response.response_type,
774 operation.response.headers, operation.response.blob_uuid,
775 operation.response.blob_size, operation.response.stream_url));
777 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
779 if (!response->blob_uuid.empty()) {
780 if (!blob_storage_context_) {
781 callback.Run(CACHE_STORAGE_ERROR_STORAGE);
782 return;
784 blob_data_handle =
785 blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid);
786 if (!blob_data_handle) {
787 callback.Run(CACHE_STORAGE_ERROR_STORAGE);
788 return;
792 ErrorCallback pending_callback =
793 base::Bind(&CacheStorageCache::PendingErrorCallback,
794 weak_ptr_factory_.GetWeakPtr(), callback);
796 scoped_ptr<PutContext> put_context(new PutContext(
797 origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(),
798 pending_callback, request_context_, quota_manager_proxy_));
800 scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::PutImpl,
801 weak_ptr_factory_.GetWeakPtr(),
802 base::Passed(put_context.Pass())));
805 void CacheStorageCache::PutImpl(scoped_ptr<PutContext> put_context) {
806 DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
807 if (backend_state_ != BACKEND_OPEN) {
808 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
809 return;
812 scoped_ptr<ServiceWorkerFetchRequest> request_copy(
813 new ServiceWorkerFetchRequest(*put_context->request));
815 DeleteImpl(request_copy.Pass(), base::Bind(&CacheStorageCache::PutDidDelete,
816 weak_ptr_factory_.GetWeakPtr(),
817 base::Passed(put_context.Pass())));
820 void CacheStorageCache::PutDidDelete(scoped_ptr<PutContext> put_context,
821 CacheStorageError delete_error) {
822 if (backend_state_ != BACKEND_OPEN) {
823 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
824 return;
827 disk_cache::Entry** entry_ptr = &put_context->cache_entry;
828 ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
829 disk_cache::Backend* backend_ptr = backend_.get();
831 net::CompletionCallback create_entry_callback = base::Bind(
832 &CacheStorageCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(),
833 base::Passed(put_context.Pass()));
835 int create_rv = backend_ptr->CreateEntry(request_ptr->url.spec(), entry_ptr,
836 create_entry_callback);
838 if (create_rv != net::ERR_IO_PENDING)
839 create_entry_callback.Run(create_rv);
842 void CacheStorageCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
843 int rv) {
844 if (rv != net::OK) {
845 put_context->callback.Run(CACHE_STORAGE_ERROR_EXISTS);
846 return;
849 DCHECK(put_context->cache_entry);
851 CacheMetadata metadata;
852 CacheRequest* request_metadata = metadata.mutable_request();
853 request_metadata->set_method(put_context->request->method);
854 for (ServiceWorkerHeaderMap::const_iterator it =
855 put_context->request->headers.begin();
856 it != put_context->request->headers.end(); ++it) {
857 DCHECK_EQ(std::string::npos, it->first.find('\0'));
858 DCHECK_EQ(std::string::npos, it->second.find('\0'));
859 CacheHeaderMap* header_map = request_metadata->add_headers();
860 header_map->set_name(it->first);
861 header_map->set_value(it->second);
864 CacheResponse* response_metadata = metadata.mutable_response();
865 response_metadata->set_status_code(put_context->response->status_code);
866 response_metadata->set_status_text(put_context->response->status_text);
867 response_metadata->set_response_type(
868 WebResponseTypeToProtoResponseType(put_context->response->response_type));
869 response_metadata->set_url(put_context->response->url.spec());
870 for (ServiceWorkerHeaderMap::const_iterator it =
871 put_context->response->headers.begin();
872 it != put_context->response->headers.end(); ++it) {
873 DCHECK_EQ(std::string::npos, it->first.find('\0'));
874 DCHECK_EQ(std::string::npos, it->second.find('\0'));
875 CacheHeaderMap* header_map = response_metadata->add_headers();
876 header_map->set_name(it->first);
877 header_map->set_value(it->second);
880 scoped_ptr<std::string> serialized(new std::string());
881 if (!metadata.SerializeToString(serialized.get())) {
882 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
883 return;
886 scoped_refptr<net::StringIOBuffer> buffer(
887 new net::StringIOBuffer(serialized.Pass()));
889 // Get a temporary copy of the entry pointer before passing it in base::Bind.
890 disk_cache::Entry* tmp_entry_ptr = put_context->cache_entry;
892 net::CompletionCallback write_headers_callback = base::Bind(
893 &CacheStorageCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(),
894 base::Passed(put_context.Pass()), buffer->size());
896 rv = tmp_entry_ptr->WriteData(INDEX_HEADERS, 0 /* offset */, buffer.get(),
897 buffer->size(), write_headers_callback,
898 true /* truncate */);
900 if (rv != net::ERR_IO_PENDING)
901 write_headers_callback.Run(rv);
904 void CacheStorageCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
905 int expected_bytes,
906 int rv) {
907 if (rv != expected_bytes) {
908 put_context->cache_entry->Doom();
909 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
910 return;
913 // The metadata is written, now for the response content. The data is streamed
914 // from the blob into the cache entry.
916 if (put_context->response->blob_uuid.empty()) {
917 if (put_context->quota_manager_proxy.get()) {
918 put_context->quota_manager_proxy->NotifyStorageModified(
919 storage::QuotaClient::kServiceWorkerCache, put_context->origin,
920 storage::kStorageTypeTemporary,
921 put_context->cache_entry->GetDataSize(INDEX_HEADERS));
924 put_context->callback.Run(CACHE_STORAGE_OK);
925 return;
928 DCHECK(put_context->blob_data_handle);
930 disk_cache::ScopedEntryPtr entry(put_context->cache_entry);
931 put_context->cache_entry = NULL;
932 scoped_ptr<BlobReader> reader(new BlobReader());
933 BlobReader* reader_ptr = reader.get();
935 // Grab some pointers before passing put_context in Bind.
936 net::URLRequestContext* request_context = put_context->request_context;
937 scoped_ptr<storage::BlobDataHandle> blob_data_handle =
938 put_context->blob_data_handle.Pass();
940 reader_ptr->StreamBlobToCache(
941 entry.Pass(), request_context, blob_data_handle.Pass(),
942 base::Bind(&CacheStorageCache::PutDidWriteBlobToCache,
943 weak_ptr_factory_.GetWeakPtr(),
944 base::Passed(put_context.Pass()),
945 base::Passed(reader.Pass())));
948 void CacheStorageCache::PutDidWriteBlobToCache(
949 scoped_ptr<PutContext> put_context,
950 scoped_ptr<BlobReader> blob_reader,
951 disk_cache::ScopedEntryPtr entry,
952 bool success) {
953 DCHECK(entry);
954 put_context->cache_entry = entry.release();
956 if (!success) {
957 put_context->cache_entry->Doom();
958 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
959 return;
962 if (put_context->quota_manager_proxy.get()) {
963 put_context->quota_manager_proxy->NotifyStorageModified(
964 storage::QuotaClient::kServiceWorkerCache, put_context->origin,
965 storage::kStorageTypeTemporary,
966 put_context->cache_entry->GetDataSize(INDEX_HEADERS) +
967 put_context->cache_entry->GetDataSize(INDEX_RESPONSE_BODY));
970 put_context->callback.Run(CACHE_STORAGE_OK);
973 void CacheStorageCache::Delete(const CacheStorageBatchOperation& operation,
974 const ErrorCallback& callback) {
975 DCHECK(BACKEND_OPEN == backend_state_ || initializing_);
976 DCHECK_EQ(CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE,
977 operation.operation_type);
979 scoped_ptr<ServiceWorkerFetchRequest> request(new ServiceWorkerFetchRequest(
980 operation.request.url, operation.request.method,
981 operation.request.headers, operation.request.referrer,
982 operation.request.is_reload));
984 ErrorCallback pending_callback =
985 base::Bind(&CacheStorageCache::PendingErrorCallback,
986 weak_ptr_factory_.GetWeakPtr(), callback);
987 scheduler_->ScheduleOperation(
988 base::Bind(&CacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(),
989 base::Passed(request.Pass()), pending_callback));
992 void CacheStorageCache::DeleteImpl(
993 scoped_ptr<ServiceWorkerFetchRequest> request,
994 const ErrorCallback& callback) {
995 DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
996 if (backend_state_ != BACKEND_OPEN) {
997 callback.Run(CACHE_STORAGE_ERROR_STORAGE);
998 return;
1000 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
1002 disk_cache::Entry** entry_ptr = entry.get();
1004 ServiceWorkerFetchRequest* request_ptr = request.get();
1006 net::CompletionCallback open_entry_callback = base::Bind(
1007 &CacheStorageCache::DeleteDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
1008 origin_, base::Passed(request.Pass()), callback,
1009 base::Passed(entry.Pass()), quota_manager_proxy_);
1011 int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr,
1012 open_entry_callback);
1013 if (rv != net::ERR_IO_PENDING)
1014 open_entry_callback.Run(rv);
1017 void CacheStorageCache::DeleteDidOpenEntry(
1018 const GURL& origin,
1019 scoped_ptr<ServiceWorkerFetchRequest> request,
1020 const CacheStorageCache::ErrorCallback& callback,
1021 scoped_ptr<disk_cache::Entry*> entry_ptr,
1022 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
1023 int rv) {
1024 if (rv != net::OK) {
1025 callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND);
1026 return;
1029 DCHECK(entry_ptr);
1030 disk_cache::ScopedEntryPtr entry(*entry_ptr);
1032 if (quota_manager_proxy.get()) {
1033 quota_manager_proxy->NotifyStorageModified(
1034 storage::QuotaClient::kServiceWorkerCache, origin,
1035 storage::kStorageTypeTemporary,
1036 -1 * (entry->GetDataSize(INDEX_HEADERS) +
1037 entry->GetDataSize(INDEX_RESPONSE_BODY)));
1040 entry->Doom();
1041 callback.Run(CACHE_STORAGE_OK);
1044 void CacheStorageCache::KeysImpl(const RequestsCallback& callback) {
1045 DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
1046 if (backend_state_ != BACKEND_OPEN) {
1047 callback.Run(CACHE_STORAGE_ERROR_STORAGE, scoped_ptr<Requests>());
1048 return;
1051 // 1. Iterate through all of the entries, open them, and add them to a vector.
1052 // 2. For each open entry:
1053 // 2.1. Read the headers into a protobuf.
1054 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
1055 // 2.3. Push the response into a vector of requests to be returned.
1056 // 3. Return the vector of requests (keys).
1058 // The entries have to be loaded into a vector first because enumeration loops
1059 // forever if you read data from a cache entry while enumerating.
1061 scoped_ptr<KeysContext> keys_context(new KeysContext(callback));
1063 keys_context->backend_iterator = backend_->CreateIterator();
1064 disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
1065 disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
1067 net::CompletionCallback open_entry_callback = base::Bind(
1068 &CacheStorageCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(),
1069 base::Passed(keys_context.Pass()));
1071 int rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
1073 if (rv != net::ERR_IO_PENDING)
1074 open_entry_callback.Run(rv);
1077 void CacheStorageCache::KeysDidOpenNextEntry(
1078 scoped_ptr<KeysContext> keys_context,
1079 int rv) {
1080 if (rv == net::ERR_FAILED) {
1081 DCHECK(!keys_context->enumerated_entry);
1082 // Enumeration is complete, extract the requests from the entries.
1083 Entries::iterator iter = keys_context->entries.begin();
1084 KeysProcessNextEntry(keys_context.Pass(), iter);
1085 return;
1088 if (rv < 0) {
1089 keys_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
1090 scoped_ptr<Requests>());
1091 return;
1094 if (backend_state_ != BACKEND_OPEN) {
1095 keys_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
1096 scoped_ptr<Requests>());
1097 return;
1100 // Store the entry.
1101 keys_context->entries.push_back(keys_context->enumerated_entry);
1102 keys_context->enumerated_entry = NULL;
1104 // Enumerate the next entry.
1105 disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
1106 disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
1107 net::CompletionCallback open_entry_callback = base::Bind(
1108 &CacheStorageCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(),
1109 base::Passed(keys_context.Pass()));
1111 rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
1113 if (rv != net::ERR_IO_PENDING)
1114 open_entry_callback.Run(rv);
1117 void CacheStorageCache::KeysProcessNextEntry(
1118 scoped_ptr<KeysContext> keys_context,
1119 const Entries::iterator& iter) {
1120 if (iter == keys_context->entries.end()) {
1121 // All done. Return all of the keys.
1122 keys_context->original_callback.Run(CACHE_STORAGE_OK,
1123 keys_context->out_keys.Pass());
1124 return;
1127 ReadMetadata(*iter, base::Bind(&CacheStorageCache::KeysDidReadMetadata,
1128 weak_ptr_factory_.GetWeakPtr(),
1129 base::Passed(keys_context.Pass()), iter));
1132 void CacheStorageCache::KeysDidReadMetadata(
1133 scoped_ptr<KeysContext> keys_context,
1134 const Entries::iterator& iter,
1135 scoped_ptr<CacheMetadata> metadata) {
1136 disk_cache::Entry* entry = *iter;
1138 if (metadata) {
1139 keys_context->out_keys->push_back(ServiceWorkerFetchRequest(
1140 GURL(entry->GetKey()), metadata->request().method(),
1141 ServiceWorkerHeaderMap(), Referrer(), false));
1143 ServiceWorkerHeaderMap& req_headers =
1144 keys_context->out_keys->back().headers;
1146 for (int i = 0; i < metadata->request().headers_size(); ++i) {
1147 const CacheHeaderMap header = metadata->request().headers(i);
1148 DCHECK_EQ(std::string::npos, header.name().find('\0'));
1149 DCHECK_EQ(std::string::npos, header.value().find('\0'));
1150 req_headers.insert(std::make_pair(header.name(), header.value()));
1152 } else {
1153 entry->Doom();
1156 KeysProcessNextEntry(keys_context.Pass(), iter + 1);
1159 void CacheStorageCache::CloseImpl(const base::Closure& callback) {
1160 DCHECK_NE(BACKEND_CLOSED, backend_state_);
1162 backend_state_ = BACKEND_CLOSED;
1163 backend_.reset();
1164 callback.Run();
1167 void CacheStorageCache::CreateBackend(const ErrorCallback& callback) {
1168 DCHECK(!backend_);
1170 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
1171 net::CacheType cache_type = memory_only_ ? net::MEMORY_CACHE : net::APP_CACHE;
1173 scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr());
1175 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
1176 ScopedBackendPtr* backend = backend_ptr.get();
1178 net::CompletionCallback create_cache_callback =
1179 base::Bind(&CacheStorageCache::CreateBackendDidCreate,
1180 weak_ptr_factory_.GetWeakPtr(), callback,
1181 base::Passed(backend_ptr.Pass()));
1183 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
1184 // has for disk caches.
1185 int rv = disk_cache::CreateCacheBackend(
1186 cache_type, net::CACHE_BACKEND_SIMPLE, path_, kMaxCacheBytes,
1187 false, /* force */
1188 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(),
1189 NULL, backend, create_cache_callback);
1190 if (rv != net::ERR_IO_PENDING)
1191 create_cache_callback.Run(rv);
1194 void CacheStorageCache::CreateBackendDidCreate(
1195 const CacheStorageCache::ErrorCallback& callback,
1196 scoped_ptr<ScopedBackendPtr> backend_ptr,
1197 int rv) {
1198 if (rv != net::OK) {
1199 callback.Run(CACHE_STORAGE_ERROR_STORAGE);
1200 return;
1203 backend_ = backend_ptr->Pass();
1204 callback.Run(CACHE_STORAGE_OK);
1207 void CacheStorageCache::InitBackend() {
1208 DCHECK_EQ(BACKEND_UNINITIALIZED, backend_state_);
1210 if (initializing_)
1211 return;
1213 DCHECK(!scheduler_->ScheduledOperations());
1214 initializing_ = true;
1216 scheduler_->ScheduleOperation(base::Bind(
1217 &CacheStorageCache::CreateBackend, weak_ptr_factory_.GetWeakPtr(),
1218 base::Bind(&CacheStorageCache::InitDone,
1219 weak_ptr_factory_.GetWeakPtr())));
1222 void CacheStorageCache::InitDone(CacheStorageError error) {
1223 initializing_ = false;
1224 backend_state_ = (error == CACHE_STORAGE_OK && backend_ &&
1225 backend_state_ == BACKEND_UNINITIALIZED)
1226 ? BACKEND_OPEN
1227 : BACKEND_CLOSED;
1229 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", error,
1230 CACHE_STORAGE_ERROR_LAST + 1);
1232 scheduler_->CompleteOperationAndRunNext();
1235 void CacheStorageCache::PendingClosure(const base::Closure& callback) {
1236 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1238 callback.Run();
1239 if (cache)
1240 scheduler_->CompleteOperationAndRunNext();
1243 void CacheStorageCache::PendingErrorCallback(const ErrorCallback& callback,
1244 CacheStorageError error) {
1245 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1247 callback.Run(error);
1248 if (cache)
1249 scheduler_->CompleteOperationAndRunNext();
1252 void CacheStorageCache::PendingResponseCallback(
1253 const ResponseCallback& callback,
1254 CacheStorageError error,
1255 scoped_ptr<ServiceWorkerResponse> response,
1256 scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
1257 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1259 callback.Run(error, response.Pass(), blob_data_handle.Pass());
1260 if (cache)
1261 scheduler_->CompleteOperationAndRunNext();
1264 void CacheStorageCache::PendingRequestsCallback(
1265 const RequestsCallback& callback,
1266 CacheStorageError error,
1267 scoped_ptr<Requests> requests) {
1268 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1270 callback.Run(error, requests.Pass());
1271 if (cache)
1272 scheduler_->CompleteOperationAndRunNext();
1275 } // namespace content