Index: content/browser/service_worker/service_worker_cache.cc |
diff --git a/content/browser/service_worker/service_worker_cache.cc b/content/browser/service_worker/service_worker_cache.cc |
index 6a63b6b3e37d2dac223c3d911def4bc2636f3135..59fbbd4747a849df3034423e55c3be171e6ae993 100644 |
--- a/content/browser/service_worker/service_worker_cache.cc |
+++ b/content/browser/service_worker/service_worker_cache.cc |
@@ -22,11 +22,20 @@ |
namespace content { |
namespace { |
+struct EntriesDeleter; |
typedef scoped_ptr<disk_cache::Backend> ScopedBackendPtr; |
typedef base::Callback<void(bool)> BoolCallback; |
typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)> |
EntryBoolCallback; |
+typedef base::Callback<void(scoped_ptr<ServiceWorkerRequestResponseHeaders>)> |
+ HeadersCallback; |
+typedef std::vector<disk_cache::Entry*> Entries; |
+ |
+// Automatically closes all of the entries in the vector when it goes out of |
+// scope. |
+typedef scoped_ptr<Entries, EntriesDeleter> ScopedEntriesPtr; |
+ |
enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY }; |
// The maximum size of an individual cache. Ultimately cache size is controlled |
@@ -36,6 +45,13 @@ const int kMaxCacheBytes = 512 * 1024 * 1024; |
// Buffer size for cache and blob reading/writing. |
const int kBufferSize = 1024 * 512; |
+struct EntriesDeleter { |
+ void operator()(Entries* entries) { |
+ for (size_t i = 0, max = entries->size(); i < max; ++i) |
+ entries->at(i)->Close(); |
michaeln
2014/08/27 23:45:20
delete entries too?
jkarlin
2014/08/28 15:16:11
Done.
|
+ } |
+}; |
+ |
struct ResponseReadContext { |
ResponseReadContext(scoped_refptr<net::IOBufferWithSize> buff, |
scoped_refptr<storage::BlobData> blob) |
@@ -189,8 +205,7 @@ void MatchDidReadHeaderData( |
const ServiceWorkerCache::ResponseCallback& callback, |
base::WeakPtr<storage::BlobStorageContext> blob_storage, |
disk_cache::ScopedEntryPtr entry, |
- const scoped_refptr<net::IOBufferWithSize>& buffer, |
- int rv); |
+ scoped_ptr<ServiceWorkerRequestResponseHeaders> headers); |
void MatchDidReadResponseBodyData( |
ServiceWorkerFetchRequest* request, |
const ServiceWorkerCache::ResponseCallback& callback, |
@@ -211,6 +226,33 @@ void DeleteDidOpenEntry(ServiceWorkerFetchRequest* request, |
scoped_ptr<disk_cache::Entry*> entryptr, |
int rv); |
+// Keys callback |
+void KeysDidOpenNextEntry(const ServiceWorkerCache::RequestsCallback& callback, |
+ base::WeakPtr<ServiceWorkerCache> cache, |
+ scoped_ptr<void*> iter, |
+ scoped_ptr<disk_cache::Entry*> entryptr, |
+ ScopedEntriesPtr entries, |
+ int rv); |
+void KeysProcessNextEntry(const ServiceWorkerCache::RequestsCallback& callback, |
+ scoped_ptr<ServiceWorkerCache::Requests> requests, |
+ ScopedEntriesPtr entries, |
+ const Entries::iterator& iter); |
+void KeysDidReadHeaders( |
+ const ServiceWorkerCache::RequestsCallback& callback, |
+ scoped_ptr<ServiceWorkerCache::Requests> out_requests, |
+ ScopedEntriesPtr entries, |
+ const Entries::iterator& iter, |
+ scoped_ptr<ServiceWorkerRequestResponseHeaders> headers); |
+ |
+// Copy headers out of a cache entry and into a protobuf. The callback is |
+// guaranteed to be run. |
+void ReadHeaders(disk_cache::Entry* entry, const HeadersCallback& callback); |
+void ReadHeadersDidReadHeaderData( |
+ disk_cache::Entry* entry, |
+ const HeadersCallback& callback, |
+ const scoped_refptr<net::IOBufferWithSize>& buffer, |
+ int rv); |
+ |
// CreateBackend callbacks |
void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback& callback, |
scoped_ptr<ScopedBackendPtr> backend_ptr, |
@@ -224,10 +266,8 @@ void PutDidCreateEntry(ServiceWorkerFetchRequest* request, |
scoped_ptr<storage::BlobDataHandle> blob_data_handle, |
net::URLRequestContext* request_context, |
int rv) { |
- if (rv != net::OK) { |
- callback.Run(ServiceWorkerCache::ErrorTypeExists); |
- return; |
- } |
+ if (rv != net::OK) |
+ return callback.Run(ServiceWorkerCache::ErrorTypeExists); |
DCHECK(entryptr); |
disk_cache::ScopedEntryPtr entry(*entryptr); |
@@ -258,10 +298,8 @@ void PutDidCreateEntry(ServiceWorkerFetchRequest* request, |
} |
scoped_ptr<std::string> serialized(new std::string()); |
- if (!headers.SerializeToString(serialized.get())) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
- return; |
- } |
+ if (!headers.SerializeToString(serialized.get())) |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
scoped_refptr<net::StringIOBuffer> buffer( |
new net::StringIOBuffer(serialized.Pass())); |
@@ -298,17 +336,14 @@ void PutDidWriteHeaders(ServiceWorkerResponse* response, |
int rv) { |
if (rv != expected_bytes) { |
entry->Doom(); |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
} |
// The metadata is written, now for the response content. The data is streamed |
// from the blob into the cache entry. |
- if (response->blob_uuid.empty()) { |
- callback.Run(ServiceWorkerCache::ErrorTypeOK); |
- return; |
- } |
+ if (response->blob_uuid.empty()) |
+ return callback.Run(ServiceWorkerCache::ErrorTypeOK); |
DCHECK(blob_data_handle); |
@@ -328,8 +363,7 @@ void PutDidWriteBlobToCache(const ServiceWorkerCache::ErrorCallback& callback, |
bool success) { |
if (!success) { |
entry->Doom(); |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
} |
callback.Run(ServiceWorkerCache::ErrorTypeOK); |
@@ -341,34 +375,24 @@ void MatchDidOpenEntry(ServiceWorkerFetchRequest* request, |
scoped_ptr<disk_cache::Entry*> entryptr, |
int rv) { |
if (rv != net::OK) { |
- callback.Run(ServiceWorkerCache::ErrorTypeNotFound, |
- scoped_ptr<ServiceWorkerResponse>(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeNotFound, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<storage::BlobDataHandle>()); |
} |
DCHECK(entryptr); |
disk_cache::ScopedEntryPtr entry(*entryptr); |
- scoped_refptr<net::IOBufferWithSize> buffer( |
- new net::IOBufferWithSize(entry->GetDataSize(INDEX_HEADERS))); |
- |
// Copy the entry pointer before passing it in base::Bind. |
disk_cache::Entry* tmp_entry_ptr = entry.get(); |
- net::CompletionCallback read_header_callback = |
- base::Bind(MatchDidReadHeaderData, |
- request, |
- callback, |
- blob_storage, |
- base::Passed(entry.Pass()), |
- buffer); |
- |
- int read_rv = tmp_entry_ptr->ReadData( |
- INDEX_HEADERS, 0, buffer.get(), buffer->size(), read_header_callback); |
+ HeadersCallback headers_callback = base::Bind(MatchDidReadHeaderData, |
+ request, |
+ callback, |
+ blob_storage, |
+ base::Passed(entry.Pass())); |
- if (read_rv != net::ERR_IO_PENDING) |
- read_header_callback.Run(read_rv); |
+ ReadHeaders(tmp_entry_ptr, headers_callback); |
} |
void MatchDidReadHeaderData( |
@@ -376,55 +400,39 @@ void MatchDidReadHeaderData( |
const ServiceWorkerCache::ResponseCallback& callback, |
base::WeakPtr<storage::BlobStorageContext> blob_storage, |
disk_cache::ScopedEntryPtr entry, |
- const scoped_refptr<net::IOBufferWithSize>& buffer, |
- int rv) { |
- if (rv != buffer->size()) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
- scoped_ptr<ServiceWorkerResponse>(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- |
- return; |
- } |
- |
- ServiceWorkerRequestResponseHeaders headers; |
- |
- if (!headers.ParseFromArray(buffer->data(), buffer->size())) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
- scoped_ptr<ServiceWorkerResponse>(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- |
- return; |
+ scoped_ptr<ServiceWorkerRequestResponseHeaders> headers) { |
+ if (!headers) { |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<storage::BlobDataHandle>()); |
} |
scoped_ptr<ServiceWorkerResponse> response( |
new ServiceWorkerResponse(request->url, |
- headers.status_code(), |
- headers.status_text(), |
+ headers->status_code(), |
+ headers->status_text(), |
std::map<std::string, std::string>(), |
"")); |
- for (int i = 0; i < headers.response_headers_size(); ++i) { |
+ for (int i = 0; i < headers->response_headers_size(); ++i) { |
const ServiceWorkerRequestResponseHeaders::HeaderMap header = |
- headers.response_headers(i); |
+ headers->response_headers(i); |
response->headers.insert(std::make_pair(header.name(), header.value())); |
} |
// TODO(jkarlin): Insert vary validation here. |
if (entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) { |
- callback.Run(ServiceWorkerCache::ErrorTypeOK, |
- response.Pass(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeOK, |
+ response.Pass(), |
+ scoped_ptr<storage::BlobDataHandle>()); |
} |
// Stream the response body into a blob. |
if (!blob_storage) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
- scoped_ptr<ServiceWorkerResponse>(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<storage::BlobDataHandle>()); |
} |
response->blob_uuid = base::GenerateGUID(); |
@@ -468,10 +476,9 @@ void MatchDidReadResponseBodyData( |
scoped_ptr<ResponseReadContext> response_context, |
int rv) { |
if (rv < 0) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
- scoped_ptr<ServiceWorkerResponse>(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<storage::BlobDataHandle>()); |
} |
if (rv == 0) { |
@@ -519,10 +526,9 @@ void MatchDoneWithBody(ServiceWorkerFetchRequest* request, |
scoped_ptr<ServiceWorkerResponse> response, |
scoped_ptr<ResponseReadContext> response_context) { |
if (!blob_storage) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
- scoped_ptr<ServiceWorkerResponse>(), |
- scoped_ptr<storage::BlobDataHandle>()); |
- return; |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<storage::BlobDataHandle>()); |
} |
scoped_ptr<storage::BlobDataHandle> blob_data_handle( |
@@ -537,10 +543,8 @@ void DeleteDidOpenEntry(ServiceWorkerFetchRequest* request, |
const ServiceWorkerCache::ErrorCallback& callback, |
scoped_ptr<disk_cache::Entry*> entryptr, |
int rv) { |
- if (rv != net::OK) { |
- callback.Run(ServiceWorkerCache::ErrorTypeNotFound); |
- return; |
- } |
+ if (rv != net::OK) |
+ return callback.Run(ServiceWorkerCache::ErrorTypeNotFound); |
DCHECK(entryptr); |
disk_cache::ScopedEntryPtr entry(*entryptr); |
@@ -549,14 +553,135 @@ void DeleteDidOpenEntry(ServiceWorkerFetchRequest* request, |
callback.Run(ServiceWorkerCache::ErrorTypeOK); |
} |
+void KeysDidOpenNextEntry(const ServiceWorkerCache::RequestsCallback& callback, |
+ base::WeakPtr<ServiceWorkerCache> cache, |
+ scoped_ptr<void*> iter, |
michaeln
2014/08/27 23:45:20
might be nice to distinguish the void* iter from t
jkarlin
2014/08/28 15:16:11
Done.
|
+ scoped_ptr<disk_cache::Entry*> entryptr, |
+ ScopedEntriesPtr entries, |
+ int rv) { |
+ if (rv == net::ERR_FAILED) { |
+ // Enumeration is complete, extract the requests from the entries. |
+ Entries::iterator iter = entries->begin(); |
+ scoped_ptr<ServiceWorkerCache::Requests> out_requests( |
+ new ServiceWorkerCache::Requests()); |
michaeln
2014/08/27 23:45:20
ah ha, here's where the collection to hold the res
jkarlin
2014/08/28 15:16:10
Done.
|
+ return KeysProcessNextEntry( |
michaeln
2014/08/27 23:45:20
its odd to see return <something> in a function wi
jkarlin
2014/08/28 15:16:10
Done for the whole file.
|
+ callback, out_requests.Pass(), entries.Pass(), iter); |
+ } |
+ |
+ if (rv < 0 || !cache) { |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerCache::Requests>()); |
+ } |
+ |
+ entries->push_back(*entryptr); |
+ |
+ void** iter_ptr = iter.get(); |
+ disk_cache::Entry** entry_ptr = entryptr.get(); |
+ |
+ net::CompletionCallback open_entry_callback = |
+ base::Bind(KeysDidOpenNextEntry, |
+ callback, |
+ cache, |
+ base::Passed(iter.Pass()), |
+ base::Passed(entryptr.Pass()), |
+ base::Passed(entries.Pass())); |
+ |
+ // Enumerate the next entry. |
+ int rvv = |
michaeln
2014/08/27 23:45:20
looks like you could just use the existing paramet
jkarlin
2014/08/28 15:16:11
Done.
|
+ cache->backend()->OpenNextEntry(iter_ptr, entry_ptr, open_entry_callback); |
michaeln
2014/08/27 23:45:20
i was wondering what caused backend() to be added
jkarlin
2014/08/28 15:16:10
You're right, better to hide backend. I'm not gai
|
+ |
+ if (rvv != net::ERR_IO_PENDING) |
+ open_entry_callback.Run(rvv); |
+} |
+ |
+void KeysProcessNextEntry(const ServiceWorkerCache::RequestsCallback& callback, |
+ scoped_ptr<ServiceWorkerCache::Requests> requests, |
+ ScopedEntriesPtr entries, |
+ const Entries::iterator& iter) { |
+ if (iter == entries->end()) |
+ return callback.Run(ServiceWorkerCache::ErrorTypeOK, requests.Pass()); |
michaeln
2014/08/27 23:45:20
This is the end of the line in the expected case,
jkarlin
2014/08/28 15:16:11
Done.
|
+ |
+ ReadHeaders(*iter, |
+ base::Bind(KeysDidReadHeaders, |
+ callback, |
+ base::Passed(requests.Pass()), |
+ base::Passed(entries.Pass()), |
+ iter)); |
+} |
+ |
+void KeysDidReadHeaders( |
+ const ServiceWorkerCache::RequestsCallback& callback, |
+ scoped_ptr<ServiceWorkerCache::Requests> out_requests, |
+ ScopedEntriesPtr entries, |
+ const Entries::iterator& iter, |
+ scoped_ptr<ServiceWorkerRequestResponseHeaders> headers) { |
+ disk_cache::Entry* entry = *iter; |
+ |
+ if (!headers) { |
+ entry->Doom(); |
michaeln
2014/08/27 23:45:20
Interesting, a subsequent call to Keys() will yeil
jkarlin
2014/08/28 15:16:10
Done.
|
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage, |
+ out_requests.Pass()); |
+ } |
+ |
+ out_requests->push_back( |
+ ServiceWorkerFetchRequest(GURL(entry->GetKey()), |
+ headers->method(), |
+ std::map<std::string, std::string>(), |
+ GURL(), |
+ false)); |
+ |
+ std::map<std::string, std::string>& req_headers = |
+ out_requests->back().headers; |
+ |
+ for (int i = 0; i < headers->request_headers_size(); ++i) { |
+ const ServiceWorkerRequestResponseHeaders::HeaderMap header = |
+ headers->request_headers(i); |
+ req_headers.insert(std::make_pair(header.name(), header.value())); |
+ } |
+ |
+ KeysProcessNextEntry(callback, out_requests.Pass(), entries.Pass(), iter + 1); |
+} |
+ |
+void ReadHeaders(disk_cache::Entry* entry, const HeadersCallback& callback) { |
+ DCHECK(entry); |
+ |
+ scoped_refptr<net::IOBufferWithSize> buffer( |
+ new net::IOBufferWithSize(entry->GetDataSize(INDEX_HEADERS))); |
+ |
+ net::CompletionCallback read_header_callback = |
+ base::Bind(ReadHeadersDidReadHeaderData, entry, callback, buffer); |
+ |
+ int read_rv = entry->ReadData( |
+ INDEX_HEADERS, 0, buffer.get(), buffer->size(), read_header_callback); |
+ |
+ if (read_rv != net::ERR_IO_PENDING) |
+ read_header_callback.Run(read_rv); |
+} |
+ |
+void ReadHeadersDidReadHeaderData( |
+ disk_cache::Entry* entry, |
+ const HeadersCallback& callback, |
+ const scoped_refptr<net::IOBufferWithSize>& buffer, |
+ int rv) { |
+ if (rv != buffer->size()) |
+ return callback.Run(scoped_ptr<ServiceWorkerRequestResponseHeaders>()); |
+ |
+ scoped_ptr<ServiceWorkerRequestResponseHeaders> headers( |
+ new ServiceWorkerRequestResponseHeaders()); |
+ |
+ if (!headers->ParseFromArray(buffer->data(), buffer->size())) |
+ return callback.Run(scoped_ptr<ServiceWorkerRequestResponseHeaders>()); |
+ |
+ callback.Run(headers.Pass()); |
+} |
+ |
void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback& callback, |
scoped_ptr<ScopedBackendPtr> backend_ptr, |
base::WeakPtr<ServiceWorkerCache> cache, |
int rv) { |
- if (rv != net::OK || !cache) { |
- callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
- return; |
- } |
+ if (rv != net::OK || !cache) |
+ return callback.Run(ServiceWorkerCache::ErrorTypeStorage); |
+ |
cache->set_backend(backend_ptr->Pass()); |
callback.Run(ServiceWorkerCache::ErrorTypeOK); |
} |
@@ -636,14 +761,12 @@ void ServiceWorkerCache::Put(ServiceWorkerFetchRequest* request, |
if (!response->blob_uuid.empty()) { |
if (!blob_storage_context_) { |
- callback.Run(ErrorTypeStorage); |
- return; |
+ return callback.Run(ErrorTypeStorage); |
michaeln
2014/08/27 23:45:20
why?
jkarlin
2014/08/28 15:16:10
Done.
|
} |
blob_data_handle = |
blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid); |
if (!blob_data_handle) { |
- callback.Run(ErrorTypeStorage); |
- return; |
+ return callback.Run(ErrorTypeStorage); |
} |
} |
@@ -701,6 +824,34 @@ void ServiceWorkerCache::Delete(ServiceWorkerFetchRequest* request, |
open_entry_callback.Run(rv); |
} |
+void ServiceWorkerCache::Keys(const RequestsCallback& callback) { |
+ DCHECK(backend_); |
+ |
+ scoped_ptr<void*> iter(new void*(NULL)); |
+ scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
+ |
+ void** iter_ptr = iter.get(); |
+ disk_cache::Entry** entry_ptr = entry.get(); |
+ |
+ // Load up all of the entries into a vector and then read the request data |
michaeln
2014/08/27 23:45:20
It might help to expand on this comment to better
jkarlin
2014/08/28 15:16:10
Done.
|
+ // from them. This has to be done in two steps because enumeration breaks if |
+ // entries are altered (such as reading header data) while enumerating. |
michaeln
2014/08/27 23:45:20
how does reading header data alter it?
jkarlin
2014/08/28 15:16:10
It changes the "last_used" field which seems buggy
|
+ ScopedEntriesPtr entries(new Entries()); |
+ |
+ net::CompletionCallback open_entry_callback = |
+ base::Bind(KeysDidOpenNextEntry, |
+ callback, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ base::Passed(iter.Pass()), |
+ base::Passed(entry.Pass()), |
+ base::Passed(entries.Pass())); |
+ |
+ int rv = backend_->OpenNextEntry(iter_ptr, entry_ptr, open_entry_callback); |
+ |
+ if (rv != net::ERR_IO_PENDING) |
+ open_entry_callback.Run(rv); |
+} |
+ |
bool ServiceWorkerCache::HasCreatedBackend() const { |
return backend_; |
} |