ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_cache.cc
bloba597a0303f94627fa4dc56d4e8233fba140fd733
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"
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/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"
29 namespace content {
31 namespace {
33 typedef base::Callback<void(bool)> BoolCallback;
34 typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
35 EntryBoolCallback;
36 typedef base::Callback<void(scoped_ptr<ServiceWorkerCacheMetadata>)>
37 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 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;
66 NOTREACHED();
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;
84 NOTREACHED();
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,
95 int rv);
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())
103 return true;
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();
109 ++it) {
110 std::string trimmed;
111 base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &trimmed);
112 if (trimmed == "*")
113 return false;
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()))
122 return false;
124 // If the header exists in one, it exists in both. Verify that the values
125 // are equal.
126 if (request_iter != request.end() &&
127 request_iter->second != cached_request_iter->second)
128 return false;
131 return true;
135 void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
136 DCHECK(entry);
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,
158 int rv) {
159 if (rv != buffer->size()) {
160 callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
161 return;
164 scoped_ptr<ServiceWorkerCacheMetadata> metadata(
165 new ServiceWorkerCacheMetadata());
167 if (!metadata->ParseFromArray(buffer->data(), buffer->size())) {
168 callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
169 return;
172 callback.Run(metadata.Pass());
175 } // namespace
177 // Streams data from a blob and writes it to a given disk_cache::Entry.
178 class ServiceWorkerCache::BlobReader : public net::URLRequest::Delegate {
179 public:
180 typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
181 EntryAndBoolCallback;
183 BlobReader()
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) {
193 DCHECK(entry);
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 {
205 NOTREACHED();
207 void OnAuthRequired(net::URLRequest* request,
208 net::AuthChallengeInfo* auth_info) override {
209 NOTREACHED();
211 void OnCertificateRequested(
212 net::URLRequest* request,
213 net::SSLCertRequestInfo* cert_request_info) override {
214 NOTREACHED();
216 void OnSSLCertificateError(net::URLRequest* request,
217 const net::SSLInfo& ssl_info,
218 bool fatal) override {
219 NOTREACHED();
221 void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override {
222 NOTREACHED();
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);
233 return;
235 ReadFromBlob();
238 virtual void ReadFromBlob() {
239 int bytes_read = 0;
240 bool done =
241 blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read);
242 if (done)
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);
254 return;
257 if (bytes_read == 0) {
258 callback_.Run(entry_.Pass(), true);
259 return;
262 net::CompletionCallback cache_write_callback =
263 base::Bind(&BlobReader::DidWriteDataToEntry,
264 weak_ptr_factory_.GetWeakPtr(),
265 bytes_read);
267 int rv = entry_->WriteData(INDEX_RESPONSE_BODY,
268 cache_entry_offset_,
269 buffer_.get(),
270 bytes_read,
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);
280 return;
283 cache_entry_offset_ += rv;
284 ReadFromBlob();
287 private:
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) {}
303 ~KeysContext() {
304 for (size_t i = 0, max = entries.size(); i < max; ++i)
305 entries[i]->Close();
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.
314 Entries entries;
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),
333 entry(nullptr),
334 total_bytes_read(0) {}
336 ~MatchContext() {
337 if (entry)
338 entry->Close();
341 // Input
342 scoped_ptr<ServiceWorkerFetchRequest> request;
343 ServiceWorkerCache::ResponseCallback original_callback;
344 base::WeakPtr<storage::BlobStorageContext> blob_storage_context;
345 disk_cache::Entry* entry;
347 // Output
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 {
360 PutContext(
361 const GURL& origin,
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)
368 : origin(origin),
369 request(request.Pass()),
370 response(response.Pass()),
371 blob_data_handle(blob_data_handle.Pass()),
372 callback(callback),
373 request_context(request_context),
374 quota_manager_proxy(quota_manager_proxy),
375 cache_entry(NULL) {}
376 ~PutContext() {
377 if (cache_entry)
378 cache_entry->Close();
381 // Input parameters to the Put function.
382 GURL origin;
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
391 // CreateEntry.
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);
400 // static
401 scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache(
402 const GURL& origin,
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,
407 base::FilePath(),
408 request_context,
409 quota_manager_proxy,
410 blob_context));
413 // static
414 scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache(
415 const GURL& origin,
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>());
440 return;
442 blob_data_handle =
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>());
447 return;
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)
467 InitBackend();
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:
478 InitBackend();
479 break;
480 case BACKEND_CLOSED:
481 callback.Run(ErrorTypeStorage, scoped_ptr<ServiceWorkerResponse>(),
482 scoped_ptr<storage::BlobDataHandle>());
483 return;
484 case BACKEND_OPEN:
485 DCHECK(backend_);
486 break;
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:
501 InitBackend();
502 break;
503 case BACKEND_CLOSED:
504 callback.Run(ErrorTypeStorage);
505 return;
506 case BACKEND_OPEN:
507 DCHECK(backend_);
508 break;
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:
521 InitBackend();
522 break;
523 case BACKEND_CLOSED:
524 callback.Run(ErrorTypeStorage, scoped_ptr<Requests>());
525 return;
526 case BACKEND_OPEN:
527 DCHECK(backend_);
528 break;
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(),
536 pending_callback));
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(),
549 pending_callback));
552 int64 ServiceWorkerCache::MemoryBackedSize() const {
553 if (backend_state_ != BACKEND_OPEN || !memory_only_)
554 return 0;
556 scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
557 backend_->CreateIterator();
558 disk_cache::Entry* entry = nullptr;
560 int64 sum = 0;
562 std::vector<disk_cache::Entry*> entries;
563 int rv = net::OK;
564 while ((rv = backend_iter->OpenNextEntry(
565 &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
566 entries.push_back(entry); // Open the entries without mutating them.
568 DCHECK(rv !=
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);
574 entry->Close();
577 return sum;
580 ServiceWorkerCache::ServiceWorkerCache(
581 const GURL& origin,
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)
586 : origin_(origin),
587 path_(path),
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>());
605 return;
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,
626 int rv) {
627 if (rv != net::OK) {
628 match_context->original_callback.Run(ServiceWorkerCache::ErrorTypeNotFound,
629 scoped_ptr<ServiceWorkerResponse>(),
630 scoped_ptr<storage::BlobDataHandle>());
631 return;
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) {
648 if (!metadata) {
649 match_context->original_callback.Run(ServiceWorkerCache::ErrorTypeStorage,
650 scoped_ptr<ServiceWorkerResponse>(),
651 scoped_ptr<storage::BlobDataHandle>());
652 return;
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>());
686 return;
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>());
693 return;
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>());
701 return;
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()));
718 int read_rv =
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,
728 int rv) {
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"));
734 if (rv < 0) {
735 match_context->original_callback.Run(ServiceWorkerCache::ErrorTypeStorage,
736 scoped_ptr<ServiceWorkerResponse>(),
737 scoped_ptr<storage::BlobDataHandle>());
738 return;
741 if (rv == 0) {
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());
745 return;
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>());
777 return;
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>());
795 return;
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>());
812 return;
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,
831 int rv) {
832 if (rv != net::OK) {
833 put_context->callback.Run(ServiceWorkerCache::ErrorTypeExists,
834 scoped_ptr<ServiceWorkerResponse>(),
835 scoped_ptr<storage::BlobDataHandle>());
836 return;
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();
847 ++it) {
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();
864 ++it) {
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>());
877 return;
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,
891 0 /* offset */,
892 buffer.get(),
893 buffer->size(),
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,
902 int expected_bytes,
903 int rv) {
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>());
909 return;
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,
919 put_context->origin,
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>());
927 return;
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,
954 bool success) {
955 DCHECK(entry);
956 put_context->cache_entry = entry.release();
958 if (!success) {
959 put_context->cache_entry->Doom();
960 put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
961 scoped_ptr<ServiceWorkerResponse>(),
962 scoped_ptr<storage::BlobDataHandle>());
963 return;
966 if (put_context->quota_manager_proxy.get()) {
967 put_context->quota_manager_proxy->NotifyStorageModified(
968 storage::QuotaClient::kServiceWorkerCache,
969 put_context->origin,
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);
986 return;
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(
1006 const GURL& origin,
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,
1011 int rv) {
1012 if (rv != net::OK) {
1013 callback.Run(ServiceWorkerCache::ErrorTypeNotFound);
1014 return;
1017 DCHECK(entry_ptr);
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)));
1028 entry->Doom();
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>());
1036 return;
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,
1067 int rv) {
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);
1073 return;
1076 if (rv < 0) {
1077 keys_context->original_callback.Run(ErrorTypeStorage,
1078 scoped_ptr<Requests>());
1079 return;
1082 if (backend_state_ != BACKEND_OPEN) {
1083 keys_context->original_callback.Run(ErrorTypeNotFound,
1084 scoped_ptr<Requests>());
1085 return;
1088 // Store the entry.
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());
1112 return;
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;
1126 if (metadata) {
1127 keys_context->out_keys->push_back(
1128 ServiceWorkerFetchRequest(GURL(entry->GetKey()),
1129 metadata->request().method(),
1130 ServiceWorkerHeaderMap(),
1131 Referrer(),
1132 false));
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()));
1143 } else {
1144 entry->Doom();
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;
1154 backend_.reset();
1155 callback.Run();
1158 void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) {
1159 DCHECK(!backend_);
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(
1177 cache_type,
1178 net::CACHE_BACKEND_SIMPLE,
1179 path_,
1180 kMaxCacheBytes,
1181 false, /* force */
1182 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(),
1183 NULL,
1184 backend,
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,
1193 int rv) {
1194 if (rv != net::OK) {
1195 callback.Run(ServiceWorkerCache::ErrorTypeStorage);
1196 return;
1199 backend_ = backend_ptr->Pass();
1200 callback.Run(ServiceWorkerCache::ErrorTypeOK);
1203 void ServiceWorkerCache::InitBackend() {
1204 DCHECK(backend_state_ == BACKEND_UNINITIALIZED);
1206 if (initializing_)
1207 return;
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)
1222 ? BACKEND_OPEN
1223 : BACKEND_CLOSED;
1224 scheduler_->CompleteOperationAndRunNext();
1227 void ServiceWorkerCache::PendingClosure(const base::Closure& callback) {
1228 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1230 callback.Run();
1231 if (cache)
1232 scheduler_->CompleteOperationAndRunNext();
1235 void ServiceWorkerCache::PendingErrorCallback(const ErrorCallback& callback,
1236 ErrorType error) {
1237 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1239 callback.Run(error);
1240 if (cache)
1241 scheduler_->CompleteOperationAndRunNext();
1244 void ServiceWorkerCache::PendingResponseCallback(
1245 const ResponseCallback& callback,
1246 ErrorType error,
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());
1252 if (cache)
1253 scheduler_->CompleteOperationAndRunNext();
1256 void ServiceWorkerCache::PendingRequestsCallback(
1257 const RequestsCallback& callback,
1258 ErrorType error,
1259 scoped_ptr<Requests> requests) {
1260 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1262 callback.Run(error, requests.Pass());
1263 if (cache)
1264 scheduler_->CompleteOperationAndRunNext();
1267 } // namespace content