| Index: content/browser/cache_storage/cache_storage_cache.cc
 | 
| diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
 | 
| index ae64bad809bae41786537f3a958d1caae8002e3e..a6e570e684c98a14466785e4a686731b6d0b271d 100644
 | 
| --- a/content/browser/cache_storage/cache_storage_cache.cc
 | 
| +++ b/content/browser/cache_storage/cache_storage_cache.cc
 | 
| @@ -32,8 +32,24 @@ namespace content {
 | 
|  
 | 
|  namespace {
 | 
|  
 | 
| -typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
 | 
| -    EntryBoolCallback;
 | 
| +// This class ensures that the cache and the entry have a lifetime as long as
 | 
| +// the blob that is created to contain them.
 | 
| +class CacheStorageCacheDataHandle
 | 
| +    : public storage::BlobDataBuilder::DataHandle {
 | 
| + public:
 | 
| +  CacheStorageCacheDataHandle(const scoped_refptr<CacheStorageCache>& cache,
 | 
| +                              disk_cache::ScopedEntryPtr entry)
 | 
| +      : cache_(cache), entry_(entry.Pass()) {}
 | 
| +
 | 
| + private:
 | 
| +  ~CacheStorageCacheDataHandle() override {}
 | 
| +
 | 
| +  scoped_refptr<CacheStorageCache> cache_;
 | 
| +  disk_cache::ScopedEntryPtr entry_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(CacheStorageCacheDataHandle);
 | 
| +};
 | 
| +
 | 
|  typedef base::Callback<void(scoped_ptr<CacheMetadata>)> MetadataCallback;
 | 
|  
 | 
|  enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
 | 
| @@ -42,9 +58,6 @@ enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
 | 
|  // per-origin.
 | 
|  const int kMaxCacheBytes = 512 * 1024 * 1024;
 | 
|  
 | 
| -// Buffer size for cache and blob reading/writing.
 | 
| -const int kBufferSize = 1024 * 512;
 | 
| -
 | 
|  void NotReachedCompletionCallback(int rv) {
 | 
|    NOTREACHED();
 | 
|  }
 | 
| @@ -198,39 +211,6 @@ struct CacheStorageCache::KeysContext {
 | 
|    DISALLOW_COPY_AND_ASSIGN(KeysContext);
 | 
|  };
 | 
|  
 | 
| -struct CacheStorageCache::MatchContext {
 | 
| -  MatchContext(scoped_ptr<ServiceWorkerFetchRequest> request,
 | 
| -               const CacheStorageCache::ResponseCallback& callback,
 | 
| -               base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
 | 
| -      : request(request.Pass()),
 | 
| -        original_callback(callback),
 | 
| -        blob_storage_context(blob_storage_context),
 | 
| -        entry(nullptr),
 | 
| -        total_bytes_read(0) {}
 | 
| -
 | 
| -  ~MatchContext() {
 | 
| -    if (entry)
 | 
| -      entry->Close();
 | 
| -  }
 | 
| -
 | 
| -  // Input
 | 
| -  scoped_ptr<ServiceWorkerFetchRequest> request;
 | 
| -  CacheStorageCache::ResponseCallback original_callback;
 | 
| -  base::WeakPtr<storage::BlobStorageContext> blob_storage_context;
 | 
| -  disk_cache::Entry* entry;
 | 
| -
 | 
| -  // Output
 | 
| -  scoped_ptr<ServiceWorkerResponse> response;
 | 
| -  scoped_ptr<storage::BlobDataBuilder> blob_data;
 | 
| -
 | 
| -  // For reading the cache entry data into a blob.
 | 
| -  scoped_refptr<net::IOBufferWithSize> response_body_buffer;
 | 
| -  size_t total_bytes_read;
 | 
| -
 | 
| - private:
 | 
| -  DISALLOW_COPY_AND_ASSIGN(MatchContext);
 | 
| -};
 | 
| -
 | 
|  // The state needed to pass between CacheStorageCache::Put callbacks.
 | 
|  struct CacheStorageCache::PutContext {
 | 
|    PutContext(
 | 
| @@ -247,12 +227,7 @@ struct CacheStorageCache::PutContext {
 | 
|          blob_data_handle(blob_data_handle.Pass()),
 | 
|          callback(callback),
 | 
|          request_context_getter(request_context_getter),
 | 
| -        quota_manager_proxy(quota_manager_proxy),
 | 
| -        cache_entry(NULL) {}
 | 
| -  ~PutContext() {
 | 
| -    if (cache_entry)
 | 
| -      cache_entry->Close();
 | 
| -  }
 | 
| +        quota_manager_proxy(quota_manager_proxy) {}
 | 
|  
 | 
|    // Input parameters to the Put function.
 | 
|    GURL origin;
 | 
| @@ -262,10 +237,7 @@ struct CacheStorageCache::PutContext {
 | 
|    CacheStorageCache::ErrorCallback callback;
 | 
|    scoped_refptr<net::URLRequestContextGetter> request_context_getter;
 | 
|    scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
 | 
| -
 | 
| -  // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
 | 
| -  // CreateEntry.
 | 
| -  disk_cache::Entry* cache_entry;
 | 
| +  disk_cache::ScopedEntryPtr cache_entry;
 | 
|  
 | 
|   private:
 | 
|    DISALLOW_COPY_AND_ASSIGN(PutContext);
 | 
| @@ -478,15 +450,14 @@ void CacheStorageCache::MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  scoped_ptr<MatchContext> match_context(
 | 
| -      new MatchContext(request.Pass(), callback, blob_storage_context_));
 | 
| -
 | 
| -  disk_cache::Entry** entry_ptr = &match_context->entry;
 | 
| -  ServiceWorkerFetchRequest* request_ptr = match_context->request.get();
 | 
| +  scoped_ptr<disk_cache::Entry*> scoped_entry_ptr(new disk_cache::Entry*());
 | 
| +  disk_cache::Entry** entry_ptr = scoped_entry_ptr.get();
 | 
| +  ServiceWorkerFetchRequest* request_ptr = request.get();
 | 
|  
 | 
| -  net::CompletionCallback open_entry_callback = base::Bind(
 | 
| -      &CacheStorageCache::MatchDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
 | 
| -      base::Passed(match_context.Pass()));
 | 
| +  net::CompletionCallback open_entry_callback =
 | 
| +      base::Bind(&CacheStorageCache::MatchDidOpenEntry,
 | 
| +                 weak_ptr_factory_.GetWeakPtr(), base::Passed(request.Pass()),
 | 
| +                 callback, base::Passed(scoped_entry_ptr.Pass()));
 | 
|  
 | 
|    int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr,
 | 
|                                 open_entry_callback);
 | 
| @@ -495,44 +466,43 @@ void CacheStorageCache::MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
 | 
|  }
 | 
|  
 | 
|  void CacheStorageCache::MatchDidOpenEntry(
 | 
| -    scoped_ptr<MatchContext> match_context,
 | 
| +    scoped_ptr<ServiceWorkerFetchRequest> request,
 | 
| +    const ResponseCallback& callback,
 | 
| +    scoped_ptr<disk_cache::Entry*> entry_ptr,
 | 
|      int rv) {
 | 
|    if (rv != net::OK) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
 | 
| -                                         scoped_ptr<ServiceWorkerResponse>(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| +    callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
 | 
| +                 scoped_ptr<ServiceWorkerResponse>(),
 | 
| +                 scoped_ptr<storage::BlobDataHandle>());
 | 
|      return;
 | 
|    }
 | 
| -
 | 
| -  // Copy the entry pointer before passing it in base::Bind.
 | 
| -  disk_cache::Entry* tmp_entry_ptr = match_context->entry;
 | 
| -  DCHECK(tmp_entry_ptr);
 | 
| +  disk_cache::ScopedEntryPtr entry(*entry_ptr);
 | 
|  
 | 
|    MetadataCallback headers_callback = base::Bind(
 | 
|        &CacheStorageCache::MatchDidReadMetadata, weak_ptr_factory_.GetWeakPtr(),
 | 
| -      base::Passed(match_context.Pass()));
 | 
| +      base::Passed(request.Pass()), callback, base::Passed(entry.Pass()));
 | 
|  
 | 
| -  ReadMetadata(tmp_entry_ptr, headers_callback);
 | 
| +  ReadMetadata(*entry_ptr, headers_callback);
 | 
|  }
 | 
|  
 | 
|  void CacheStorageCache::MatchDidReadMetadata(
 | 
| -    scoped_ptr<MatchContext> match_context,
 | 
| +    scoped_ptr<ServiceWorkerFetchRequest> request,
 | 
| +    const ResponseCallback& callback,
 | 
| +    disk_cache::ScopedEntryPtr entry,
 | 
|      scoped_ptr<CacheMetadata> metadata) {
 | 
|    if (!metadata) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
 | 
| -                                         scoped_ptr<ServiceWorkerResponse>(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| +    callback.Run(CACHE_STORAGE_ERROR_STORAGE,
 | 
| +                 scoped_ptr<ServiceWorkerResponse>(),
 | 
| +                 scoped_ptr<storage::BlobDataHandle>());
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  match_context->response.reset(new ServiceWorkerResponse(
 | 
| -      match_context->request->url, metadata->response().status_code(),
 | 
| +  scoped_ptr<ServiceWorkerResponse> response(new ServiceWorkerResponse(
 | 
| +      request->url, metadata->response().status_code(),
 | 
|        metadata->response().status_text(),
 | 
|        ProtoResponseTypeToWebResponseType(metadata->response().response_type()),
 | 
|        ServiceWorkerHeaderMap(), "", 0, GURL()));
 | 
|  
 | 
| -  ServiceWorkerResponse* response = match_context->response.get();
 | 
| -
 | 
|    if (metadata->response().has_url())
 | 
|      response->url = GURL(metadata->response().url());
 | 
|  
 | 
| @@ -551,107 +521,39 @@ void CacheStorageCache::MatchDidReadMetadata(
 | 
|      cached_request_headers[header.name()] = header.value();
 | 
|    }
 | 
|  
 | 
| -  if (!VaryMatches(match_context->request->headers, cached_request_headers,
 | 
| +  if (!VaryMatches(request->headers, cached_request_headers,
 | 
|                     response->headers)) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
 | 
| -                                         scoped_ptr<ServiceWorkerResponse>(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| +    callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
 | 
| +                 scoped_ptr<ServiceWorkerResponse>(),
 | 
| +                 scoped_ptr<storage::BlobDataHandle>());
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  if (match_context->entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_OK,
 | 
| -                                         match_context->response.Pass(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| +  if (entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
 | 
| +    callback.Run(CACHE_STORAGE_OK, response.Pass(),
 | 
| +                 scoped_ptr<storage::BlobDataHandle>());
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  // Stream the response body into a blob.
 | 
| -  if (!match_context->blob_storage_context) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
 | 
| -                                         scoped_ptr<ServiceWorkerResponse>(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| +  if (!blob_storage_context_) {
 | 
| +    callback.Run(CACHE_STORAGE_ERROR_STORAGE,
 | 
| +                 scoped_ptr<ServiceWorkerResponse>(),
 | 
| +                 scoped_ptr<storage::BlobDataHandle>());
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| +  // Create a blob with the response body data.
 | 
| +  response->blob_size = entry->GetDataSize(INDEX_RESPONSE_BODY);
 | 
|    response->blob_uuid = base::GenerateGUID();
 | 
| +  storage::BlobDataBuilder blob_data(response->blob_uuid);
 | 
|  
 | 
| -  match_context->blob_data.reset(
 | 
| -      new storage::BlobDataBuilder(response->blob_uuid));
 | 
| -  match_context->response_body_buffer = new net::IOBufferWithSize(kBufferSize);
 | 
| -
 | 
| -  disk_cache::Entry* tmp_entry_ptr = match_context->entry;
 | 
| -  net::IOBufferWithSize* response_body_buffer =
 | 
| -      match_context->response_body_buffer.get();
 | 
| -
 | 
| -  net::CompletionCallback read_callback = base::Bind(
 | 
| -      &CacheStorageCache::MatchDidReadResponseBodyData,
 | 
| -      weak_ptr_factory_.GetWeakPtr(), base::Passed(match_context.Pass()));
 | 
| -
 | 
| -  int read_rv =
 | 
| -      tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY, 0, response_body_buffer,
 | 
| -                              response_body_buffer->size(), read_callback);
 | 
| -
 | 
| -  if (read_rv != net::ERR_IO_PENDING)
 | 
| -    read_callback.Run(read_rv);
 | 
| -}
 | 
| -
 | 
| -void CacheStorageCache::MatchDidReadResponseBodyData(
 | 
| -    scoped_ptr<MatchContext> match_context,
 | 
| -    int rv) {
 | 
| -  if (rv < 0) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
 | 
| -                                         scoped_ptr<ServiceWorkerResponse>(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  if (rv == 0) {
 | 
| -    match_context->response->blob_uuid = match_context->blob_data->uuid();
 | 
| -    match_context->response->blob_size = match_context->total_bytes_read;
 | 
| -    MatchDoneWithBody(match_context.Pass());
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // TODO(jkarlin): This copying of the the entire cache response into memory is
 | 
| -  // awful. Create a new interface around SimpleCache that provides access the
 | 
| -  // data directly from the file. See bug http://crbug.com/403493.
 | 
| -  match_context->blob_data->AppendData(
 | 
| -      match_context->response_body_buffer->data(), rv);
 | 
| -  match_context->total_bytes_read += rv;
 | 
| -  int total_bytes_read = match_context->total_bytes_read;
 | 
| -
 | 
| -  // Grab some pointers before passing match_context in bind.
 | 
| -  net::IOBufferWithSize* buffer = match_context->response_body_buffer.get();
 | 
| -  disk_cache::Entry* tmp_entry_ptr = match_context->entry;
 | 
| -
 | 
| -  net::CompletionCallback read_callback = base::Bind(
 | 
| -      &CacheStorageCache::MatchDidReadResponseBodyData,
 | 
| -      weak_ptr_factory_.GetWeakPtr(), base::Passed(match_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 CacheStorageCache::MatchDoneWithBody(
 | 
| -    scoped_ptr<MatchContext> match_context) {
 | 
| -  if (!match_context->blob_storage_context) {
 | 
| -    match_context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
 | 
| -                                         scoped_ptr<ServiceWorkerResponse>(),
 | 
| -                                         scoped_ptr<storage::BlobDataHandle>());
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| +  disk_cache::Entry* temp_entry = entry.get();
 | 
| +  blob_data.AppendDiskCacheEntry(
 | 
| +      new CacheStorageCacheDataHandle(this, entry.Pass()), temp_entry,
 | 
| +      INDEX_RESPONSE_BODY);
 | 
|    scoped_ptr<storage::BlobDataHandle> blob_data_handle(
 | 
| -      match_context->blob_storage_context->AddFinishedBlob(
 | 
| -          match_context->blob_data.get()));
 | 
| -
 | 
| -  match_context->original_callback.Run(CACHE_STORAGE_OK,
 | 
| -                                       match_context->response.Pass(),
 | 
| -                                       blob_data_handle.Pass());
 | 
| +      blob_storage_context_->AddFinishedBlob(&blob_data));
 | 
| +  callback.Run(CACHE_STORAGE_OK, response.Pass(), blob_data_handle.Pass());
 | 
|  }
 | 
|  
 | 
|  void CacheStorageCache::Put(const CacheStorageBatchOperation& operation,
 | 
| @@ -722,13 +624,14 @@ void CacheStorageCache::PutDidDelete(scoped_ptr<PutContext> put_context,
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  disk_cache::Entry** entry_ptr = &put_context->cache_entry;
 | 
| +  scoped_ptr<disk_cache::Entry*> scoped_entry_ptr(new disk_cache::Entry*());
 | 
| +  disk_cache::Entry** entry_ptr = scoped_entry_ptr.get();
 | 
|    ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
 | 
|    disk_cache::Backend* backend_ptr = backend_.get();
 | 
|  
 | 
|    net::CompletionCallback create_entry_callback = base::Bind(
 | 
|        &CacheStorageCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(),
 | 
| -      base::Passed(put_context.Pass()));
 | 
| +      base::Passed(scoped_entry_ptr.Pass()), base::Passed(put_context.Pass()));
 | 
|  
 | 
|    int create_rv = backend_ptr->CreateEntry(request_ptr->url.spec(), entry_ptr,
 | 
|                                             create_entry_callback);
 | 
| @@ -737,14 +640,15 @@ void CacheStorageCache::PutDidDelete(scoped_ptr<PutContext> put_context,
 | 
|      create_entry_callback.Run(create_rv);
 | 
|  }
 | 
|  
 | 
| -void CacheStorageCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
 | 
| -                                          int rv) {
 | 
| +void CacheStorageCache::PutDidCreateEntry(
 | 
| +    scoped_ptr<disk_cache::Entry*> entry_ptr,
 | 
| +    scoped_ptr<PutContext> put_context,
 | 
| +    int rv) {
 | 
|    if (rv != net::OK) {
 | 
|      put_context->callback.Run(CACHE_STORAGE_ERROR_EXISTS);
 | 
|      return;
 | 
|    }
 | 
| -
 | 
| -  DCHECK(put_context->cache_entry);
 | 
| +  put_context->cache_entry.reset(*entry_ptr);
 | 
|  
 | 
|    CacheMetadata metadata;
 | 
|    CacheRequest* request_metadata = metadata.mutable_request();
 | 
| @@ -785,15 +689,15 @@ void CacheStorageCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
 | 
|        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 = put_context->cache_entry;
 | 
| +  disk_cache::Entry* temp_entry_ptr = put_context->cache_entry.get();
 | 
|  
 | 
|    net::CompletionCallback write_headers_callback = base::Bind(
 | 
|        &CacheStorageCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(),
 | 
|        base::Passed(put_context.Pass()), buffer->size());
 | 
|  
 | 
| -  rv = tmp_entry_ptr->WriteData(INDEX_HEADERS, 0 /* offset */, buffer.get(),
 | 
| -                                buffer->size(), write_headers_callback,
 | 
| -                                true /* truncate */);
 | 
| +  rv = temp_entry_ptr->WriteData(INDEX_HEADERS, 0 /* offset */, buffer.get(),
 | 
| +                                 buffer->size(), write_headers_callback,
 | 
| +                                 true /* truncate */);
 | 
|  
 | 
|    if (rv != net::ERR_IO_PENDING)
 | 
|      write_headers_callback.Run(rv);
 | 
| @@ -825,7 +729,7 @@ void CacheStorageCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
 | 
|  
 | 
|    DCHECK(put_context->blob_data_handle);
 | 
|  
 | 
| -  disk_cache::ScopedEntryPtr entry(put_context->cache_entry);
 | 
| +  disk_cache::ScopedEntryPtr entry(put_context->cache_entry.Pass());
 | 
|    put_context->cache_entry = NULL;
 | 
|    scoped_ptr<CacheStorageBlobToDiskCache> reader(
 | 
|        new CacheStorageBlobToDiskCache());
 | 
| @@ -852,7 +756,7 @@ void CacheStorageCache::PutDidWriteBlobToCache(
 | 
|      disk_cache::ScopedEntryPtr entry,
 | 
|      bool success) {
 | 
|    DCHECK(entry);
 | 
| -  put_context->cache_entry = entry.release();
 | 
| +  put_context->cache_entry = entry.Pass();
 | 
|  
 | 
|    if (!success) {
 | 
|      put_context->cache_entry->Doom();
 | 
| 
 |