Chromium Code Reviews| 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 |