| Index: net/disk_cache/simple/simple_synchronous_entry.cc
|
| diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
|
| index dc27812c71382e95de0430d79a699a080174899d..1c21f44b30af1133accfc140b804a161d4af8f0d 100644
|
| --- a/net/disk_cache/simple/simple_synchronous_entry.cc
|
| +++ b/net/disk_cache/simple/simple_synchronous_entry.cc
|
| @@ -13,6 +13,7 @@
|
| #include "base/files/file_util.h"
|
| #include "base/hash.h"
|
| #include "base/location.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/metrics/histogram_macros.h"
|
| #include "base/numerics/safe_conversions.h"
|
| #include "base/sha1.h"
|
| @@ -269,7 +270,8 @@ void SimpleSynchronousEntry::OpenEntry(
|
| new SimpleSynchronousEntry(cache_type, path, key, entry_hash, had_index);
|
| out_results->result = sync_entry->InitializeForOpen(
|
| &out_results->entry_stat, &out_results->stream_0_data,
|
| - &out_results->stream_0_crc32);
|
| + &out_results->stream_0_crc32, &out_results->stream_1_data,
|
| + &out_results->stream_1_crc32);
|
| if (out_results->result != net::OK) {
|
| sync_entry->Doom();
|
| delete sync_entry;
|
| @@ -692,19 +694,17 @@ void SimpleSynchronousEntry::GetAvailableRange(
|
|
|
| int SimpleSynchronousEntry::CheckEOFRecord(int index,
|
| const SimpleEntryStat& entry_stat,
|
| - uint32_t expected_crc32) const {
|
| + uint32_t expected_crc32) {
|
| DCHECK(initialized_);
|
| - uint32_t crc32;
|
| - bool has_crc32;
|
| - bool has_key_sha256;
|
| - int32_t stream_size;
|
| - int rv = GetEOFRecordData(index, entry_stat, &has_crc32, &has_key_sha256,
|
| - &crc32, &stream_size);
|
| + SimpleFileEOF eof_record;
|
| + int rv = GetEOFRecordData(nullptr, 0, index, entry_stat, &eof_record);
|
| +
|
| if (rv != net::OK) {
|
| Doom();
|
| return rv;
|
| }
|
| - if (has_crc32 && crc32 != expected_crc32) {
|
| + if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
|
| + eof_record.data_crc32 != expected_crc32) {
|
| DVLOG(1) << "EOF record had bad crc.";
|
| RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
|
| Doom();
|
| @@ -714,6 +714,41 @@ int SimpleSynchronousEntry::CheckEOFRecord(int index,
|
| return net::OK;
|
| }
|
|
|
| +int SimpleSynchronousEntry::PreReadStreamPayload(
|
| + char* prefetch_buf,
|
| + int file_size,
|
| + int stream_index,
|
| + int extra_size,
|
| + const SimpleEntryStat& entry_stat,
|
| + const SimpleFileEOF& eof_record,
|
| + scoped_refptr<net::GrowableIOBuffer>* stream_data,
|
| + uint32_t* out_crc32) {
|
| + int stream_size = entry_stat.data_size(stream_index);
|
| + int read_size = stream_size + extra_size;
|
| + *stream_data = new net::GrowableIOBuffer();
|
| + (*stream_data)->SetCapacity(read_size);
|
| + int file_offset = entry_stat.GetOffsetInFile(key_.size(), 0, stream_index);
|
| + if (!ReadFromFileOrPrefetched(prefetch_buf, file_size, file_offset, read_size,
|
| + (*stream_data)->data()))
|
| + return net::ERR_FAILED;
|
| +
|
| + // Check the CRC32.
|
| + uint32_t expected_crc32 =
|
| + stream_size == 0
|
| + ? crc32(0, Z_NULL, 0)
|
| + : crc32(crc32(0, Z_NULL, 0),
|
| + reinterpret_cast<const Bytef*>((*stream_data)->data()),
|
| + stream_size);
|
| + if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
|
| + eof_record.data_crc32 != expected_crc32) {
|
| + DVLOG(1) << "EOF record had bad crc.";
|
| + RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
|
| + return net::ERR_CACHE_CHECKSUM_MISMATCH;
|
| + }
|
| + *out_crc32 = expected_crc32;
|
| + return net::OK;
|
| +}
|
| +
|
| void SimpleSynchronousEntry::Close(
|
| const SimpleEntryStat& entry_stat,
|
| std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write,
|
| @@ -1096,7 +1131,9 @@ bool SimpleSynchronousEntry::CheckHeaderAndKey(int file_index) {
|
| int SimpleSynchronousEntry::InitializeForOpen(
|
| SimpleEntryStat* out_entry_stat,
|
| scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
|
| - uint32_t* out_stream_0_crc32) {
|
| + uint32_t* out_stream_0_crc32,
|
| + scoped_refptr<net::GrowableIOBuffer>* stream_1_data,
|
| + uint32_t* out_stream_1_crc32) {
|
| DCHECK(!initialized_);
|
| if (!OpenFiles(out_entry_stat)) {
|
| DLOG(WARNING) << "Could not open platform files for entry.";
|
| @@ -1124,9 +1161,9 @@ int SimpleSynchronousEntry::InitializeForOpen(
|
|
|
| if (i == 0) {
|
| // File size for stream 0 has been stored temporarily in data_size[1].
|
| - int ret_value_stream_0 =
|
| - ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat,
|
| - stream_0_data, out_stream_0_crc32);
|
| + int ret_value_stream_0 = ReadAndValidateStream0(
|
| + out_entry_stat->data_size(1), out_entry_stat, stream_0_data,
|
| + out_stream_0_crc32, stream_1_data, out_stream_1_crc32);
|
| if (ret_value_stream_0 != net::OK)
|
| return ret_value_stream_0;
|
| } else {
|
| @@ -1221,7 +1258,20 @@ int SimpleSynchronousEntry::ReadAndValidateStream0(
|
| int file_size,
|
| SimpleEntryStat* out_entry_stat,
|
| scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
|
| - uint32_t* out_stream_0_crc32) {
|
| + uint32_t* out_stream_0_crc32,
|
| + scoped_refptr<net::GrowableIOBuffer>* stream_1_data,
|
| + uint32_t* out_stream_1_crc32) {
|
| + // If the file is sufficiently small, we will prefetch everything --
|
| + // in which case |prefetch_buf| will be non-null, and we should look at it
|
| + // rather than call ::Read for the bits.
|
| + std::unique_ptr<char[]> prefetch_buf;
|
| + const int kPrefetchLimit = 32 * 1024;
|
| + if (file_size <= kPrefetchLimit) {
|
| + prefetch_buf = base::MakeUnique<char[]>(file_size);
|
| + if (files_[0].Read(0, prefetch_buf.get(), file_size) != file_size)
|
| + return net::ERR_FAILED;
|
| + }
|
| +
|
| // Pretend this file has a null stream zero, and contains the optional key
|
| // SHA256. This is good enough to read the EOF record on the file, which gives
|
| // the actual size of stream 0.
|
| @@ -1230,49 +1280,56 @@ int SimpleSynchronousEntry::ReadAndValidateStream0(
|
| out_entry_stat->set_data_size(
|
| 1, temp_data_size - sizeof(net::SHA256HashValue) - sizeof(SimpleFileEOF));
|
|
|
| - bool has_crc32;
|
| - bool has_key_sha256;
|
| - uint32_t read_crc32;
|
| - int32_t stream_0_size;
|
| - int ret_value_crc32 =
|
| - GetEOFRecordData(0, *out_entry_stat, &has_crc32, &has_key_sha256,
|
| - &read_crc32, &stream_0_size);
|
| - if (ret_value_crc32 != net::OK)
|
| - return ret_value_crc32;
|
| + SimpleFileEOF stream_0_eof;
|
| + int rv = GetEOFRecordData(prefetch_buf.get(), file_size, 0, *out_entry_stat,
|
| + &stream_0_eof);
|
| + if (rv != net::OK)
|
| + return rv;
|
| +
|
| + bool has_key_sha256 =
|
| + (stream_0_eof.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
|
| + SimpleFileEOF::FLAG_HAS_KEY_SHA256;
|
| + int32_t stream_0_size = stream_0_eof.stream_size;
|
|
|
| // Calculate and set the real values for the two streams.
|
| int32_t total_size = out_entry_stat->data_size(1);
|
| if (!has_key_sha256)
|
| total_size += sizeof(net::SHA256HashValue);
|
| +
|
| + // Sanity-check: don't want to be allocating a gigantic buffer > file size
|
| + // just because of a header field.
|
| if (stream_0_size > total_size)
|
| return net::ERR_FAILED;
|
| out_entry_stat->set_data_size(0, stream_0_size);
|
| out_entry_stat->set_data_size(1, total_size - stream_0_size);
|
|
|
| - // Put stream 0 data in memory.
|
| - *stream_0_data = new net::GrowableIOBuffer();
|
| - (*stream_0_data)->SetCapacity(stream_0_size + sizeof(net::SHA256HashValue));
|
| - int file_offset = out_entry_stat->GetOffsetInFile(key_.size(), 0, 0);
|
| - int read_size = stream_0_size;
|
| + // Put stream 0 data in memory --- plus maybe the sha256(key) footer.
|
| + int extra_stream_0_read = 0;
|
| if (has_key_sha256)
|
| - read_size += sizeof(net::SHA256HashValue);
|
| - if (files_[0].Read(file_offset, (*stream_0_data)->data(), read_size) !=
|
| - read_size)
|
| - return net::ERR_FAILED;
|
| + extra_stream_0_read += sizeof(net::SHA256HashValue);
|
| + rv = PreReadStreamPayload(prefetch_buf.get(), file_size, 0,
|
| + extra_stream_0_read, *out_entry_stat, stream_0_eof,
|
| + stream_0_data, out_stream_0_crc32);
|
| + if (rv != net::OK)
|
| + return rv;
|
|
|
| - // Check the CRC32.
|
| - uint32_t expected_crc32 =
|
| - stream_0_size == 0
|
| - ? crc32(0, Z_NULL, 0)
|
| - : crc32(crc32(0, Z_NULL, 0),
|
| - reinterpret_cast<const Bytef*>((*stream_0_data)->data()),
|
| - stream_0_size);
|
| - if (has_crc32 && read_crc32 != expected_crc32) {
|
| - DVLOG(1) << "EOF record had bad crc.";
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
|
| - return net::ERR_FAILED;
|
| + // If prefetch buffer is available, and we have sha256(key) (so we don't need
|
| + // to look at the header), extract out stream 1 info as well.
|
| + if (prefetch_buf && has_key_sha256) {
|
| + SimpleFileEOF stream_1_eof;
|
| + rv = GetEOFRecordData(prefetch_buf.get(), file_size, 1, *out_entry_stat,
|
| + &stream_1_eof);
|
| + if (rv != net::OK)
|
| + return rv;
|
| +
|
| + rv = PreReadStreamPayload(prefetch_buf.get(), file_size, 1, 0,
|
| + *out_entry_stat, stream_1_eof, stream_1_data,
|
| + out_stream_1_crc32);
|
| + if (rv != net::OK)
|
| + return rv;
|
| + } else {
|
| + *stream_1_data = nullptr;
|
| }
|
| - *out_stream_0_crc32 = expected_crc32;
|
|
|
| // If present, check the key SHA256.
|
| if (has_key_sha256) {
|
| @@ -1300,40 +1357,66 @@ int SimpleSynchronousEntry::ReadAndValidateStream0(
|
| return net::OK;
|
| }
|
|
|
| -int SimpleSynchronousEntry::GetEOFRecordData(int index,
|
| +bool SimpleSynchronousEntry::ReadFromFileOrPrefetched(char* prefetch_buf,
|
| + int file_size,
|
| + int offset,
|
| + int size,
|
| + char* dest) {
|
| + if (!prefetch_buf) {
|
| + return files_[0].Read(offset, dest, size) == size;
|
| + } else {
|
| + if (offset < 0 || size < 0)
|
| + return false;
|
| + base::CheckedNumeric<int> end =
|
| + base::CheckedNumeric<int>(offset) + size - 1;
|
| + if (!end.IsValid())
|
| + return false;
|
| + if (offset >= file_size || end.ValueOrDie() >= file_size)
|
| + return false;
|
| +
|
| + memcpy(dest, prefetch_buf + offset, size);
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +int SimpleSynchronousEntry::GetEOFRecordData(char* prefetch_buf,
|
| + int file_size,
|
| + int stream_index,
|
| const SimpleEntryStat& entry_stat,
|
| - bool* out_has_crc32,
|
| - bool* out_has_key_sha256,
|
| - uint32_t* out_crc32,
|
| - int32_t* out_data_size) const {
|
| - SimpleFileEOF eof_record;
|
| - int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), index);
|
| - int file_index = GetFileIndexFromStreamIndex(index);
|
| - File* file = const_cast<File*>(&files_[file_index]);
|
| - if (file->Read(file_offset, reinterpret_cast<char*>(&eof_record),
|
| - sizeof(eof_record)) !=
|
| - sizeof(eof_record)) {
|
| + SimpleFileEOF* eof_record) {
|
| + int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), stream_index);
|
| + int file_index = GetFileIndexFromStreamIndex(stream_index);
|
| +
|
| + // Should only have prefetch_buf when reading things in file 0.
|
| + DCHECK(file_index == 0 || !prefetch_buf);
|
| + bool ok;
|
| + if (prefetch_buf)
|
| + ok = ReadFromFileOrPrefetched(prefetch_buf, file_size, file_offset,
|
| + sizeof(SimpleFileEOF),
|
| + reinterpret_cast<char*>(eof_record));
|
| + else
|
| + // Need to support files_[1], so can't use ReadFromFileOrPrefetched
|
| + // in this case.
|
| + ok = files_[file_index].Read(
|
| + file_offset, reinterpret_cast<char*>(eof_record),
|
| + sizeof(SimpleFileEOF)) == sizeof(SimpleFileEOF);
|
| +
|
| + if (!ok) {
|
| RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE);
|
| return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
|
| }
|
|
|
| - if (eof_record.final_magic_number != kSimpleFinalMagicNumber) {
|
| + if (eof_record->final_magic_number != kSimpleFinalMagicNumber) {
|
| RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH);
|
| DVLOG(1) << "EOF record had bad magic number.";
|
| return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
|
| }
|
|
|
| - if (!base::IsValueInRangeForNumericType<int32_t>(eof_record.stream_size))
|
| + if (!base::IsValueInRangeForNumericType<int32_t>(eof_record->stream_size))
|
| return net::ERR_FAILED;
|
| -
|
| - *out_has_crc32 = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) ==
|
| - SimpleFileEOF::FLAG_HAS_CRC32;
|
| - *out_has_key_sha256 =
|
| - (eof_record.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
|
| - SimpleFileEOF::FLAG_HAS_KEY_SHA256;
|
| - *out_crc32 = eof_record.data_crc32;
|
| - *out_data_size = eof_record.stream_size;
|
| - SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, *out_has_crc32);
|
| + SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_,
|
| + (eof_record->flags & SimpleFileEOF::FLAG_HAS_CRC32) ==
|
| + SimpleFileEOF::FLAG_HAS_CRC32);
|
| return net::OK;
|
| }
|
|
|
|
|