1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/service_worker/service_worker_cache.h"
9 #include "base/files/file_path.h"
10 #include "base/guid.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "content/browser/service_worker/service_worker_cache.pb.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/disk_cache/disk_cache.h"
17 #include "net/url_request/url_request_context.h"
18 #include "storage/browser/blob/blob_data_handle.h"
19 #include "storage/browser/blob/blob_storage_context.h"
20 #include "storage/browser/blob/blob_url_request_job_factory.h"
26 typedef scoped_ptr
<disk_cache::Backend
> ScopedBackendPtr
;
27 typedef base::Callback
<void(bool)> BoolCallback
;
28 typedef base::Callback
<void(disk_cache::ScopedEntryPtr
, bool)>
30 typedef base::Callback
<void(scoped_ptr
<ServiceWorkerRequestResponseHeaders
>)>
33 enum EntryIndex
{ INDEX_HEADERS
= 0, INDEX_RESPONSE_BODY
};
35 // The maximum size of an individual cache. Ultimately cache size is controlled
37 const int kMaxCacheBytes
= 512 * 1024 * 1024;
39 // Buffer size for cache and blob reading/writing.
40 const int kBufferSize
= 1024 * 512;
42 struct ResponseReadContext
{
43 ResponseReadContext(scoped_refptr
<net::IOBufferWithSize
> buff
,
44 scoped_refptr
<storage::BlobData
> blob
)
45 : buffer(buff
), blob_data(blob
), total_bytes_read(0) {}
47 scoped_refptr
<net::IOBufferWithSize
> buffer
;
48 scoped_refptr
<storage::BlobData
> blob_data
;
51 DISALLOW_COPY_AND_ASSIGN(ResponseReadContext
);
54 // Streams data from a blob and writes it to a given disk_cache::Entry.
55 class BlobReader
: public net::URLRequest::Delegate
{
57 typedef base::Callback
<void(disk_cache::ScopedEntryPtr
, bool)>
60 BlobReader(disk_cache::ScopedEntryPtr entry
)
61 : cache_entry_offset_(0),
62 buffer_(new net::IOBufferWithSize(kBufferSize
)),
63 weak_ptr_factory_(this) {
65 entry_
= entry
.Pass();
68 void StreamBlobToCache(net::URLRequestContext
* request_context
,
69 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
70 const EntryBoolCallback
& callback
) {
72 blob_request_
= storage::BlobProtocolHandler::CreateBlobRequest(
73 blob_data_handle
.Pass(), request_context
, this);
74 blob_request_
->Start();
77 // net::URLRequest::Delegate overrides for reading blobs.
78 virtual void OnReceivedRedirect(net::URLRequest
* request
,
79 const net::RedirectInfo
& redirect_info
,
80 bool* defer_redirect
) OVERRIDE
{
83 virtual void OnAuthRequired(net::URLRequest
* request
,
84 net::AuthChallengeInfo
* auth_info
) OVERRIDE
{
87 virtual void OnCertificateRequested(
88 net::URLRequest
* request
,
89 net::SSLCertRequestInfo
* cert_request_info
) OVERRIDE
{
92 virtual void OnSSLCertificateError(net::URLRequest
* request
,
93 const net::SSLInfo
& ssl_info
,
94 bool fatal
) OVERRIDE
{
97 virtual void OnBeforeNetworkStart(net::URLRequest
* request
,
98 bool* defer
) OVERRIDE
{
102 virtual void OnResponseStarted(net::URLRequest
* request
) OVERRIDE
{
103 if (!request
->status().is_success()) {
104 callback_
.Run(entry_
.Pass(), false);
110 virtual void ReadFromBlob() {
113 blob_request_
->Read(buffer_
.get(), buffer_
->size(), &bytes_read
);
115 OnReadCompleted(blob_request_
.get(), bytes_read
);
118 virtual void OnReadCompleted(net::URLRequest
* request
,
119 int bytes_read
) OVERRIDE
{
120 if (!request
->status().is_success()) {
121 callback_
.Run(entry_
.Pass(), false);
125 if (bytes_read
== 0) {
126 callback_
.Run(entry_
.Pass(), true);
130 net::CompletionCallback cache_write_callback
=
131 base::Bind(&BlobReader::DidWriteDataToEntry
,
132 weak_ptr_factory_
.GetWeakPtr(),
135 int rv
= entry_
->WriteData(INDEX_RESPONSE_BODY
,
139 cache_write_callback
,
140 true /* truncate */);
141 if (rv
!= net::ERR_IO_PENDING
)
142 cache_write_callback
.Run(rv
);
145 void DidWriteDataToEntry(int expected_bytes
, int rv
) {
146 if (rv
!= expected_bytes
) {
147 callback_
.Run(entry_
.Pass(), false);
151 cache_entry_offset_
+= rv
;
156 int cache_entry_offset_
;
157 disk_cache::ScopedEntryPtr entry_
;
158 scoped_ptr
<net::URLRequest
> blob_request_
;
159 EntryBoolCallback callback_
;
160 scoped_refptr
<net::IOBufferWithSize
> buffer_
;
161 base::WeakPtrFactory
<BlobReader
> weak_ptr_factory_
;
165 void PutDidCreateEntry(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
166 scoped_ptr
<ServiceWorkerResponse
> response
,
167 const ServiceWorkerCache::ErrorCallback
& callback
,
168 scoped_ptr
<disk_cache::Entry
*> entryptr
,
169 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
170 net::URLRequestContext
* request_context
,
172 void PutDidWriteHeaders(scoped_ptr
<ServiceWorkerResponse
> response
,
173 const ServiceWorkerCache::ErrorCallback
& callback
,
174 disk_cache::ScopedEntryPtr entry
,
175 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
176 net::URLRequestContext
* request_context
,
179 void PutDidWriteBlobToCache(const ServiceWorkerCache::ErrorCallback
& callback
,
180 scoped_ptr
<BlobReader
> blob_reader
,
181 disk_cache::ScopedEntryPtr entry
,
185 void MatchDidOpenEntry(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
186 const ServiceWorkerCache::ResponseCallback
& callback
,
187 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
188 scoped_ptr
<disk_cache::Entry
*> entryptr
,
190 void MatchDidReadHeaderData(
191 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
192 const ServiceWorkerCache::ResponseCallback
& callback
,
193 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
194 disk_cache::ScopedEntryPtr entry
,
195 scoped_ptr
<ServiceWorkerRequestResponseHeaders
> headers
);
196 void MatchDidReadResponseBodyData(
197 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
198 const ServiceWorkerCache::ResponseCallback
& callback
,
199 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
200 disk_cache::ScopedEntryPtr entry
,
201 scoped_ptr
<ServiceWorkerResponse
> response
,
202 scoped_ptr
<ResponseReadContext
> response_context
,
204 void MatchDoneWithBody(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
205 const ServiceWorkerCache::ResponseCallback
& callback
,
206 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
207 scoped_ptr
<ServiceWorkerResponse
> response
,
208 scoped_ptr
<ResponseReadContext
> response_context
);
211 void DeleteDidOpenEntry(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
212 const ServiceWorkerCache::ErrorCallback
& callback
,
213 scoped_ptr
<disk_cache::Entry
*> entryptr
,
216 // Copy headers out of a cache entry and into a protobuf. The callback is
217 // guaranteed to be run.
218 void ReadHeaders(disk_cache::Entry
* entry
, const HeadersCallback
& callback
);
219 void ReadHeadersDidReadHeaderData(
220 disk_cache::Entry
* entry
,
221 const HeadersCallback
& callback
,
222 const scoped_refptr
<net::IOBufferWithSize
>& buffer
,
225 // CreateBackend callbacks
226 void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback
& callback
,
227 scoped_ptr
<ScopedBackendPtr
> backend_ptr
,
228 base::WeakPtr
<ServiceWorkerCache
> cache
,
231 void PutDidCreateEntry(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
232 scoped_ptr
<ServiceWorkerResponse
> response
,
233 const ServiceWorkerCache::ErrorCallback
& callback
,
234 scoped_ptr
<disk_cache::Entry
*> entryptr
,
235 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
236 net::URLRequestContext
* request_context
,
239 callback
.Run(ServiceWorkerCache::ErrorTypeExists
);
244 disk_cache::ScopedEntryPtr
entry(*entryptr
);
246 ServiceWorkerRequestResponseHeaders headers
;
247 headers
.set_method(request
->method
);
249 headers
.set_status_code(response
->status_code
);
250 headers
.set_status_text(response
->status_text
);
251 for (std::map
<std::string
, std::string
>::const_iterator it
=
252 request
->headers
.begin();
253 it
!= request
->headers
.end();
255 ServiceWorkerRequestResponseHeaders::HeaderMap
* header_map
=
256 headers
.add_request_headers();
257 header_map
->set_name(it
->first
);
258 header_map
->set_value(it
->second
);
261 for (std::map
<std::string
, std::string
>::const_iterator it
=
262 response
->headers
.begin();
263 it
!= response
->headers
.end();
265 ServiceWorkerRequestResponseHeaders::HeaderMap
* header_map
=
266 headers
.add_response_headers();
267 header_map
->set_name(it
->first
);
268 header_map
->set_value(it
->second
);
271 scoped_ptr
<std::string
> serialized(new std::string());
272 if (!headers
.SerializeToString(serialized
.get())) {
273 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
);
277 scoped_refptr
<net::StringIOBuffer
> buffer(
278 new net::StringIOBuffer(serialized
.Pass()));
280 // Get a temporary copy of the entry pointer before passing it in base::Bind.
281 disk_cache::Entry
* tmp_entry_ptr
= entry
.get();
283 net::CompletionCallback write_headers_callback
=
284 base::Bind(PutDidWriteHeaders
,
285 base::Passed(response
.Pass()),
287 base::Passed(entry
.Pass()),
288 base::Passed(blob_data_handle
.Pass()),
292 rv
= tmp_entry_ptr
->WriteData(INDEX_HEADERS
,
296 write_headers_callback
,
297 true /* truncate */);
299 if (rv
!= net::ERR_IO_PENDING
)
300 write_headers_callback
.Run(rv
);
303 void PutDidWriteHeaders(scoped_ptr
<ServiceWorkerResponse
> response
,
304 const ServiceWorkerCache::ErrorCallback
& callback
,
305 disk_cache::ScopedEntryPtr entry
,
306 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
307 net::URLRequestContext
* request_context
,
310 if (rv
!= expected_bytes
) {
312 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
);
316 // The metadata is written, now for the response content. The data is streamed
317 // from the blob into the cache entry.
319 if (response
->blob_uuid
.empty()) {
320 callback
.Run(ServiceWorkerCache::ErrorTypeOK
);
324 DCHECK(blob_data_handle
);
326 scoped_ptr
<BlobReader
> reader(new BlobReader(entry
.Pass()));
327 BlobReader
* reader_ptr
= reader
.get();
329 reader_ptr
->StreamBlobToCache(
331 blob_data_handle
.Pass(),
333 PutDidWriteBlobToCache
, callback
, base::Passed(reader
.Pass())));
336 void PutDidWriteBlobToCache(const ServiceWorkerCache::ErrorCallback
& callback
,
337 scoped_ptr
<BlobReader
> blob_reader
,
338 disk_cache::ScopedEntryPtr entry
,
342 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
);
346 callback
.Run(ServiceWorkerCache::ErrorTypeOK
);
349 void MatchDidOpenEntry(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
350 const ServiceWorkerCache::ResponseCallback
& callback
,
351 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
352 scoped_ptr
<disk_cache::Entry
*> entryptr
,
355 callback
.Run(ServiceWorkerCache::ErrorTypeNotFound
,
356 scoped_ptr
<ServiceWorkerResponse
>(),
357 scoped_ptr
<storage::BlobDataHandle
>());
362 disk_cache::ScopedEntryPtr
entry(*entryptr
);
364 // Copy the entry pointer before passing it in base::Bind.
365 disk_cache::Entry
* tmp_entry_ptr
= entry
.get();
367 HeadersCallback headers_callback
= base::Bind(MatchDidReadHeaderData
,
368 base::Passed(request
.Pass()),
371 base::Passed(entry
.Pass()));
373 ReadHeaders(tmp_entry_ptr
, headers_callback
);
376 void MatchDidReadHeaderData(
377 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
378 const ServiceWorkerCache::ResponseCallback
& callback
,
379 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
380 disk_cache::ScopedEntryPtr entry
,
381 scoped_ptr
<ServiceWorkerRequestResponseHeaders
> headers
) {
383 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
384 scoped_ptr
<ServiceWorkerResponse
>(),
385 scoped_ptr
<storage::BlobDataHandle
>());
389 scoped_ptr
<ServiceWorkerResponse
> response(
390 new ServiceWorkerResponse(request
->url
,
391 headers
->status_code(),
392 headers
->status_text(),
393 std::map
<std::string
, std::string
>(),
396 for (int i
= 0; i
< headers
->response_headers_size(); ++i
) {
397 const ServiceWorkerRequestResponseHeaders::HeaderMap header
=
398 headers
->response_headers(i
);
399 response
->headers
.insert(std::make_pair(header
.name(), header
.value()));
402 // TODO(jkarlin): Insert vary validation here.
404 if (entry
->GetDataSize(INDEX_RESPONSE_BODY
) == 0) {
405 callback
.Run(ServiceWorkerCache::ErrorTypeOK
,
407 scoped_ptr
<storage::BlobDataHandle
>());
411 // Stream the response body into a blob.
413 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
414 scoped_ptr
<ServiceWorkerResponse
>(),
415 scoped_ptr
<storage::BlobDataHandle
>());
419 response
->blob_uuid
= base::GenerateGUID();
421 scoped_refptr
<storage::BlobData
> blob_data
=
422 new storage::BlobData(response
->blob_uuid
);
423 scoped_refptr
<net::IOBufferWithSize
> response_body_buffer(
424 new net::IOBufferWithSize(kBufferSize
));
426 scoped_ptr
<ResponseReadContext
> read_context(
427 new ResponseReadContext(response_body_buffer
, blob_data
));
429 // Copy the entry pointer before passing it in base::Bind.
430 disk_cache::Entry
* tmp_entry_ptr
= entry
.get();
432 net::CompletionCallback read_callback
=
433 base::Bind(MatchDidReadResponseBodyData
,
434 base::Passed(request
.Pass()),
437 base::Passed(entry
.Pass()),
438 base::Passed(response
.Pass()),
439 base::Passed(read_context
.Pass()));
441 int read_rv
= tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
,
443 response_body_buffer
.get(),
444 response_body_buffer
->size(),
447 if (read_rv
!= net::ERR_IO_PENDING
)
448 read_callback
.Run(read_rv
);
451 void MatchDidReadResponseBodyData(
452 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
453 const ServiceWorkerCache::ResponseCallback
& callback
,
454 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
455 disk_cache::ScopedEntryPtr entry
,
456 scoped_ptr
<ServiceWorkerResponse
> response
,
457 scoped_ptr
<ResponseReadContext
> response_context
,
460 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
461 scoped_ptr
<ServiceWorkerResponse
>(),
462 scoped_ptr
<storage::BlobDataHandle
>());
467 MatchDoneWithBody(request
.Pass(),
471 response_context
.Pass());
475 // TODO(jkarlin): This copying of the the entire cache response into memory is
476 // awful. Create a new interface around SimpleCache that provides access the
477 // data directly from the file. See bug http://crbug.com/403493.
478 response_context
->blob_data
->AppendData(response_context
->buffer
->data(), rv
);
479 response_context
->total_bytes_read
+= rv
;
480 int total_bytes_read
= response_context
->total_bytes_read
;
482 // Grab some pointers before passing them in bind.
483 net::IOBufferWithSize
* buffer
= response_context
->buffer
.get();
484 disk_cache::Entry
* tmp_entry_ptr
= entry
.get();
486 net::CompletionCallback read_callback
=
487 base::Bind(MatchDidReadResponseBodyData
,
488 base::Passed(request
.Pass()),
491 base::Passed(entry
.Pass()),
492 base::Passed(response
.Pass()),
493 base::Passed(response_context
.Pass()));
495 int read_rv
= tmp_entry_ptr
->ReadData(INDEX_RESPONSE_BODY
,
501 if (read_rv
!= net::ERR_IO_PENDING
)
502 read_callback
.Run(read_rv
);
505 void MatchDoneWithBody(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
506 const ServiceWorkerCache::ResponseCallback
& callback
,
507 base::WeakPtr
<storage::BlobStorageContext
> blob_storage
,
508 scoped_ptr
<ServiceWorkerResponse
> response
,
509 scoped_ptr
<ResponseReadContext
> response_context
) {
511 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
,
512 scoped_ptr
<ServiceWorkerResponse
>(),
513 scoped_ptr
<storage::BlobDataHandle
>());
517 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle(
518 blob_storage
->AddFinishedBlob(response_context
->blob_data
.get()));
520 callback
.Run(ServiceWorkerCache::ErrorTypeOK
,
522 blob_data_handle
.Pass());
525 void DeleteDidOpenEntry(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
526 const ServiceWorkerCache::ErrorCallback
& callback
,
527 scoped_ptr
<disk_cache::Entry
*> entryptr
,
530 callback
.Run(ServiceWorkerCache::ErrorTypeNotFound
);
535 disk_cache::ScopedEntryPtr
entry(*entryptr
);
538 callback
.Run(ServiceWorkerCache::ErrorTypeOK
);
541 void ReadHeaders(disk_cache::Entry
* entry
, const HeadersCallback
& callback
) {
544 scoped_refptr
<net::IOBufferWithSize
> buffer(
545 new net::IOBufferWithSize(entry
->GetDataSize(INDEX_HEADERS
)));
547 net::CompletionCallback read_header_callback
=
548 base::Bind(ReadHeadersDidReadHeaderData
, entry
, callback
, buffer
);
550 int read_rv
= entry
->ReadData(
551 INDEX_HEADERS
, 0, buffer
.get(), buffer
->size(), read_header_callback
);
553 if (read_rv
!= net::ERR_IO_PENDING
)
554 read_header_callback
.Run(read_rv
);
557 void ReadHeadersDidReadHeaderData(
558 disk_cache::Entry
* entry
,
559 const HeadersCallback
& callback
,
560 const scoped_refptr
<net::IOBufferWithSize
>& buffer
,
562 if (rv
!= buffer
->size()) {
563 callback
.Run(scoped_ptr
<ServiceWorkerRequestResponseHeaders
>());
567 scoped_ptr
<ServiceWorkerRequestResponseHeaders
> headers(
568 new ServiceWorkerRequestResponseHeaders());
570 if (!headers
->ParseFromArray(buffer
->data(), buffer
->size())) {
571 callback
.Run(scoped_ptr
<ServiceWorkerRequestResponseHeaders
>());
575 callback
.Run(headers
.Pass());
578 void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback
& callback
,
579 scoped_ptr
<ScopedBackendPtr
> backend_ptr
,
580 base::WeakPtr
<ServiceWorkerCache
> cache
,
582 if (rv
!= net::OK
|| !cache
) {
583 callback
.Run(ServiceWorkerCache::ErrorTypeStorage
);
587 cache
->set_backend(backend_ptr
->Pass());
588 callback
.Run(ServiceWorkerCache::ErrorTypeOK
);
593 // The state needed to pass between ServiceWorkerCache::Keys callbacks.
594 struct ServiceWorkerCache::KeysContext
{
595 KeysContext(const ServiceWorkerCache::RequestsCallback
& callback
,
596 base::WeakPtr
<ServiceWorkerCache
> cache
)
597 : original_callback(callback
),
599 out_keys(new ServiceWorkerCache::Requests()),
600 backend_iterator(NULL
),
601 enumerated_entry(NULL
) {}
604 for (size_t i
= 0, max
= entries
.size(); i
< max
; ++i
)
606 if (enumerated_entry
)
607 enumerated_entry
->Close();
608 if (cache
&& backend_iterator
&& cache
->backend_
)
609 cache
->backend_
->EndEnumeration(&backend_iterator
);
612 // The callback passed to the Keys() function.
613 ServiceWorkerCache::RequestsCallback original_callback
;
615 // The ServiceWorkerCache that Keys was called on.
616 base::WeakPtr
<ServiceWorkerCache
> cache
;
618 // The vector of open entries in the backend.
621 // The output of the Keys function.
622 scoped_ptr
<ServiceWorkerCache::Requests
> out_keys
;
624 // Used for enumerating cache entries.
625 void* backend_iterator
;
626 disk_cache::Entry
* enumerated_entry
;
630 scoped_refptr
<ServiceWorkerCache
> ServiceWorkerCache::CreateMemoryCache(
631 net::URLRequestContext
* request_context
,
632 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
633 return make_scoped_refptr(
634 new ServiceWorkerCache(base::FilePath(), request_context
, blob_context
));
638 scoped_refptr
<ServiceWorkerCache
> ServiceWorkerCache::CreatePersistentCache(
639 const base::FilePath
& path
,
640 net::URLRequestContext
* request_context
,
641 base::WeakPtr
<storage::BlobStorageContext
> blob_context
) {
642 return make_scoped_refptr(
643 new ServiceWorkerCache(path
, request_context
, blob_context
));
646 ServiceWorkerCache::~ServiceWorkerCache() {
649 base::WeakPtr
<ServiceWorkerCache
> ServiceWorkerCache::AsWeakPtr() {
650 return weak_ptr_factory_
.GetWeakPtr();
653 void ServiceWorkerCache::Put(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
654 scoped_ptr
<ServiceWorkerResponse
> response
,
655 const ErrorCallback
& callback
) {
656 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
658 if (!response
->blob_uuid
.empty()) {
659 if (!blob_storage_context_
) {
660 callback
.Run(ErrorTypeStorage
);
664 blob_storage_context_
->GetBlobDataFromUUID(response
->blob_uuid
);
665 if (!blob_data_handle
) {
666 callback
.Run(ErrorTypeStorage
);
671 base::Closure continuation
= base::Bind(&ServiceWorkerCache::PutImpl
,
672 weak_ptr_factory_
.GetWeakPtr(),
673 base::Passed(request
.Pass()),
674 base::Passed(response
.Pass()),
675 base::Passed(blob_data_handle
.Pass()),
686 void ServiceWorkerCache::Match(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
687 const ResponseCallback
& callback
) {
689 Init(base::Bind(&ServiceWorkerCache::Match
,
690 weak_ptr_factory_
.GetWeakPtr(),
691 base::Passed(request
.Pass()),
696 callback
.Run(ErrorTypeStorage
,
697 scoped_ptr
<ServiceWorkerResponse
>(),
698 scoped_ptr
<storage::BlobDataHandle
>());
702 scoped_ptr
<disk_cache::Entry
*> entry(new disk_cache::Entry
*);
704 disk_cache::Entry
** entry_ptr
= entry
.get();
706 ServiceWorkerFetchRequest
* request_ptr
= request
.get();
708 net::CompletionCallback open_entry_callback
=
709 base::Bind(MatchDidOpenEntry
,
710 base::Passed(request
.Pass()),
712 blob_storage_context_
,
713 base::Passed(entry
.Pass()));
715 int rv
= backend_
->OpenEntry(
716 request_ptr
->url
.spec(), entry_ptr
, open_entry_callback
);
717 if (rv
!= net::ERR_IO_PENDING
)
718 open_entry_callback
.Run(rv
);
721 void ServiceWorkerCache::Delete(scoped_ptr
<ServiceWorkerFetchRequest
> request
,
722 const ErrorCallback
& callback
) {
724 Init(base::Bind(&ServiceWorkerCache::Delete
,
725 weak_ptr_factory_
.GetWeakPtr(),
726 base::Passed(request
.Pass()),
731 callback
.Run(ErrorTypeStorage
);
735 scoped_ptr
<disk_cache::Entry
*> entry(new disk_cache::Entry
*);
737 disk_cache::Entry
** entry_ptr
= entry
.get();
739 ServiceWorkerFetchRequest
* request_ptr
= request
.get();
741 net::CompletionCallback open_entry_callback
=
742 base::Bind(DeleteDidOpenEntry
,
743 base::Passed(request
.Pass()),
745 base::Passed(entry
.Pass()));
747 int rv
= backend_
->OpenEntry(
748 request_ptr
->url
.spec(), entry_ptr
, open_entry_callback
);
749 if (rv
!= net::ERR_IO_PENDING
)
750 open_entry_callback
.Run(rv
);
753 void ServiceWorkerCache::Keys(const RequestsCallback
& callback
) {
756 &ServiceWorkerCache::Keys
, weak_ptr_factory_
.GetWeakPtr(), callback
));
760 callback
.Run(ErrorTypeStorage
, scoped_ptr
<Requests
>());
764 // 1. Iterate through all of the entries, open them, and add them to a vector.
765 // 2. For each open entry:
766 // 2.1. Read the headers into a protobuf.
767 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
768 // 2.3. Push the response into a vector of requests to be returned.
769 // 3. Return the vector of requests (keys).
771 // The entries have to be loaded into a vector first because enumeration loops
772 // forever if you read data from a cache entry while enumerating.
774 scoped_ptr
<KeysContext
> keys_context(
775 new KeysContext(callback
, weak_ptr_factory_
.GetWeakPtr()));
777 void** backend_iterator
= &keys_context
->backend_iterator
;
778 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
780 net::CompletionCallback open_entry_callback
=
781 base::Bind(KeysDidOpenNextEntry
, base::Passed(keys_context
.Pass()));
783 int rv
= backend_
->OpenNextEntry(
784 backend_iterator
, enumerated_entry
, open_entry_callback
);
786 if (rv
!= net::ERR_IO_PENDING
)
787 open_entry_callback
.Run(rv
);
790 void ServiceWorkerCache::Close() {
794 ServiceWorkerCache::ServiceWorkerCache(
795 const base::FilePath
& path
,
796 net::URLRequestContext
* request_context
,
797 base::WeakPtr
<storage::BlobStorageContext
> blob_context
)
799 request_context_(request_context
),
800 blob_storage_context_(blob_context
),
802 weak_ptr_factory_(this) {
805 void ServiceWorkerCache::PutImpl(
806 scoped_ptr
<ServiceWorkerFetchRequest
> request
,
807 scoped_ptr
<ServiceWorkerResponse
> response
,
808 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
,
809 const ErrorCallback
& callback
) {
811 callback
.Run(ErrorTypeStorage
);
815 scoped_ptr
<disk_cache::Entry
*> entry(new disk_cache::Entry
*);
817 disk_cache::Entry
** entry_ptr
= entry
.get();
819 ServiceWorkerFetchRequest
* request_ptr
= request
.get();
821 net::CompletionCallback create_entry_callback
=
822 base::Bind(PutDidCreateEntry
,
823 base::Passed(request
.Pass()),
824 base::Passed(response
.Pass()),
826 base::Passed(entry
.Pass()),
827 base::Passed(blob_data_handle
.Pass()),
830 int rv
= backend_
->CreateEntry(
831 request_ptr
->url
.spec(), entry_ptr
, create_entry_callback
);
833 if (rv
!= net::ERR_IO_PENDING
)
834 create_entry_callback
.Run(rv
);
838 void ServiceWorkerCache::KeysDidOpenNextEntry(
839 scoped_ptr
<KeysContext
> keys_context
,
841 if (rv
== net::ERR_FAILED
) {
842 DCHECK(!keys_context
->enumerated_entry
);
843 // Enumeration is complete, extract the requests from the entries.
844 Entries::iterator iter
= keys_context
->entries
.begin();
845 KeysProcessNextEntry(keys_context
.Pass(), iter
);
849 base::WeakPtr
<ServiceWorkerCache
> cache
= keys_context
->cache
;
850 if (rv
< 0 || !cache
) {
851 keys_context
->original_callback
.Run(ErrorTypeStorage
,
852 scoped_ptr
<Requests
>());
856 if (!cache
->backend_
) {
857 keys_context
->original_callback
.Run(ErrorTypeNotFound
,
858 scoped_ptr
<Requests
>());
863 keys_context
->entries
.push_back(keys_context
->enumerated_entry
);
864 keys_context
->enumerated_entry
= NULL
;
866 // Enumerate the next entry.
867 void** backend_iterator
= &keys_context
->backend_iterator
;
868 disk_cache::Entry
** enumerated_entry
= &keys_context
->enumerated_entry
;
870 net::CompletionCallback open_entry_callback
=
871 base::Bind(KeysDidOpenNextEntry
, base::Passed(keys_context
.Pass()));
873 rv
= cache
->backend_
->OpenNextEntry(
874 backend_iterator
, enumerated_entry
, open_entry_callback
);
876 if (rv
!= net::ERR_IO_PENDING
)
877 open_entry_callback
.Run(rv
);
881 void ServiceWorkerCache::KeysProcessNextEntry(
882 scoped_ptr
<KeysContext
> keys_context
,
883 const Entries::iterator
& iter
) {
884 if (iter
== keys_context
->entries
.end()) {
885 // All done. Return all of the keys.
886 keys_context
->original_callback
.Run(ErrorTypeOK
,
887 keys_context
->out_keys
.Pass());
893 base::Bind(KeysDidReadHeaders
, base::Passed(keys_context
.Pass()), iter
));
897 void ServiceWorkerCache::KeysDidReadHeaders(
898 scoped_ptr
<KeysContext
> keys_context
,
899 const Entries::iterator
& iter
,
900 scoped_ptr
<ServiceWorkerRequestResponseHeaders
> headers
) {
901 disk_cache::Entry
* entry
= *iter
;
904 keys_context
->out_keys
->push_back(
905 ServiceWorkerFetchRequest(GURL(entry
->GetKey()),
907 std::map
<std::string
, std::string
>(),
911 std::map
<std::string
, std::string
>& req_headers
=
912 keys_context
->out_keys
->back().headers
;
914 for (int i
= 0; i
< headers
->request_headers_size(); ++i
) {
915 const ServiceWorkerRequestResponseHeaders::HeaderMap header
=
916 headers
->request_headers(i
);
917 req_headers
.insert(std::make_pair(header
.name(), header
.value()));
923 KeysProcessNextEntry(keys_context
.Pass(), iter
+ 1);
926 void ServiceWorkerCache::CreateBackend(const ErrorCallback
& callback
) {
929 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
930 net::CacheType cache_type
=
931 path_
.empty() ? net::MEMORY_CACHE
: net::APP_CACHE
;
933 scoped_ptr
<ScopedBackendPtr
> backend_ptr(new ScopedBackendPtr());
935 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
936 ScopedBackendPtr
* backend
= backend_ptr
.get();
938 net::CompletionCallback create_cache_callback
=
939 base::Bind(CreateBackendDidCreate
,
941 base::Passed(backend_ptr
.Pass()),
942 weak_ptr_factory_
.GetWeakPtr());
944 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
945 // has for disk caches.
946 int rv
= disk_cache::CreateCacheBackend(
948 net::CACHE_BACKEND_SIMPLE
,
952 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE
).get(),
955 create_cache_callback
);
956 if (rv
!= net::ERR_IO_PENDING
)
957 create_cache_callback
.Run(rv
);
960 void ServiceWorkerCache::Init(const base::Closure
& callback
) {
961 init_callbacks_
.push_back(callback
);
963 // If this isn't the first call to Init then return as the initialization
964 // has already started.
965 if (init_callbacks_
.size() > 1u)
968 CreateBackend(base::Bind(&ServiceWorkerCache::InitDone
,
969 weak_ptr_factory_
.GetWeakPtr()));
972 void ServiceWorkerCache::InitDone(ErrorType error
) {
974 for (std::vector
<base::Closure
>::iterator it
= init_callbacks_
.begin();
975 it
!= init_callbacks_
.end();
979 init_callbacks_
.clear();
982 } // namespace content