Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(642)

Side by Side Diff: content/browser/service_worker/service_worker_cache.cc

Issue 1039763002: Cache Storage: Move files to content/*/cache_storage, rename classes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: GN fix Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "content/browser/service_worker/service_worker_cache.h"
6
7 #include <string>
8
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/service_worker/service_worker_cache.pb.h"
16 #include "content/browser/service_worker/service_worker_cache_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"
29
30 namespace content {
31
32 namespace {
33
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<ServiceWorkerCacheMetadata>)>
38 MetadataCallback;
39
40 enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
41
42 // The maximum size of an individual cache. Ultimately cache size is controlled
43 // per-origin.
44 const int kMaxCacheBytes = 512 * 1024 * 1024;
45
46 // Buffer size for cache and blob reading/writing.
47 const int kBufferSize = 1024 * 512;
48
49 void NotReachedCompletionCallback(int rv) {
50 NOTREACHED();
51 }
52
53 blink::WebServiceWorkerResponseType ProtoResponseTypeToWebResponseType(
54 ServiceWorkerCacheResponse::ResponseType response_type) {
55 switch (response_type) {
56 case ServiceWorkerCacheResponse::BASIC_TYPE:
57 return blink::WebServiceWorkerResponseTypeBasic;
58 case ServiceWorkerCacheResponse::CORS_TYPE:
59 return blink::WebServiceWorkerResponseTypeCORS;
60 case ServiceWorkerCacheResponse::DEFAULT_TYPE:
61 return blink::WebServiceWorkerResponseTypeDefault;
62 case ServiceWorkerCacheResponse::ERROR_TYPE:
63 return blink::WebServiceWorkerResponseTypeError;
64 case ServiceWorkerCacheResponse::OPAQUE_TYPE:
65 return blink::WebServiceWorkerResponseTypeOpaque;
66 }
67 NOTREACHED();
68 return blink::WebServiceWorkerResponseTypeOpaque;
69 }
70
71 ServiceWorkerCacheResponse::ResponseType WebResponseTypeToProtoResponseType(
72 blink::WebServiceWorkerResponseType response_type) {
73 switch (response_type) {
74 case blink::WebServiceWorkerResponseTypeBasic:
75 return ServiceWorkerCacheResponse::BASIC_TYPE;
76 case blink::WebServiceWorkerResponseTypeCORS:
77 return ServiceWorkerCacheResponse::CORS_TYPE;
78 case blink::WebServiceWorkerResponseTypeDefault:
79 return ServiceWorkerCacheResponse::DEFAULT_TYPE;
80 case blink::WebServiceWorkerResponseTypeError:
81 return ServiceWorkerCacheResponse::ERROR_TYPE;
82 case blink::WebServiceWorkerResponseTypeOpaque:
83 return ServiceWorkerCacheResponse::OPAQUE_TYPE;
84 }
85 NOTREACHED();
86 return ServiceWorkerCacheResponse::OPAQUE_TYPE;
87 }
88
89 // Copy headers out of a cache entry and into a protobuf. The callback is
90 // guaranteed to be run.
91 void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback);
92 void ReadMetadataDidReadMetadata(
93 disk_cache::Entry* entry,
94 const MetadataCallback& callback,
95 const scoped_refptr<net::IOBufferWithSize>& buffer,
96 int rv);
97
98
99 bool VaryMatches(const ServiceWorkerHeaderMap& request,
100 const ServiceWorkerHeaderMap& cached_request,
101 const ServiceWorkerHeaderMap& response) {
102 ServiceWorkerHeaderMap::const_iterator vary_iter = response.find("vary");
103 if (vary_iter == response.end())
104 return true;
105
106 std::vector<std::string> vary_keys;
107 Tokenize(vary_iter->second, ",", &vary_keys);
108 for (std::vector<std::string>::const_iterator it = vary_keys.begin();
109 it != vary_keys.end();
110 ++it) {
111 std::string trimmed;
112 base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &trimmed);
113 if (trimmed == "*")
114 return false;
115
116 ServiceWorkerHeaderMap::const_iterator request_iter = request.find(trimmed);
117 ServiceWorkerHeaderMap::const_iterator cached_request_iter =
118 cached_request.find(trimmed);
119
120 // If the header exists in one but not the other, no match.
121 if ((request_iter == request.end()) !=
122 (cached_request_iter == cached_request.end()))
123 return false;
124
125 // If the header exists in one, it exists in both. Verify that the values
126 // are equal.
127 if (request_iter != request.end() &&
128 request_iter->second != cached_request_iter->second)
129 return false;
130 }
131
132 return true;
133 }
134
135
136 void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
137 DCHECK(entry);
138
139 scoped_refptr<net::IOBufferWithSize> buffer(
140 new net::IOBufferWithSize(entry->GetDataSize(INDEX_HEADERS)));
141
142 net::CompletionCallback read_header_callback =
143 base::Bind(ReadMetadataDidReadMetadata, entry, callback, buffer);
144
145 int read_rv = entry->ReadData(
146 INDEX_HEADERS, 0, buffer.get(), buffer->size(),
147 tracked_objects::ScopedTracker::TrackCallback(
148 FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 ReadMetadata"),
149 read_header_callback));
150
151 if (read_rv != net::ERR_IO_PENDING)
152 read_header_callback.Run(read_rv);
153 }
154
155 void ReadMetadataDidReadMetadata(
156 disk_cache::Entry* entry,
157 const MetadataCallback& callback,
158 const scoped_refptr<net::IOBufferWithSize>& buffer,
159 int rv) {
160 if (rv != buffer->size()) {
161 callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
162 return;
163 }
164
165 scoped_ptr<ServiceWorkerCacheMetadata> metadata(
166 new ServiceWorkerCacheMetadata());
167
168 if (!metadata->ParseFromArray(buffer->data(), buffer->size())) {
169 callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
170 return;
171 }
172
173 callback.Run(metadata.Pass());
174 }
175
176 } // namespace
177
178 // Streams data from a blob and writes it to a given disk_cache::Entry.
179 class ServiceWorkerCache::BlobReader : public net::URLRequest::Delegate {
180 public:
181 typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
182 EntryAndBoolCallback;
183
184 BlobReader()
185 : cache_entry_offset_(0),
186 buffer_(new net::IOBufferWithSize(kBufferSize)),
187 weak_ptr_factory_(this) {}
188
189 // |entry| is passed to the callback once complete.
190 void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
191 net::URLRequestContext* request_context,
192 scoped_ptr<storage::BlobDataHandle> blob_data_handle,
193 const EntryAndBoolCallback& callback) {
194 DCHECK(entry);
195 entry_ = entry.Pass();
196 callback_ = callback;
197 blob_request_ = storage::BlobProtocolHandler::CreateBlobRequest(
198 blob_data_handle.Pass(), request_context, this);
199 blob_request_->Start();
200 }
201
202 // net::URLRequest::Delegate overrides for reading blobs.
203 void OnReceivedRedirect(net::URLRequest* request,
204 const net::RedirectInfo& redirect_info,
205 bool* defer_redirect) override {
206 NOTREACHED();
207 }
208 void OnAuthRequired(net::URLRequest* request,
209 net::AuthChallengeInfo* auth_info) override {
210 NOTREACHED();
211 }
212 void OnCertificateRequested(
213 net::URLRequest* request,
214 net::SSLCertRequestInfo* cert_request_info) override {
215 NOTREACHED();
216 }
217 void OnSSLCertificateError(net::URLRequest* request,
218 const net::SSLInfo& ssl_info,
219 bool fatal) override {
220 NOTREACHED();
221 }
222 void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override {
223 NOTREACHED();
224 }
225
226 void OnResponseStarted(net::URLRequest* request) override {
227 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
228 tracked_objects::ScopedTracker tracking_profile(
229 FROM_HERE_WITH_EXPLICIT_FUNCTION(
230 "423948 ServiceWorkerCache::BlobReader::OnResponseStarted"));
231
232 if (!request->status().is_success()) {
233 callback_.Run(entry_.Pass(), false);
234 return;
235 }
236 ReadFromBlob();
237 }
238
239 virtual void ReadFromBlob() {
240 int bytes_read = 0;
241 bool done =
242 blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read);
243 if (done)
244 OnReadCompleted(blob_request_.get(), bytes_read);
245 }
246
247 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
248 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
249 tracked_objects::ScopedTracker tracking_profile(
250 FROM_HERE_WITH_EXPLICIT_FUNCTION(
251 "423948 ServiceWorkerCache::BlobReader::OnReadCompleted"));
252
253 if (!request->status().is_success()) {
254 callback_.Run(entry_.Pass(), false);
255 return;
256 }
257
258 if (bytes_read == 0) {
259 callback_.Run(entry_.Pass(), true);
260 return;
261 }
262
263 net::CompletionCallback cache_write_callback =
264 base::Bind(&BlobReader::DidWriteDataToEntry,
265 weak_ptr_factory_.GetWeakPtr(),
266 bytes_read);
267
268 int rv = entry_->WriteData(INDEX_RESPONSE_BODY,
269 cache_entry_offset_,
270 buffer_.get(),
271 bytes_read,
272 cache_write_callback,
273 true /* truncate */);
274 if (rv != net::ERR_IO_PENDING)
275 cache_write_callback.Run(rv);
276 }
277
278 void DidWriteDataToEntry(int expected_bytes, int rv) {
279 if (rv != expected_bytes) {
280 callback_.Run(entry_.Pass(), false);
281 return;
282 }
283
284 cache_entry_offset_ += rv;
285 ReadFromBlob();
286 }
287
288 private:
289 int cache_entry_offset_;
290 disk_cache::ScopedEntryPtr entry_;
291 scoped_ptr<net::URLRequest> blob_request_;
292 EntryAndBoolCallback callback_;
293 scoped_refptr<net::IOBufferWithSize> buffer_;
294 base::WeakPtrFactory<BlobReader> weak_ptr_factory_;
295 };
296
297 // The state needed to pass between ServiceWorkerCache::Keys callbacks.
298 struct ServiceWorkerCache::KeysContext {
299 KeysContext(const ServiceWorkerCache::RequestsCallback& callback)
300 : original_callback(callback),
301 out_keys(new ServiceWorkerCache::Requests()),
302 enumerated_entry(NULL) {}
303
304 ~KeysContext() {
305 for (size_t i = 0, max = entries.size(); i < max; ++i)
306 entries[i]->Close();
307 if (enumerated_entry)
308 enumerated_entry->Close();
309 }
310
311 // The callback passed to the Keys() function.
312 ServiceWorkerCache::RequestsCallback original_callback;
313
314 // The vector of open entries in the backend.
315 Entries entries;
316
317 // The output of the Keys function.
318 scoped_ptr<ServiceWorkerCache::Requests> out_keys;
319
320 // Used for enumerating cache entries.
321 scoped_ptr<disk_cache::Backend::Iterator> backend_iterator;
322 disk_cache::Entry* enumerated_entry;
323
324 DISALLOW_COPY_AND_ASSIGN(KeysContext);
325 };
326
327 struct ServiceWorkerCache::MatchContext {
328 MatchContext(scoped_ptr<ServiceWorkerFetchRequest> request,
329 const ServiceWorkerCache::ResponseCallback& callback,
330 base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
331 : request(request.Pass()),
332 original_callback(callback),
333 blob_storage_context(blob_storage_context),
334 entry(nullptr),
335 total_bytes_read(0) {}
336
337 ~MatchContext() {
338 if (entry)
339 entry->Close();
340 }
341
342 // Input
343 scoped_ptr<ServiceWorkerFetchRequest> request;
344 ServiceWorkerCache::ResponseCallback original_callback;
345 base::WeakPtr<storage::BlobStorageContext> blob_storage_context;
346 disk_cache::Entry* entry;
347
348 // Output
349 scoped_ptr<ServiceWorkerResponse> response;
350 scoped_ptr<storage::BlobDataBuilder> blob_data;
351
352 // For reading the cache entry data into a blob.
353 scoped_refptr<net::IOBufferWithSize> response_body_buffer;
354 size_t total_bytes_read;
355
356 DISALLOW_COPY_AND_ASSIGN(MatchContext);
357 };
358
359 // The state needed to pass between ServiceWorkerCache::Put callbacks.
360 struct ServiceWorkerCache::PutContext {
361 PutContext(
362 const GURL& origin,
363 scoped_ptr<ServiceWorkerFetchRequest> request,
364 scoped_ptr<ServiceWorkerResponse> response,
365 scoped_ptr<storage::BlobDataHandle> blob_data_handle,
366 const ServiceWorkerCache::ResponseCallback& callback,
367 net::URLRequestContext* request_context,
368 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
369 : origin(origin),
370 request(request.Pass()),
371 response(response.Pass()),
372 blob_data_handle(blob_data_handle.Pass()),
373 callback(callback),
374 request_context(request_context),
375 quota_manager_proxy(quota_manager_proxy),
376 cache_entry(NULL) {}
377 ~PutContext() {
378 if (cache_entry)
379 cache_entry->Close();
380 }
381
382 // Input parameters to the Put function.
383 GURL origin;
384 scoped_ptr<ServiceWorkerFetchRequest> request;
385 scoped_ptr<ServiceWorkerResponse> response;
386 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
387 ServiceWorkerCache::ResponseCallback callback;
388 net::URLRequestContext* request_context;
389 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
390
391 // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
392 // CreateEntry.
393 disk_cache::Entry* cache_entry;
394
395 // The BlobDataHandle for the output ServiceWorkerResponse.
396 scoped_ptr<storage::BlobDataHandle> out_blob_data_handle;
397
398 DISALLOW_COPY_AND_ASSIGN(PutContext);
399 };
400
401 // static
402 scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache(
403 const GURL& origin,
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 ServiceWorkerCache(origin,
408 base::FilePath(),
409 request_context,
410 quota_manager_proxy,
411 blob_context));
412 }
413
414 // static
415 scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache(
416 const GURL& origin,
417 const base::FilePath& path,
418 net::URLRequestContext* request_context,
419 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
420 base::WeakPtr<storage::BlobStorageContext> blob_context) {
421 return make_scoped_refptr(new ServiceWorkerCache(
422 origin, path, request_context, quota_manager_proxy, blob_context));
423 }
424
425 ServiceWorkerCache::~ServiceWorkerCache() {
426 }
427
428 base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() {
429 return weak_ptr_factory_.GetWeakPtr();
430 }
431
432 void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request,
433 scoped_ptr<ServiceWorkerResponse> response,
434 const ResponseCallback& callback) {
435 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
436
437 if (!response->blob_uuid.empty()) {
438 if (!blob_storage_context_) {
439 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<ServiceWorkerResponse>(),
440 scoped_ptr<storage::BlobDataHandle>());
441 return;
442 }
443 blob_data_handle =
444 blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid);
445 if (!blob_data_handle) {
446 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<ServiceWorkerResponse>(),
447 scoped_ptr<storage::BlobDataHandle>());
448 return;
449 }
450 }
451
452 ResponseCallback pending_callback =
453 base::Bind(&ServiceWorkerCache::PendingResponseCallback,
454 weak_ptr_factory_.GetWeakPtr(), callback);
455
456 scoped_ptr<PutContext> put_context(new PutContext(
457 origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(),
458 pending_callback, request_context_, quota_manager_proxy_));
459
460 if (put_context->blob_data_handle) {
461 // Grab another handle to the blob for the callback response.
462 put_context->out_blob_data_handle =
463 blob_storage_context_->GetBlobDataFromUUID(
464 put_context->response->blob_uuid);
465 }
466
467 if (backend_state_ == BACKEND_UNINITIALIZED)
468 InitBackend();
469
470 scheduler_->ScheduleOperation(base::Bind(&ServiceWorkerCache::PutImpl,
471 weak_ptr_factory_.GetWeakPtr(),
472 base::Passed(put_context.Pass())));
473 }
474
475 void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request,
476 const ResponseCallback& callback) {
477 switch (backend_state_) {
478 case BACKEND_UNINITIALIZED:
479 InitBackend();
480 break;
481 case BACKEND_CLOSED:
482 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<ServiceWorkerResponse>(),
483 scoped_ptr<storage::BlobDataHandle>());
484 return;
485 case BACKEND_OPEN:
486 DCHECK(backend_);
487 break;
488 }
489
490 ResponseCallback pending_callback =
491 base::Bind(&ServiceWorkerCache::PendingResponseCallback,
492 weak_ptr_factory_.GetWeakPtr(), callback);
493 scheduler_->ScheduleOperation(
494 base::Bind(&ServiceWorkerCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(),
495 base::Passed(request.Pass()), pending_callback));
496 }
497
498 void ServiceWorkerCache::Delete(scoped_ptr<ServiceWorkerFetchRequest> request,
499 const ErrorCallback& callback) {
500 switch (backend_state_) {
501 case BACKEND_UNINITIALIZED:
502 InitBackend();
503 break;
504 case BACKEND_CLOSED:
505 callback.Run(ERROR_TYPE_STORAGE);
506 return;
507 case BACKEND_OPEN:
508 DCHECK(backend_);
509 break;
510 }
511 ErrorCallback pending_callback =
512 base::Bind(&ServiceWorkerCache::PendingErrorCallback,
513 weak_ptr_factory_.GetWeakPtr(), callback);
514 scheduler_->ScheduleOperation(base::Bind(
515 &ServiceWorkerCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(),
516 base::Passed(request.Pass()), pending_callback));
517 }
518
519 void ServiceWorkerCache::Keys(const RequestsCallback& callback) {
520 switch (backend_state_) {
521 case BACKEND_UNINITIALIZED:
522 InitBackend();
523 break;
524 case BACKEND_CLOSED:
525 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<Requests>());
526 return;
527 case BACKEND_OPEN:
528 DCHECK(backend_);
529 break;
530 }
531
532 RequestsCallback pending_callback =
533 base::Bind(&ServiceWorkerCache::PendingRequestsCallback,
534 weak_ptr_factory_.GetWeakPtr(), callback);
535 scheduler_->ScheduleOperation(base::Bind(&ServiceWorkerCache::KeysImpl,
536 weak_ptr_factory_.GetWeakPtr(),
537 pending_callback));
538 }
539
540 void ServiceWorkerCache::Close(const base::Closure& callback) {
541 DCHECK(backend_state_ != BACKEND_CLOSED)
542 << "Don't call ServiceWorkerCache::Close() twice.";
543
544 base::Closure pending_callback =
545 base::Bind(&ServiceWorkerCache::PendingClosure,
546 weak_ptr_factory_.GetWeakPtr(), callback);
547
548 scheduler_->ScheduleOperation(base::Bind(&ServiceWorkerCache::CloseImpl,
549 weak_ptr_factory_.GetWeakPtr(),
550 pending_callback));
551 }
552
553 int64 ServiceWorkerCache::MemoryBackedSize() const {
554 if (backend_state_ != BACKEND_OPEN || !memory_only_)
555 return 0;
556
557 scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
558 backend_->CreateIterator();
559 disk_cache::Entry* entry = nullptr;
560
561 int64 sum = 0;
562
563 std::vector<disk_cache::Entry*> entries;
564 int rv = net::OK;
565 while ((rv = backend_iter->OpenNextEntry(
566 &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
567 entries.push_back(entry); // Open the entries without mutating them.
568 }
569 DCHECK(rv !=
570 net::ERR_IO_PENDING); // Expect all memory ops to be synchronous.
571
572 for (disk_cache::Entry* entry : entries) {
573 sum += entry->GetDataSize(INDEX_HEADERS) +
574 entry->GetDataSize(INDEX_RESPONSE_BODY);
575 entry->Close();
576 }
577
578 return sum;
579 }
580
581 ServiceWorkerCache::ServiceWorkerCache(
582 const GURL& origin,
583 const base::FilePath& path,
584 net::URLRequestContext* request_context,
585 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
586 base::WeakPtr<storage::BlobStorageContext> blob_context)
587 : origin_(origin),
588 path_(path),
589 request_context_(request_context),
590 quota_manager_proxy_(quota_manager_proxy),
591 blob_storage_context_(blob_context),
592 backend_state_(BACKEND_UNINITIALIZED),
593 scheduler_(new ServiceWorkerCacheScheduler()),
594 initializing_(false),
595 memory_only_(path.empty()),
596 weak_ptr_factory_(this) {
597 }
598
599 void ServiceWorkerCache::MatchImpl(
600 scoped_ptr<ServiceWorkerFetchRequest> request,
601 const ResponseCallback& callback) {
602 DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
603 if (backend_state_ != BACKEND_OPEN) {
604 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<ServiceWorkerResponse>(),
605 scoped_ptr<storage::BlobDataHandle>());
606 return;
607 }
608
609 scoped_ptr<MatchContext> match_context(
610 new MatchContext(request.Pass(), callback, blob_storage_context_));
611
612 disk_cache::Entry** entry_ptr = &match_context->entry;
613 ServiceWorkerFetchRequest* request_ptr = match_context->request.get();
614
615 net::CompletionCallback open_entry_callback = base::Bind(
616 &ServiceWorkerCache::MatchDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
617 base::Passed(match_context.Pass()));
618
619 int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr,
620 open_entry_callback);
621 if (rv != net::ERR_IO_PENDING)
622 open_entry_callback.Run(rv);
623 }
624
625 void ServiceWorkerCache::MatchDidOpenEntry(
626 scoped_ptr<MatchContext> match_context,
627 int rv) {
628 if (rv != net::OK) {
629 match_context->original_callback.Run(
630 ServiceWorkerCache::ERROR_TYPE_NOT_FOUND,
631 scoped_ptr<ServiceWorkerResponse>(),
632 scoped_ptr<storage::BlobDataHandle>());
633 return;
634 }
635
636 // Copy the entry pointer before passing it in base::Bind.
637 disk_cache::Entry* tmp_entry_ptr = match_context->entry;
638 DCHECK(tmp_entry_ptr);
639
640 MetadataCallback headers_callback = base::Bind(
641 &ServiceWorkerCache::MatchDidReadMetadata, weak_ptr_factory_.GetWeakPtr(),
642 base::Passed(match_context.Pass()));
643
644 ReadMetadata(tmp_entry_ptr, headers_callback);
645 }
646
647 void ServiceWorkerCache::MatchDidReadMetadata(
648 scoped_ptr<MatchContext> match_context,
649 scoped_ptr<ServiceWorkerCacheMetadata> metadata) {
650 if (!metadata) {
651 match_context->original_callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE,
652 scoped_ptr<ServiceWorkerResponse>(),
653 scoped_ptr<storage::BlobDataHandle>());
654 return;
655 }
656
657 match_context->response.reset(new ServiceWorkerResponse(
658 match_context->request->url, metadata->response().status_code(),
659 metadata->response().status_text(),
660 ProtoResponseTypeToWebResponseType(metadata->response().response_type()),
661 ServiceWorkerHeaderMap(), "", 0, GURL()));
662
663 ServiceWorkerResponse* response = match_context->response.get();
664
665 if (metadata->response().has_url())
666 response->url = GURL(metadata->response().url());
667
668 for (int i = 0; i < metadata->response().headers_size(); ++i) {
669 const ServiceWorkerCacheHeaderMap header = metadata->response().headers(i);
670 DCHECK(header.name().find('\0') == std::string::npos);
671 DCHECK(header.value().find('\0') == std::string::npos);
672 response->headers.insert(std::make_pair(header.name(), header.value()));
673 }
674
675 ServiceWorkerHeaderMap cached_request_headers;
676 for (int i = 0; i < metadata->request().headers_size(); ++i) {
677 const ServiceWorkerCacheHeaderMap header = metadata->request().headers(i);
678 DCHECK(header.name().find('\0') == std::string::npos);
679 DCHECK(header.value().find('\0') == std::string::npos);
680 cached_request_headers[header.name()] = header.value();
681 }
682
683 if (!VaryMatches(match_context->request->headers, cached_request_headers,
684 response->headers)) {
685 match_context->original_callback.Run(
686 ServiceWorkerCache::ERROR_TYPE_NOT_FOUND,
687 scoped_ptr<ServiceWorkerResponse>(),
688 scoped_ptr<storage::BlobDataHandle>());
689 return;
690 }
691
692 if (match_context->entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
693 match_context->original_callback.Run(ServiceWorkerCache::ERROR_TYPE_OK,
694 match_context->response.Pass(),
695 scoped_ptr<storage::BlobDataHandle>());
696 return;
697 }
698
699 // Stream the response body into a blob.
700 if (!match_context->blob_storage_context) {
701 match_context->original_callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE,
702 scoped_ptr<ServiceWorkerResponse>(),
703 scoped_ptr<storage::BlobDataHandle>());
704 return;
705 }
706
707 response->blob_uuid = base::GenerateGUID();
708
709 match_context->blob_data.reset(
710 new storage::BlobDataBuilder(response->blob_uuid));
711 match_context->response_body_buffer = new net::IOBufferWithSize(kBufferSize);
712
713 disk_cache::Entry* tmp_entry_ptr = match_context->entry;
714 net::IOBufferWithSize* response_body_buffer =
715 match_context->response_body_buffer.get();
716
717 net::CompletionCallback read_callback = base::Bind(
718 &ServiceWorkerCache::MatchDidReadResponseBodyData,
719 weak_ptr_factory_.GetWeakPtr(), base::Passed(match_context.Pass()));
720
721 int read_rv =
722 tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, 0, response_body_buffer,
723 response_body_buffer->size(), read_callback);
724
725 if (read_rv != net::ERR_IO_PENDING)
726 read_callback.Run(read_rv);
727 }
728
729 void ServiceWorkerCache::MatchDidReadResponseBodyData(
730 scoped_ptr<MatchContext> match_context,
731 int rv) {
732 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
733 tracked_objects::ScopedTracker tracking_profile(
734 FROM_HERE_WITH_EXPLICIT_FUNCTION(
735 "422516 ServiceWorkerCache::MatchDidReadResponseBodyData"));
736
737 if (rv < 0) {
738 match_context->original_callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE,
739 scoped_ptr<ServiceWorkerResponse>(),
740 scoped_ptr<storage::BlobDataHandle>());
741 return;
742 }
743
744 if (rv == 0) {
745 match_context->response->blob_uuid = match_context->blob_data->uuid();
746 match_context->response->blob_size = match_context->total_bytes_read;
747 MatchDoneWithBody(match_context.Pass());
748 return;
749 }
750
751 // TODO(jkarlin): This copying of the the entire cache response into memory is
752 // awful. Create a new interface around SimpleCache that provides access the
753 // data directly from the file. See bug http://crbug.com/403493.
754 match_context->blob_data->AppendData(
755 match_context->response_body_buffer->data(), rv);
756 match_context->total_bytes_read += rv;
757 int total_bytes_read = match_context->total_bytes_read;
758
759 // Grab some pointers before passing match_context in bind.
760 net::IOBufferWithSize* buffer = match_context->response_body_buffer.get();
761 disk_cache::Entry* tmp_entry_ptr = match_context->entry;
762
763 net::CompletionCallback read_callback = base::Bind(
764 &ServiceWorkerCache::MatchDidReadResponseBodyData,
765 weak_ptr_factory_.GetWeakPtr(), base::Passed(match_context.Pass()));
766
767 int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, total_bytes_read,
768 buffer, buffer->size(), read_callback);
769
770 if (read_rv != net::ERR_IO_PENDING)
771 read_callback.Run(read_rv);
772 }
773
774 void ServiceWorkerCache::MatchDoneWithBody(
775 scoped_ptr<MatchContext> match_context) {
776 if (!match_context->blob_storage_context) {
777 match_context->original_callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE,
778 scoped_ptr<ServiceWorkerResponse>(),
779 scoped_ptr<storage::BlobDataHandle>());
780 return;
781 }
782
783 scoped_ptr<storage::BlobDataHandle> blob_data_handle(
784 match_context->blob_storage_context->AddFinishedBlob(
785 match_context->blob_data.get()));
786
787 match_context->original_callback.Run(ServiceWorkerCache::ERROR_TYPE_OK,
788 match_context->response.Pass(),
789 blob_data_handle.Pass());
790 }
791
792 void ServiceWorkerCache::PutImpl(scoped_ptr<PutContext> put_context) {
793 DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
794 if (backend_state_ != BACKEND_OPEN) {
795 put_context->callback.Run(ERROR_TYPE_STORAGE,
796 scoped_ptr<ServiceWorkerResponse>(),
797 scoped_ptr<storage::BlobDataHandle>());
798 return;
799 }
800
801 scoped_ptr<ServiceWorkerFetchRequest> request_copy(
802 new ServiceWorkerFetchRequest(*put_context->request));
803
804 DeleteImpl(request_copy.Pass(), base::Bind(&ServiceWorkerCache::PutDidDelete,
805 weak_ptr_factory_.GetWeakPtr(),
806 base::Passed(put_context.Pass())));
807 }
808
809 void ServiceWorkerCache::PutDidDelete(scoped_ptr<PutContext> put_context,
810 ErrorType delete_error) {
811 if (backend_state_ != BACKEND_OPEN) {
812 put_context->callback.Run(ERROR_TYPE_STORAGE,
813 scoped_ptr<ServiceWorkerResponse>(),
814 scoped_ptr<storage::BlobDataHandle>());
815 return;
816 }
817
818 disk_cache::Entry** entry_ptr = &put_context->cache_entry;
819 ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
820 disk_cache::Backend* backend_ptr = backend_.get();
821
822 net::CompletionCallback create_entry_callback = base::Bind(
823 &ServiceWorkerCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(),
824 base::Passed(put_context.Pass()));
825
826 int create_rv = backend_ptr->CreateEntry(
827 request_ptr->url.spec(), entry_ptr, create_entry_callback);
828
829 if (create_rv != net::ERR_IO_PENDING)
830 create_entry_callback.Run(create_rv);
831 }
832
833 void ServiceWorkerCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
834 int rv) {
835 if (rv != net::OK) {
836 put_context->callback.Run(ServiceWorkerCache::ERROR_TYPE_EXISTS,
837 scoped_ptr<ServiceWorkerResponse>(),
838 scoped_ptr<storage::BlobDataHandle>());
839 return;
840 }
841
842 DCHECK(put_context->cache_entry);
843
844 ServiceWorkerCacheMetadata metadata;
845 ServiceWorkerCacheRequest* request_metadata = metadata.mutable_request();
846 request_metadata->set_method(put_context->request->method);
847 for (ServiceWorkerHeaderMap::const_iterator it =
848 put_context->request->headers.begin();
849 it != put_context->request->headers.end();
850 ++it) {
851 DCHECK(it->first.find('\0') == std::string::npos);
852 DCHECK(it->second.find('\0') == std::string::npos);
853 ServiceWorkerCacheHeaderMap* header_map = request_metadata->add_headers();
854 header_map->set_name(it->first);
855 header_map->set_value(it->second);
856 }
857
858 ServiceWorkerCacheResponse* response_metadata = metadata.mutable_response();
859 response_metadata->set_status_code(put_context->response->status_code);
860 response_metadata->set_status_text(put_context->response->status_text);
861 response_metadata->set_response_type(
862 WebResponseTypeToProtoResponseType(put_context->response->response_type));
863 response_metadata->set_url(put_context->response->url.spec());
864 for (ServiceWorkerHeaderMap::const_iterator it =
865 put_context->response->headers.begin();
866 it != put_context->response->headers.end();
867 ++it) {
868 DCHECK(it->first.find('\0') == std::string::npos);
869 DCHECK(it->second.find('\0') == std::string::npos);
870 ServiceWorkerCacheHeaderMap* header_map = response_metadata->add_headers();
871 header_map->set_name(it->first);
872 header_map->set_value(it->second);
873 }
874
875 scoped_ptr<std::string> serialized(new std::string());
876 if (!metadata.SerializeToString(serialized.get())) {
877 put_context->callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE,
878 scoped_ptr<ServiceWorkerResponse>(),
879 scoped_ptr<storage::BlobDataHandle>());
880 return;
881 }
882
883 scoped_refptr<net::StringIOBuffer> buffer(
884 new net::StringIOBuffer(serialized.Pass()));
885
886 // Get a temporary copy of the entry pointer before passing it in base::Bind.
887 disk_cache::Entry* tmp_entry_ptr = put_context->cache_entry;
888
889 net::CompletionCallback write_headers_callback = base::Bind(
890 &ServiceWorkerCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(),
891 base::Passed(put_context.Pass()), buffer->size());
892
893 rv = tmp_entry_ptr->WriteData(INDEX_HEADERS,
894 0 /* offset */,
895 buffer.get(),
896 buffer->size(),
897 write_headers_callback,
898 true /* truncate */);
899
900 if (rv != net::ERR_IO_PENDING)
901 write_headers_callback.Run(rv);
902 }
903
904 void ServiceWorkerCache::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(ServiceWorkerCache::ERROR_TYPE_STORAGE,
910 scoped_ptr<ServiceWorkerResponse>(),
911 scoped_ptr<storage::BlobDataHandle>());
912 return;
913 }
914
915 // The metadata is written, now for the response content. The data is streamed
916 // from the blob into the cache entry.
917
918 if (put_context->response->blob_uuid.empty()) {
919 if (put_context->quota_manager_proxy.get()) {
920 put_context->quota_manager_proxy->NotifyStorageModified(
921 storage::QuotaClient::kServiceWorkerCache,
922 put_context->origin,
923 storage::kStorageTypeTemporary,
924 put_context->cache_entry->GetDataSize(INDEX_HEADERS));
925 }
926
927 put_context->callback.Run(ServiceWorkerCache::ERROR_TYPE_OK,
928 put_context->response.Pass(),
929 scoped_ptr<storage::BlobDataHandle>());
930 return;
931 }
932
933 DCHECK(put_context->blob_data_handle);
934
935 disk_cache::ScopedEntryPtr entry(put_context->cache_entry);
936 put_context->cache_entry = NULL;
937 scoped_ptr<BlobReader> reader(new BlobReader());
938 BlobReader* reader_ptr = reader.get();
939
940 // Grab some pointers before passing put_context in Bind.
941 net::URLRequestContext* request_context = put_context->request_context;
942 scoped_ptr<storage::BlobDataHandle> blob_data_handle =
943 put_context->blob_data_handle.Pass();
944
945 reader_ptr->StreamBlobToCache(
946 entry.Pass(), request_context, blob_data_handle.Pass(),
947 base::Bind(&ServiceWorkerCache::PutDidWriteBlobToCache,
948 weak_ptr_factory_.GetWeakPtr(),
949 base::Passed(put_context.Pass()),
950 base::Passed(reader.Pass())));
951 }
952
953 void ServiceWorkerCache::PutDidWriteBlobToCache(
954 scoped_ptr<PutContext> put_context,
955 scoped_ptr<BlobReader> blob_reader,
956 disk_cache::ScopedEntryPtr entry,
957 bool success) {
958 DCHECK(entry);
959 put_context->cache_entry = entry.release();
960
961 if (!success) {
962 put_context->cache_entry->Doom();
963 put_context->callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE,
964 scoped_ptr<ServiceWorkerResponse>(),
965 scoped_ptr<storage::BlobDataHandle>());
966 return;
967 }
968
969 if (put_context->quota_manager_proxy.get()) {
970 put_context->quota_manager_proxy->NotifyStorageModified(
971 storage::QuotaClient::kServiceWorkerCache,
972 put_context->origin,
973 storage::kStorageTypeTemporary,
974 put_context->cache_entry->GetDataSize(INDEX_HEADERS) +
975 put_context->cache_entry->GetDataSize(INDEX_RESPONSE_BODY));
976 }
977
978 put_context->callback.Run(ServiceWorkerCache::ERROR_TYPE_OK,
979 put_context->response.Pass(),
980 put_context->out_blob_data_handle.Pass());
981 }
982
983 void ServiceWorkerCache::DeleteImpl(
984 scoped_ptr<ServiceWorkerFetchRequest> request,
985 const ErrorCallback& callback) {
986 DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
987 if (backend_state_ != BACKEND_OPEN) {
988 callback.Run(ERROR_TYPE_STORAGE);
989 return;
990 }
991 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
992
993 disk_cache::Entry** entry_ptr = entry.get();
994
995 ServiceWorkerFetchRequest* request_ptr = request.get();
996
997 net::CompletionCallback open_entry_callback = base::Bind(
998 &ServiceWorkerCache::DeleteDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
999 origin_, base::Passed(request.Pass()), callback,
1000 base::Passed(entry.Pass()), quota_manager_proxy_);
1001
1002 int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr,
1003 open_entry_callback);
1004 if (rv != net::ERR_IO_PENDING)
1005 open_entry_callback.Run(rv);
1006 }
1007
1008 void ServiceWorkerCache::DeleteDidOpenEntry(
1009 const GURL& origin,
1010 scoped_ptr<ServiceWorkerFetchRequest> request,
1011 const ServiceWorkerCache::ErrorCallback& callback,
1012 scoped_ptr<disk_cache::Entry*> entry_ptr,
1013 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
1014 int rv) {
1015 if (rv != net::OK) {
1016 callback.Run(ServiceWorkerCache::ERROR_TYPE_NOT_FOUND);
1017 return;
1018 }
1019
1020 DCHECK(entry_ptr);
1021 disk_cache::ScopedEntryPtr entry(*entry_ptr);
1022
1023 if (quota_manager_proxy.get()) {
1024 quota_manager_proxy->NotifyStorageModified(
1025 storage::QuotaClient::kServiceWorkerCache, origin,
1026 storage::kStorageTypeTemporary,
1027 -1 * (entry->GetDataSize(INDEX_HEADERS) +
1028 entry->GetDataSize(INDEX_RESPONSE_BODY)));
1029 }
1030
1031 entry->Doom();
1032 callback.Run(ServiceWorkerCache::ERROR_TYPE_OK);
1033 }
1034
1035 void ServiceWorkerCache::KeysImpl(const RequestsCallback& callback) {
1036 DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
1037 if (backend_state_ != BACKEND_OPEN) {
1038 callback.Run(ERROR_TYPE_STORAGE, scoped_ptr<Requests>());
1039 return;
1040 }
1041
1042 // 1. Iterate through all of the entries, open them, and add them to a vector.
1043 // 2. For each open entry:
1044 // 2.1. Read the headers into a protobuf.
1045 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
1046 // 2.3. Push the response into a vector of requests to be returned.
1047 // 3. Return the vector of requests (keys).
1048
1049 // The entries have to be loaded into a vector first because enumeration loops
1050 // forever if you read data from a cache entry while enumerating.
1051
1052 scoped_ptr<KeysContext> keys_context(new KeysContext(callback));
1053
1054 keys_context->backend_iterator = backend_->CreateIterator();
1055 disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
1056 disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
1057
1058 net::CompletionCallback open_entry_callback = base::Bind(
1059 &ServiceWorkerCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(),
1060 base::Passed(keys_context.Pass()));
1061
1062 int rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
1063
1064 if (rv != net::ERR_IO_PENDING)
1065 open_entry_callback.Run(rv);
1066 }
1067
1068 void ServiceWorkerCache::KeysDidOpenNextEntry(
1069 scoped_ptr<KeysContext> keys_context,
1070 int rv) {
1071 if (rv == net::ERR_FAILED) {
1072 DCHECK(!keys_context->enumerated_entry);
1073 // Enumeration is complete, extract the requests from the entries.
1074 Entries::iterator iter = keys_context->entries.begin();
1075 KeysProcessNextEntry(keys_context.Pass(), iter);
1076 return;
1077 }
1078
1079 if (rv < 0) {
1080 keys_context->original_callback.Run(ERROR_TYPE_STORAGE,
1081 scoped_ptr<Requests>());
1082 return;
1083 }
1084
1085 if (backend_state_ != BACKEND_OPEN) {
1086 keys_context->original_callback.Run(ERROR_TYPE_NOT_FOUND,
1087 scoped_ptr<Requests>());
1088 return;
1089 }
1090
1091 // Store the entry.
1092 keys_context->entries.push_back(keys_context->enumerated_entry);
1093 keys_context->enumerated_entry = NULL;
1094
1095 // Enumerate the next entry.
1096 disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
1097 disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
1098 net::CompletionCallback open_entry_callback = base::Bind(
1099 &ServiceWorkerCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(),
1100 base::Passed(keys_context.Pass()));
1101
1102 rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
1103
1104 if (rv != net::ERR_IO_PENDING)
1105 open_entry_callback.Run(rv);
1106 }
1107
1108 void ServiceWorkerCache::KeysProcessNextEntry(
1109 scoped_ptr<KeysContext> keys_context,
1110 const Entries::iterator& iter) {
1111 if (iter == keys_context->entries.end()) {
1112 // All done. Return all of the keys.
1113 keys_context->original_callback.Run(ERROR_TYPE_OK,
1114 keys_context->out_keys.Pass());
1115 return;
1116 }
1117
1118 ReadMetadata(*iter, base::Bind(&ServiceWorkerCache::KeysDidReadMetadata,
1119 weak_ptr_factory_.GetWeakPtr(),
1120 base::Passed(keys_context.Pass()), iter));
1121 }
1122
1123 void ServiceWorkerCache::KeysDidReadMetadata(
1124 scoped_ptr<KeysContext> keys_context,
1125 const Entries::iterator& iter,
1126 scoped_ptr<ServiceWorkerCacheMetadata> metadata) {
1127 disk_cache::Entry* entry = *iter;
1128
1129 if (metadata) {
1130 keys_context->out_keys->push_back(
1131 ServiceWorkerFetchRequest(GURL(entry->GetKey()),
1132 metadata->request().method(),
1133 ServiceWorkerHeaderMap(),
1134 Referrer(),
1135 false));
1136
1137 ServiceWorkerHeaderMap& req_headers =
1138 keys_context->out_keys->back().headers;
1139
1140 for (int i = 0; i < metadata->request().headers_size(); ++i) {
1141 const ServiceWorkerCacheHeaderMap header = metadata->request().headers(i);
1142 DCHECK(header.name().find('\0') == std::string::npos);
1143 DCHECK(header.value().find('\0') == std::string::npos);
1144 req_headers.insert(std::make_pair(header.name(), header.value()));
1145 }
1146 } else {
1147 entry->Doom();
1148 }
1149
1150 KeysProcessNextEntry(keys_context.Pass(), iter + 1);
1151 }
1152
1153 void ServiceWorkerCache::CloseImpl(const base::Closure& callback) {
1154 DCHECK(backend_state_ != BACKEND_CLOSED);
1155
1156 backend_state_ = BACKEND_CLOSED;
1157 backend_.reset();
1158 callback.Run();
1159 }
1160
1161 void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) {
1162 DCHECK(!backend_);
1163
1164 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
1165 net::CacheType cache_type = memory_only_ ? net::MEMORY_CACHE : net::APP_CACHE;
1166
1167 scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr());
1168
1169 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
1170 ScopedBackendPtr* backend = backend_ptr.get();
1171
1172 net::CompletionCallback create_cache_callback =
1173 base::Bind(&ServiceWorkerCache::CreateBackendDidCreate,
1174 weak_ptr_factory_.GetWeakPtr(), callback,
1175 base::Passed(backend_ptr.Pass()));
1176
1177 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
1178 // has for disk caches.
1179 int rv = disk_cache::CreateCacheBackend(
1180 cache_type,
1181 net::CACHE_BACKEND_SIMPLE,
1182 path_,
1183 kMaxCacheBytes,
1184 false, /* force */
1185 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(),
1186 NULL,
1187 backend,
1188 create_cache_callback);
1189 if (rv != net::ERR_IO_PENDING)
1190 create_cache_callback.Run(rv);
1191 }
1192
1193 void ServiceWorkerCache::CreateBackendDidCreate(
1194 const ServiceWorkerCache::ErrorCallback& callback,
1195 scoped_ptr<ScopedBackendPtr> backend_ptr,
1196 int rv) {
1197 if (rv != net::OK) {
1198 callback.Run(ServiceWorkerCache::ERROR_TYPE_STORAGE);
1199 return;
1200 }
1201
1202 backend_ = backend_ptr->Pass();
1203 callback.Run(ServiceWorkerCache::ERROR_TYPE_OK);
1204 }
1205
1206 void ServiceWorkerCache::InitBackend() {
1207 DCHECK(backend_state_ == BACKEND_UNINITIALIZED);
1208
1209 if (initializing_)
1210 return;
1211
1212 DCHECK(!scheduler_->ScheduledOperations());
1213 initializing_ = true;
1214
1215 scheduler_->ScheduleOperation(base::Bind(
1216 &ServiceWorkerCache::CreateBackend, weak_ptr_factory_.GetWeakPtr(),
1217 base::Bind(&ServiceWorkerCache::InitDone,
1218 weak_ptr_factory_.GetWeakPtr())));
1219 }
1220
1221 void ServiceWorkerCache::InitDone(ErrorType error) {
1222 initializing_ = false;
1223 backend_state_ = (error == ERROR_TYPE_OK && backend_ &&
1224 backend_state_ == BACKEND_UNINITIALIZED)
1225 ? BACKEND_OPEN
1226 : BACKEND_CLOSED;
1227
1228 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", error,
1229 ErrorType::ERROR_TYPE_LAST + 1);
1230
1231 scheduler_->CompleteOperationAndRunNext();
1232 }
1233
1234 void ServiceWorkerCache::PendingClosure(const base::Closure& callback) {
1235 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1236
1237 callback.Run();
1238 if (cache)
1239 scheduler_->CompleteOperationAndRunNext();
1240 }
1241
1242 void ServiceWorkerCache::PendingErrorCallback(const ErrorCallback& callback,
1243 ErrorType error) {
1244 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1245
1246 callback.Run(error);
1247 if (cache)
1248 scheduler_->CompleteOperationAndRunNext();
1249 }
1250
1251 void ServiceWorkerCache::PendingResponseCallback(
1252 const ResponseCallback& callback,
1253 ErrorType error,
1254 scoped_ptr<ServiceWorkerResponse> response,
1255 scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
1256 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1257
1258 callback.Run(error, response.Pass(), blob_data_handle.Pass());
1259 if (cache)
1260 scheduler_->CompleteOperationAndRunNext();
1261 }
1262
1263 void ServiceWorkerCache::PendingRequestsCallback(
1264 const RequestsCallback& callback,
1265 ErrorType error,
1266 scoped_ptr<Requests> requests) {
1267 base::WeakPtr<ServiceWorkerCache> cache = weak_ptr_factory_.GetWeakPtr();
1268
1269 callback.Run(error, requests.Pass());
1270 if (cache)
1271 scheduler_->CompleteOperationAndRunNext();
1272 }
1273
1274 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/service_worker/service_worker_cache.h ('k') | content/browser/service_worker/service_worker_cache.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698