blob: 4614fd6dcf20051fb8523800c56d8ea8867e5798 [file] [log] [blame]
// 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 STORAGE_BROWSER_BLOB_BLOB_READER_H_
#define STORAGE_BROWSER_BLOB_BLOB_READER_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "net/base/completion_once_callback.h"
#include "storage/browser/storage_browser_export.h"
#include "storage/common/blob_storage/blob_storage_constants.h"
class GURL;
namespace base {
class FilePath;
class TaskRunner;
class Time;
}
namespace net {
class DrainableIOBuffer;
class IOBuffer;
class IOBufferWithSize;
}
namespace storage {
class BlobDataItem;
class BlobDataHandle;
class BlobDataSnapshot;
class FileStreamReader;
// The blob reader is used to read a blob. This can only be used in the browser
// process, and we need to be on the IO thread.
// * There can only be one read happening at a time per reader.
// * If a status of Status::NET_ERROR is returned, that means there was an
// error and the net_error() variable contains the error code.
// Use a BlobDataHandle to create an instance.
//
// For more information on how to read Blobs in your specific situation, see:
// https://chromium.googlesource.com/chromium/src/+/HEAD/storage/browser/blob/README.md#accessing-reading
class STORAGE_EXPORT BlobReader {
public:
class STORAGE_EXPORT FileStreamReaderProvider {
public:
virtual ~FileStreamReaderProvider();
virtual std::unique_ptr<FileStreamReader> CreateForLocalFile(
base::TaskRunner* task_runner,
const base::FilePath& file_path,
int64_t initial_offset,
const base::Time& expected_modification_time) = 0;
virtual std::unique_ptr<FileStreamReader> CreateFileStreamReader(
const GURL& filesystem_url,
int64_t offset,
int64_t max_bytes_to_read,
const base::Time& expected_modification_time) = 0;
};
enum class Status { NET_ERROR, IO_PENDING, DONE };
using StatusCallback = base::OnceCallback<void(Status)>;
virtual ~BlobReader();
// This calculates the total size of the blob, and initializes the reading
// cursor.
// * This should only be called once per reader.
// * Status::Done means that the total_size() value is populated and you can
// continue to SetReadRange or Read.
// * The 'done' callback is only called if Status::IO_PENDING is returned.
// The callback value contains the error code or net::OK. Please use the
// total_size() value to query the blob size, as it's uint64_t.
Status CalculateSize(net::CompletionOnceCallback done);
// Returns true when the blob has side data. CalculateSize must be called
// beforehand. Currently side data is supported only for single DiskCache
// entry blob. So it returns false when the blob has more than single data
// item. This side data is used to pass the V8 code cache which is stored
// as a side stream in the CacheStorage to the renderer. (crbug.com/581613)
bool has_side_data() const;
// Reads the side data of the blob. CalculateSize must be called beforehand.
// * If the side data is read immediately, returns Status::DONE.
// * If an error happens or the blob doesn't have side data, returns
// Status::NET_ERROR and the net error code is set.
// * If this function returns Status::IO_PENDING, the done callback will be
// called with Status::DONE or Status::NET_ERROR.
// Currently side data is supported only for single DiskCache entry blob.
Status ReadSideData(StatusCallback done);
// Returns the side data which has been already read with ReadSideData().
net::IOBufferWithSize* side_data() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return side_data_.get();
}
// Used to set the read position.
// * This should be called after CalculateSize and before Read.
// * Range can only be set once.
Status SetReadRange(uint64_t position, uint64_t length);
// Reads a portion of the data.
// * CalculateSize (and optionally SetReadRange) must be called beforehand.
// * bytes_read is populated only if Status::DONE is returned. Otherwise the
// bytes read (or error code) is populated in the 'done' callback.
// * The done callback is only called if Status::IO_PENDING is returned.
// * This method can be called multiple times. A bytes_read value (either from
// the callback for Status::IO_PENDING or the bytes_read value for
// Status::DONE) of 0 means we're finished reading.
Status Read(net::IOBuffer* buffer,
size_t dest_size,
int* bytes_read,
net::CompletionOnceCallback done);
// Kills reading and invalidates all callbacks. The reader cannot be used
// after this call.
void Kill();
// Returns if all of the blob's items are in memory. Should only be called
// after CalculateSize.
bool IsInMemory() const;
// Returns the remaining bytes to be read in the blob. This is populated
// after CalculateSize, and is modified by SetReadRange.
uint64_t remaining_bytes() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return remaining_bytes_;
}
// Returns the net error code if there was an error. Defaults to net::OK.
int net_error() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return net_error_;
}
// Returns the total size of the blob. This is populated after CalculateSize
// is called.
uint64_t total_size() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(total_size_calculated_);
return total_size_;
}
protected:
friend class BlobDataHandle;
friend class BlobReaderTest;
FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, HandleBeforeAsyncCancel);
FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, ReadFromIncompleteBlob);
BlobReader(const BlobDataHandle* blob_handle);
bool total_size_calculated() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return total_size_calculated_;
}
void SetFileStreamProviderForTesting(
std::unique_ptr<FileStreamReaderProvider> file_stream_provider) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
file_stream_provider_for_testing_ = std::move(file_stream_provider);
}
private:
Status ReportError(int net_error);
void InvalidateCallbacksAndDone(int net_error,
net::CompletionOnceCallback done);
void AsyncCalculateSize(net::CompletionOnceCallback done, BlobStatus status);
// If this returns Status::IO_PENDING, it will take ownership of the callback
// pointed at by |done| and call it when complete. |done| will not be
// modified, otherwise.
Status CalculateSizeImpl(net::CompletionOnceCallback* done);
bool AddItemLength(size_t index, uint64_t length);
bool ResolveFileItemLength(const BlobDataItem& item,
int64_t total_length,
uint64_t* output_length);
void DidGetFileItemLength(size_t index, int64_t result);
void DidCountSize();
// For reading the blob.
// Returns if we're done, PENDING_IO if we're waiting on async.
Status ReadLoop(int* bytes_read);
// Called from asynchronously called methods to continue the read loop.
void ContinueAsyncReadLoop();
// PENDING_IO means we're waiting on async.
Status ReadItem();
void AdvanceItem();
void AdvanceBytesRead(int result);
void ReadBytesItem(const BlobDataItem& item, int bytes_to_read);
BlobReader::Status ReadFileItem(FileStreamReader* reader, int bytes_to_read);
void DidReadFile(int result);
void DeleteCurrentFileReader();
Status ReadDiskCacheEntryItem(const BlobDataItem& item, int bytes_to_read);
void DidReadDiskCacheEntry(int result);
void DidReadItem(int result);
void DidReadDiskCacheEntrySideData(StatusCallback done,
int expected_size,
int result);
int ComputeBytesToRead() const;
int BytesReadCompleted();
// Returns a FileStreamReader for a blob item at |index|.
// If the item at |index| is not of file this returns nullptr.
FileStreamReader* GetOrCreateFileReaderAtIndex(size_t index);
// If the reader is null, then this basically performs a delete operation.
void SetFileReaderAtIndex(size_t index,
std::unique_ptr<FileStreamReader> reader);
// Creates a FileStreamReader for the item with additional_offset.
std::unique_ptr<FileStreamReader> CreateFileStreamReader(
const BlobDataItem& item,
uint64_t additional_offset);
std::unique_ptr<BlobDataHandle> blob_handle_;
std::unique_ptr<BlobDataSnapshot> blob_data_;
std::unique_ptr<FileStreamReaderProvider> file_stream_provider_for_testing_;
scoped_refptr<base::TaskRunner> file_task_runner_;
scoped_refptr<net::IOBufferWithSize> side_data_;
int net_error_;
bool item_list_populated_ = false;
std::vector<uint64_t> item_length_list_;
scoped_refptr<net::DrainableIOBuffer> read_buf_;
bool total_size_calculated_ = false;
uint64_t total_size_ = 0;
uint64_t remaining_bytes_ = 0;
size_t pending_get_file_info_count_ = 0;
std::map<size_t, std::unique_ptr<FileStreamReader>> index_to_reader_;
size_t current_item_index_ = 0;
uint64_t current_item_offset_ = 0;
bool io_pending_ = false;
net::CompletionOnceCallback size_callback_;
net::CompletionOnceCallback read_callback_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<BlobReader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BlobReader);
};
} // namespace storage
#endif // STORAGE_BROWSER_BLOB_BLOB_READER_H_