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 cb9700211d977052eb75623fd41d4b8832d98e8b..9e2e6e9f433d8d90e2680b2a68a5edecaa804676 100644 |
--- a/net/disk_cache/simple/simple_synchronous_entry.cc |
+++ b/net/disk_cache/simple/simple_synchronous_entry.cc |
@@ -9,6 +9,7 @@ |
#include <functional> |
#include <limits> |
+#include "base/command_line.h" |
#include "base/compiler_specific.h" |
#include "base/files/file_util.h" |
#include "base/hash.h" |
@@ -1092,6 +1093,110 @@ bool SimpleSynchronousEntry::CheckHeaderAndKey(int file_index) { |
return true; |
} |
+bool SimpleSynchronousEntry::ReadStream0Data( |
+ SimpleEntryStat* out_entry_stat, |
+ scoped_refptr<net::GrowableIOBuffer>* stream_0_data, |
+ uint32_t* out_stream_0_crc32) { |
+ // How many bytes in the entry file are consumed by metadata. |
+ const size_t header_overhead_bytes = sizeof(SimpleFileHeader) + key_.size(); |
+ size_t total_overhead_bytes = header_overhead_bytes + 2 * sizeof(SimpleFileEOF); |
+ |
+ int32_t file_size = out_entry_stat->data_size(1); |
+ if (static_cast<int>(total_overhead_bytes) > file_size) |
+ return false; |
+ |
+ // Initially make an aligned read of at least 32k (or read the entire file), |
+ // which should be large enough to retrieve the stream 0 data and both EOF |
+ // records. |
+ std::vector<char> tail_data(std::min(file_size, |
+ 8192 + file_size % 4096)); |
+ int bytes_read = files_[0].Read(file_size - tail_data.size(), |
+ tail_data.data(), tail_data.size()); |
+ if (bytes_read != static_cast<int>(tail_data.size())) |
+ return false; |
+ |
+ const SimpleFileEOF* stream_0_eof = reinterpret_cast<const SimpleFileEOF*>(tail_data.data() + tail_data.size() - sizeof(SimpleFileEOF)); |
+ |
+ if (stream_0_eof->final_magic_number != kSimpleFinalMagicNumber) |
+ return false; |
+ if (!base::IsValueInRangeForNumericType<int32_t>(stream_0_eof->stream_size)) |
+ return false; |
+ const int32_t stream_0_size = stream_0_eof->stream_size; |
+ |
+ const bool has_key_sha256 = (stream_0_eof->flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) == SimpleFileEOF::FLAG_HAS_KEY_SHA256; |
+ const bool has_crc32 = (stream_0_eof->flags & SimpleFileEOF::FLAG_HAS_CRC32) == SimpleFileEOF::FLAG_HAS_CRC32; |
+ const uint32_t data_crc32 = stream_0_eof->data_crc32; |
+ // Clear |stream_0_eof| because subsequent vector resize operations may invalidate it. |
+ stream_0_eof = nullptr; |
+ |
+ base::CheckedNumeric<size_t> tail_bytes_needed = 2 * sizeof(SimpleFileEOF); |
+ if (has_key_sha256) { |
+ total_overhead_bytes += sizeof(net::SHA256HashValue); |
+ tail_bytes_needed += sizeof(net::SHA256HashValue); |
+ } |
+ if (stream_0_size > file_size - static_cast<int>(total_overhead_bytes)) |
+ return false; |
+ |
+ tail_bytes_needed += stream_0_size; |
+ if (!tail_bytes_needed.IsValid()) |
+ return false; |
+ size_t safe_tail_bytes_needed = tail_bytes_needed.ValueOrDie(); |
+ if (safe_tail_bytes_needed > file_size - header_overhead_bytes) |
+ return false; |
+ if (safe_tail_bytes_needed > tail_data.size()) { |
+ // The tail read was too short, we need to enlarge the buffer and read the extra |
+ // data. |
+ size_t missing_bytes = safe_tail_bytes_needed - tail_data.size(); |
+ if (!base::IsValueInRangeForNumericType<int>(missing_bytes)) |
+ return false; |
+ |
+ LOG(INFO) << "doing a second read. Originally " << tail_data.size() << ", but need " << safe_tail_bytes_needed << ", so reading " << missing_bytes; |
+ LOG(INFO) << "key length " << key_.size(); |
+ tail_data.resize(safe_tail_bytes_needed); |
+ std::copy_backward(tail_data.begin(), tail_data.end() - missing_bytes, |
+ tail_data.end()); |
+ if (files_[0].Read(file_size - safe_tail_bytes_needed, |
+ tail_data.data(), missing_bytes) != static_cast<int>(missing_bytes)) { |
+ return false; |
+ } |
+ } |
+ |
+ // Calculate and set the real values for data size. |
+ out_entry_stat->set_data_size(0, stream_0_size); |
+ out_entry_stat->set_data_size(1, file_size - total_overhead_bytes - stream_0_size); |
+ |
+ // Copy stream 0 data. |
+ *stream_0_data = new net::GrowableIOBuffer(); |
+ (*stream_0_data)->SetCapacity(out_entry_stat->data_size(0)); |
+ std::copy_n(tail_data.end() - safe_tail_bytes_needed + sizeof(SimpleFileEOF), |
+ stream_0_size, (*stream_0_data)->data()); |
+ |
+ // Check the CRC32. |
+ uint32_t expected_crc32 = crc32(0, Z_NULL, 0); |
+ if (stream_0_size != 0) { |
+ expected_crc32 = crc32(expected_crc32, |
+ reinterpret_cast<const Bytef*>((*stream_0_data)->data()), |
+ stream_0_size); |
+ } |
+ if (has_crc32 && data_crc32 != expected_crc32) { |
+ return false; |
+ } |
+ *out_stream_0_crc32 = expected_crc32; |
+ |
+ if (has_key_sha256) { |
+ net::SHA256HashValue hash_value; |
+ CalculateSHA256OfKey(key_, &hash_value); |
+ bool matched = std::memcmp(&hash_value, tail_data.data() + tail_data.size() - sizeof(SimpleFileEOF) - sizeof(hash_value), sizeof(hash_value)) == 0; |
+ if (!matched) { |
+ return false; |
+ } |
+ } |
+ |
+ if (!has_key_sha256 && header_and_key_check_needed_[0]) |
+ CheckHeaderAndKey(0); |
+ return true; |
+} |
+ |
int SimpleSynchronousEntry::InitializeForOpen( |
SimpleEntryStat* out_entry_stat, |
scoped_refptr<net::GrowableIOBuffer>* stream_0_data, |
@@ -1122,12 +1227,17 @@ 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); |
- if (ret_value_stream_0 != net::OK) |
- return ret_value_stream_0; |
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch("backseek")) { |
+ if (!ReadStream0Data(out_entry_stat, stream_0_data, out_stream_0_crc32)) |
+ return net::ERR_FAILED; |
+ } else { |
+ // 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); |
+ if (ret_value_stream_0 != net::OK) |
+ return ret_value_stream_0; |
+ } |
} else { |
out_entry_stat->set_data_size( |
2, |