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 d5028f00854f1f2d1241105442ee5f1ec94bb289..12e90569db54997d09e2327d3ec424ffdd48cf21 100644 |
--- a/content/browser/service_worker/service_worker_cache.cc |
+++ b/content/browser/service_worker/service_worker_cache.cc |
@@ -7,11 +7,149 @@ |
#include <string> |
#include "base/files/file_path.h" |
+#include "base/guid.h" |
+#include "base/message_loop/message_loop_proxy.h" |
+#include "content/browser/service_worker/service_worker_cache.pb.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "net/base/io_buffer.h" |
+#include "net/base/net_errors.h" |
+#include "net/disk_cache/disk_cache.h" |
#include "net/url_request/url_request_context.h" |
+#include "webkit/browser/blob/blob_data_handle.h" |
#include "webkit/browser/blob/blob_storage_context.h" |
+#include "webkit/browser/blob/blob_url_request_job_factory.h" |
namespace content { |
+namespace { |
+// The maximum size of an individual cache. Ultimately cache size is controlled |
+// per-origin. |
+const int kMaxCacheBytes = 512 * 1024 * 1024; |
michaeln
2014/08/21 01:46:15
there's a bug open about somebody trying to downlo
jkarlin
2014/08/21 18:31:21
We should talk to jsbell about what the appropriat
|
+ |
+// Buffer size for cache and blob reading/writing. |
+const int kBufferSize = 1024 * 512; |
+} |
+ |
+struct ServiceWorkerCache::ResponseReadContext { |
+ ResponseReadContext(scoped_refptr<net::IOBufferWithSize> buff, |
+ scoped_refptr<webkit_blob::BlobData> blob) |
+ : buffer(buff), blob_data(blob), total_bytes_read(0) {} |
+ |
+ scoped_refptr<net::IOBufferWithSize> buffer; |
+ scoped_refptr<webkit_blob::BlobData> blob_data; |
+ int total_bytes_read; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ResponseReadContext); |
+}; |
+ |
+// Streams data from a blob and writes it to a given disk_cache::Entry. |
+class ServiceWorkerCache::BlobReader : public net::URLRequest::Delegate { |
+ public: |
+ BlobReader(disk_cache::ScopedEntryPtr entry) |
+ : cache_entry_offset_(0), |
+ buffer_(new net::IOBufferWithSize(kBufferSize)), |
+ weak_ptr_factory_(this) { |
+ DCHECK(entry); |
+ entry_ = entry.Pass(); |
+ } |
+ |
+ void StreamBlobToCache( |
+ net::URLRequestContext* request_context, |
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle, |
+ const EntryBoolCallback& callback) { |
+ callback_ = callback; |
+ blob_request_ = webkit_blob::BlobProtocolHandler::CreateBlobRequest( |
+ blob_data_handle.Pass(), request_context, this); |
+ blob_request_->Start(); |
+ } |
+ |
+ // net::URLRequest::Delegate overrides for reading blobs. |
+ virtual void OnReceivedRedirect(net::URLRequest* request, |
+ const net::RedirectInfo& redirect_info, |
+ bool* defer_redirect) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ virtual void OnAuthRequired(net::URLRequest* request, |
+ net::AuthChallengeInfo* auth_info) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ virtual void OnCertificateRequested( |
+ net::URLRequest* request, |
+ net::SSLCertRequestInfo* cert_request_info) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ virtual void OnSSLCertificateError(net::URLRequest* request, |
+ const net::SSLInfo& ssl_info, |
+ bool fatal) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ virtual void OnBeforeNetworkStart(net::URLRequest* request, |
+ bool* defer) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ |
+ virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { |
+ if (!request->status().is_success()) { |
+ callback_.Run(entry_.Pass(), false); |
+ return; |
+ } |
+ ReadFromBlob(); |
+ } |
+ |
+ virtual void ReadFromBlob() { |
+ int bytes_read = 0; |
+ bool done = |
+ blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read); |
+ if (done) |
+ OnReadCompleted(blob_request_.get(), bytes_read); |
+ } |
+ |
+ virtual void OnReadCompleted(net::URLRequest* request, |
+ int bytes_read) OVERRIDE { |
+ if (!request->status().is_success()) { |
+ callback_.Run(entry_.Pass(), false); |
+ return; |
+ } |
+ |
+ if (bytes_read == 0) { |
+ callback_.Run(entry_.Pass(), true); |
+ return; |
+ } |
+ |
+ net::CompletionCallback cache_write_callback = |
+ base::Bind(&BlobReader::DidWriteDataToEntry, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ bytes_read); |
+ |
+ int rv = entry_->WriteData(ServiceWorkerCache::INDEX_RESPONSE_BODY, |
+ cache_entry_offset_, |
+ buffer_, |
+ bytes_read, |
+ cache_write_callback, |
+ true /* truncate */); |
+ if (rv != net::ERR_IO_PENDING) |
+ cache_write_callback.Run(rv); |
+ } |
+ |
+ void DidWriteDataToEntry(int expected_bytes, int rv) { |
+ if (rv != expected_bytes) { |
michaeln
2014/08/21 01:46:15
in this part of the urlrequest contract or just ho
jkarlin
2014/08/21 18:31:20
This is how everybody uses entry->WriteData. Eith
|
+ callback_.Run(entry_.Pass(), false); |
+ return; |
+ } |
+ |
+ cache_entry_offset_ += rv; |
+ ReadFromBlob(); |
+ } |
+ |
+ private: |
+ int cache_entry_offset_; |
+ disk_cache::ScopedEntryPtr entry_; |
+ scoped_ptr<net::URLRequest> blob_request_; |
+ EntryBoolCallback callback_; |
+ scoped_refptr<net::IOBufferWithSize> buffer_; |
+ base::WeakPtrFactory<ServiceWorkerCache::BlobReader> weak_ptr_factory_; |
+}; |
+ |
// static |
scoped_ptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache( |
const std::string& name, |
@@ -31,15 +169,146 @@ scoped_ptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache( |
new ServiceWorkerCache(path, name, request_context, blob_context)); |
} |
-void ServiceWorkerCache::CreateBackend( |
- const base::Callback<void(bool)>& callback) { |
- callback.Run(true); |
+ServiceWorkerCache::~ServiceWorkerCache() { |
} |
base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() { |
return weak_ptr_factory_.GetWeakPtr(); |
} |
+void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) { |
+ DCHECK(!backend_); |
+ |
+ net::CacheType cache_type = |
+ path_.empty() ? net::MEMORY_CACHE : net::DISK_CACHE; |
michaeln
2014/08/21 01:46:15
I think you want to use net::APP_CACHE here instea
jkarlin
2014/08/21 18:31:20
Thanks. Done.
|
+ |
+ scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr()); |
+ |
+ // Temporary pointer so that backend_ptr can be Pass()'d in Bind below. |
+ ScopedBackendPtr* backend = backend_ptr.get(); |
+ |
+ net::CompletionCallback create_cache_callback = |
+ base::Bind(&ServiceWorkerCache::CreateBackendDidCreate, |
michaeln
2014/08/21 01:46:15
nit: it might be more readable to invoke base::Bin
jkarlin
2014/08/21 18:31:21
Having create_cache_callback let's me both pass it
|
+ weak_ptr_factory_.GetWeakPtr(), |
+ callback, |
+ base::Passed(backend_ptr.Pass())); |
+ |
+ // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore |
+ // has for disk caches. |
+ // TODO(jkarlin): Switch to SimpleCache after debugging why the |
+ // QuickStressBody unittest fails with it. |
+ int rv = disk_cache::CreateCacheBackend( |
+ cache_type, |
+ net::CACHE_BACKEND_BLOCKFILE, |
+ path_, |
+ kMaxCacheBytes, |
+ false, /* force */ |
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(), |
+ NULL, |
+ backend, |
+ create_cache_callback); |
+ if (rv != net::ERR_IO_PENDING) |
+ create_cache_callback.Run(rv); |
+} |
+ |
+void ServiceWorkerCache::CreateBackendDidCreate( |
+ const ErrorCallback& callback, |
+ scoped_ptr<ScopedBackendPtr> backend_ptr, |
+ int rv) { |
+ if (rv != net::OK) { |
+ callback.Run(ErrorTypeStorage); |
+ return; |
+ } |
+ backend_ = backend_ptr->Pass(); |
+ callback.Run(ErrorTypeOK); |
+} |
+ |
+void ServiceWorkerCache::Put(ServiceWorkerFetchRequest* request, |
michaeln
2014/08/21 01:46:15
wassup with ownership of |request| and |response|?
jkarlin
2014/08/21 18:31:20
Owned by the caller. The callback is now guarante
|
+ ServiceWorkerResponse* response, |
+ const ErrorCallback& callback) { |
+ DCHECK(backend_); |
+ |
+ scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
+ |
+ disk_cache::Entry** entry_ptr = entry.get(); |
+ |
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle; |
+ |
+ if (!response->blob_uuid.empty()) { |
+ if (!blob_storage_context_) { |
+ callback.Run(ErrorTypeStorage); |
+ return; |
+ } |
+ blob_data_handle = |
+ blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid); |
+ if (!blob_data_handle) { |
+ callback.Run(ErrorTypeStorage); |
+ return; |
+ } |
+ } |
+ |
+ net::CompletionCallback create_entry_callback = |
+ base::Bind(&ServiceWorkerCache::PutDidCreateEntry, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ request, |
+ response, |
+ callback, |
+ base::Passed(entry.Pass()), |
+ base::Passed(blob_data_handle.Pass())); |
+ |
+ int rv = backend_->CreateEntry( |
+ request->url.spec(), entry_ptr, create_entry_callback); |
+ |
+ if (rv != net::ERR_IO_PENDING) |
+ create_entry_callback.Run(rv); |
+} |
+ |
+void ServiceWorkerCache::Match(ServiceWorkerFetchRequest* request, |
+ const ResponseCallback& callback) { |
+ DCHECK(backend_); |
+ |
+ scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
+ |
+ disk_cache::Entry** entry_ptr = entry.get(); |
+ |
+ net::CompletionCallback open_entry_callback = |
+ base::Bind(&ServiceWorkerCache::MatchDidOpenEntry, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ request, |
+ callback, |
+ base::Passed(entry.Pass())); |
+ |
+ int rv = |
+ backend_->OpenEntry(request->url.spec(), entry_ptr, open_entry_callback); |
+ if (rv != net::ERR_IO_PENDING) |
+ open_entry_callback.Run(rv); |
+} |
+ |
+void ServiceWorkerCache::Delete(ServiceWorkerFetchRequest* request, |
+ const ErrorCallback& callback) { |
+ DCHECK(backend_); |
+ |
+ scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
+ |
+ disk_cache::Entry** entry_ptr = entry.get(); |
+ |
+ net::CompletionCallback open_entry_callback = |
+ base::Bind(&ServiceWorkerCache::DeleteDidOpenEntry, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ request, |
+ callback, |
+ base::Passed(entry.Pass())); |
+ |
+ int rv = |
+ backend_->OpenEntry(request->url.spec(), entry_ptr, open_entry_callback); |
+ if (rv != net::ERR_IO_PENDING) |
+ open_entry_callback.Run(rv); |
+} |
+ |
+bool ServiceWorkerCache::HasCreatedBackend() const { |
+ return backend_; |
+} |
+ |
ServiceWorkerCache::ServiceWorkerCache( |
const base::FilePath& path, |
const std::string& name, |
@@ -53,7 +322,334 @@ ServiceWorkerCache::ServiceWorkerCache( |
weak_ptr_factory_(this) { |
} |
-ServiceWorkerCache::~ServiceWorkerCache() { |
+void ServiceWorkerCache::MatchDidOpenEntry( |
+ ServiceWorkerFetchRequest* request, |
michaeln
2014/08/21 01:46:15
wassup with ownership of 'request'?
jkarlin
2014/08/21 18:31:21
Owned by the caller. The callback is now guarante
|
+ const ResponseCallback& callback, |
+ scoped_ptr<disk_cache::Entry*> entryptr, |
+ int rv) { |
+ if (rv != net::OK) { |
+ callback.Run(ErrorTypeNotFound, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ return; |
+ } |
+ |
+ 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(&ServiceWorkerCache::MatchDidReadHeaderData, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ request, |
+ callback, |
+ base::Passed(entry.Pass()), |
+ buffer); |
+ |
+ int read_rv = tmp_entry_ptr->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 ServiceWorkerCache::MatchDidReadHeaderData( |
+ ServiceWorkerFetchRequest* request, |
+ const ResponseCallback& callback, |
+ disk_cache::ScopedEntryPtr entry, |
+ const scoped_refptr<net::IOBufferWithSize>& buffer, |
+ int rv) { |
+ if (rv != buffer->size()) { |
+ callback.Run(ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ |
+ return; |
+ } |
+ |
+ ServiceWorkerRequestResponseHeaders headers; |
+ |
+ if (!headers.ParseFromArray(buffer->data(), buffer->size())) { |
+ callback.Run(ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ |
+ return; |
+ } |
+ |
+ scoped_ptr<ServiceWorkerResponse> response( |
+ new ServiceWorkerResponse(request->url, |
+ headers.status_code(), |
+ headers.status_text(), |
+ std::map<std::string, std::string>(), |
+ "")); |
+ |
+ for (int i = 0; i < headers.response_headers_size(); ++i) { |
+ const ServiceWorkerRequestResponseHeaders::HeaderMap header = |
+ 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(ErrorTypeOK, |
+ response.Pass(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ return; |
+ } |
+ |
+ // Stream the response body into a blob. |
+ if (!blob_storage_context_) { |
+ callback.Run(ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ |
+ return; |
+ } |
+ |
+ response->blob_uuid = base::GenerateGUID(); |
+ |
+ scoped_refptr<webkit_blob::BlobData> blob_data = |
+ new webkit_blob::BlobData(response->blob_uuid); |
+ scoped_refptr<net::IOBufferWithSize> response_body_buffer( |
+ new net::IOBufferWithSize(kBufferSize)); |
+ |
+ scoped_ptr<ResponseReadContext> read_context( |
+ new ResponseReadContext(response_body_buffer, blob_data)); |
+ |
+ // Copy the entry pointer before passing it in base::Bind. |
+ disk_cache::Entry* tmp_entry_ptr = entry.get(); |
+ |
+ net::CompletionCallback read_callback = |
+ base::Bind(&ServiceWorkerCache::MatchDidReadResponseBodyData, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ request, |
+ callback, |
+ base::Passed(entry.Pass()), |
+ base::Passed(response.Pass()), |
+ base::Passed(read_context.Pass())); |
+ |
+ int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, |
+ 0, |
+ response_body_buffer.get(), |
+ response_body_buffer->size(), |
+ read_callback); |
+ |
+ if (read_rv != net::ERR_IO_PENDING) |
+ read_callback.Run(read_rv); |
+} |
+ |
+void ServiceWorkerCache::MatchDidReadResponseBodyData( |
+ ServiceWorkerFetchRequest* request, |
+ const ResponseCallback& callback, |
+ disk_cache::ScopedEntryPtr entry, |
+ scoped_ptr<ServiceWorkerResponse> response, |
+ scoped_ptr<ResponseReadContext> response_context, |
+ int rv) { |
+ if (rv < 0) { |
+ callback.Run(ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ return; |
+ } |
+ |
+ if (rv == 0) { |
+ MatchDoneWithBody( |
+ request, callback, response.Pass(), response_context.Pass()); |
+ return; |
+ } |
+ |
+ // TODO(jkarlin): This copying of the the entire cache response into memory is |
michaeln
2014/08/21 01:46:15
It's really hard to say this looks good. Every cal
jkarlin
2014/08/21 18:31:21
Yes, this optimization needs to happen. But we ne
|
+ // awful. Create a new interface around SimpleCache that provides access the |
+ // data directly from the file. See bug http://crbug.com/403493. |
+ response_context->blob_data->AppendData(response_context->buffer->data(), rv); |
+ response_context->total_bytes_read += rv; |
+ int total_bytes_read = response_context->total_bytes_read; |
+ |
+ // Grab some pointers before passing them in bind. |
+ net::IOBufferWithSize* buffer = response_context->buffer; |
+ disk_cache::Entry* tmp_entry_ptr = entry.get(); |
+ |
+ net::CompletionCallback read_callback = |
+ base::Bind(&ServiceWorkerCache::MatchDidReadResponseBodyData, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ request, |
+ callback, |
+ base::Passed(entry.Pass()), |
+ base::Passed(response.Pass()), |
+ base::Passed(response_context.Pass())); |
+ |
+ int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, |
+ total_bytes_read, |
+ buffer, |
+ buffer->size(), |
+ read_callback); |
+ |
+ if (read_rv != net::ERR_IO_PENDING) |
+ read_callback.Run(read_rv); |
+} |
+ |
+void ServiceWorkerCache::MatchDoneWithBody( |
+ ServiceWorkerFetchRequest* request, |
+ const ResponseCallback& callback, |
+ scoped_ptr<ServiceWorkerResponse> response, |
+ scoped_ptr<ResponseReadContext> response_context) { |
+ if (!blob_storage_context_) { |
+ callback.Run(ErrorTypeStorage, |
+ scoped_ptr<ServiceWorkerResponse>(), |
+ scoped_ptr<webkit_blob::BlobDataHandle>()); |
+ return; |
+ } |
+ |
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle( |
+ blob_storage_context_->AddFinishedBlob( |
+ response_context->blob_data.get())); |
+ |
+ callback.Run(ErrorTypeOK, response.Pass(), blob_data_handle.Pass()); |
+} |
+ |
+void ServiceWorkerCache::PutDidCreateEntry( |
+ ServiceWorkerFetchRequest* request, |
+ ServiceWorkerResponse* response, |
+ const ErrorCallback& callback, |
+ scoped_ptr<disk_cache::Entry*> entryptr, |
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle, |
+ int rv) { |
+ if (rv != net::OK) { |
+ callback.Run(ErrorTypeExists); |
+ return; |
+ } |
+ |
+ DCHECK(entryptr); |
+ disk_cache::ScopedEntryPtr entry(*entryptr); |
+ |
+ ServiceWorkerRequestResponseHeaders headers; |
+ headers.set_method(request->method); |
+ |
+ headers.set_status_code(response->status_code); |
+ headers.set_status_text(response->status_text); |
+ for (std::map<std::string, std::string>::const_iterator it = |
+ request->headers.begin(); |
+ it != request->headers.end(); |
+ ++it) { |
+ ServiceWorkerRequestResponseHeaders::HeaderMap* header_map = |
+ headers.add_request_headers(); |
+ header_map->set_name(it->first); |
+ header_map->set_value(it->second); |
+ } |
+ |
+ for (std::map<std::string, std::string>::const_iterator it = |
+ response->headers.begin(); |
+ it != response->headers.end(); |
+ ++it) { |
+ ServiceWorkerRequestResponseHeaders::HeaderMap* header_map = |
+ headers.add_response_headers(); |
+ header_map->set_name(it->first); |
+ header_map->set_value(it->second); |
+ } |
+ |
+ scoped_ptr<std::string> serialized(new std::string()); |
+ if (!headers.SerializeToString(serialized.get())) { |
+ callback.Run(ErrorTypeStorage); |
+ return; |
+ } |
+ |
+ scoped_refptr<net::StringIOBuffer> buffer( |
+ new net::StringIOBuffer(serialized.Pass())); |
+ |
+ // Get a temporary copy of the entry pointer before passing it in base::Bind. |
+ disk_cache::Entry* tmp_entry_ptr = entry.get(); |
+ |
+ net::CompletionCallback write_headers_callback = |
+ base::Bind(&ServiceWorkerCache::PutDidWriteHeaders, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ response, |
+ callback, |
+ base::Passed(entry.Pass()), |
+ base::Passed(blob_data_handle.Pass()), |
+ buffer->size()); |
+ |
+ rv = tmp_entry_ptr->WriteData(INDEX_HEADERS, |
+ 0 /* offset */, |
+ buffer, |
+ buffer->size(), |
+ write_headers_callback, |
+ true /* truncate */); |
+ |
+ if (rv != net::ERR_IO_PENDING) |
+ write_headers_callback.Run(rv); |
+} |
+ |
+void ServiceWorkerCache::PutDidWriteHeaders( |
+ ServiceWorkerResponse* response, |
+ const ErrorCallback& callback, |
+ disk_cache::ScopedEntryPtr entry, |
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle, |
+ int expected_bytes, |
+ int rv) { |
+ if (rv != expected_bytes) { |
+ entry->Doom(); |
+ callback.Run(ErrorTypeStorage); |
+ return; |
+ } |
+ |
+ // 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(ErrorTypeOK); |
+ return; |
+ } |
+ |
+ DCHECK(blob_data_handle); |
+ |
+ scoped_ptr<BlobReader> reader(new BlobReader(entry.Pass())); |
+ BlobReader* reader_ptr = reader.get(); |
+ |
+ reader_ptr->StreamBlobToCache( |
+ request_context_, |
+ blob_data_handle.Pass(), |
+ base::Bind(&ServiceWorkerCache::PutDidWriteBlobToCache, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ callback, |
+ base::Passed(reader.Pass()))); |
+} |
+ |
+void ServiceWorkerCache::PutDidWriteBlobToCache( |
+ const ErrorCallback& callback, |
+ scoped_ptr<BlobReader> blob_reader, |
+ disk_cache::ScopedEntryPtr entry, |
+ bool success) { |
+ if (!success) { |
+ entry->Doom(); |
+ callback.Run(ErrorTypeStorage); |
+ return; |
+ } |
+ |
+ callback.Run(ErrorTypeOK); |
+} |
+ |
+void ServiceWorkerCache::DeleteDidOpenEntry( |
+ ServiceWorkerFetchRequest* request, |
+ const ErrorCallback& callback, |
+ scoped_ptr<disk_cache::Entry*> entryptr, |
+ int rv) { |
+ if (rv != net::OK) { |
+ callback.Run(ErrorTypeNotFound); |
+ return; |
+ } |
+ |
+ DCHECK(entryptr); |
+ disk_cache::ScopedEntryPtr entry(*entryptr); |
+ |
+ entry->Doom(); |
+ callback.Run(ErrorTypeOK); |
} |
} // namespace content |