// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_BLOB_TO_DISK_CACHE_H_
#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_BLOB_TO_DISK_CACHE_H_

#include <memory>

#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "net/disk_cache/disk_cache.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter_observer.h"

namespace net {
class IOBufferWithSize;
class URLRequestContextGetter;
}

namespace storage {
class BlobDataHandle;
}

namespace content {

// Streams data from a blob and writes it to a given disk_cache::Entry.
class CONTENT_EXPORT CacheStorageBlobToDiskCache
    : public net::URLRequest::Delegate,
      public net::URLRequestContextGetterObserver {
 public:
  using EntryAndBoolCallback =
      base::Callback<void(disk_cache::ScopedEntryPtr, bool)>;

  // The buffer size used for reading from blobs and writing to disk cache.
  static const int kBufferSize;

  CacheStorageBlobToDiskCache();
  ~CacheStorageBlobToDiskCache() override;

  // Writes the body of |blob_data_handle| to |entry| with index
  // |disk_cache_body_index|. |entry| is passed to the callback once complete.
  // Only call this once per instantiation of CacheStorageBlobToDiskCache.
  void StreamBlobToCache(
      disk_cache::ScopedEntryPtr entry,
      int disk_cache_body_index,
      net::URLRequestContextGetter* request_context_getter,
      std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
      const EntryAndBoolCallback& callback);

  // net::URLRequest::Delegate overrides for reading blobs.
  void OnResponseStarted(net::URLRequest* request) override;
  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
  void OnReceivedRedirect(net::URLRequest* request,
                          const net::RedirectInfo& redirect_info,
                          bool* defer_redirect) override;
  void OnAuthRequired(net::URLRequest* request,
                      net::AuthChallengeInfo* auth_info) override;
  void OnCertificateRequested(
      net::URLRequest* request,
      net::SSLCertRequestInfo* cert_request_info) override;
  void OnSSLCertificateError(net::URLRequest* request,
                             const net::SSLInfo& ssl_info,
                             bool fatal) override;
  void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override;

  // URLRequestContextGetterObserver override for canceling requests just
  // before the URLRequestContext is destroyed.
  void OnContextShuttingDown() override;

 protected:
  // Virtual for testing.
  virtual void ReadFromBlob();

 private:
  void DidWriteDataToEntry(int expected_bytes, int rv);
  void RunCallbackAndRemoveObserver(bool success);

  int cache_entry_offset_;
  disk_cache::ScopedEntryPtr entry_;

  // Owned by CacheStorageCache which owns this.
  net::URLRequestContextGetter* request_context_getter_;

  int disk_cache_body_index_;
  std::unique_ptr<net::URLRequest> blob_request_;
  EntryAndBoolCallback callback_;
  scoped_refptr<net::IOBufferWithSize> buffer_;

  base::WeakPtrFactory<CacheStorageBlobToDiskCache> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(CacheStorageBlobToDiskCache);
};

}  // namespace content

#endif  // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_BLOB_TO_DISK_CACHE_H_
