diff options
author | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-18 00:53:41 +0000 |
---|---|---|
committer | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-18 00:53:41 +0000 |
commit | e5dad137bfa58430440138fbd76699d176fabc74 (patch) | |
tree | 2153c280bd7b6978b1c50456f415e5ee29cf8884 | |
parent | 28b6b9a8ca66f94390e78214c2ad7acfa11f6b78 (diff) | |
download | chromium_src-e5dad137bfa58430440138fbd76699d176fabc74.zip chromium_src-e5dad137bfa58430440138fbd76699d176fabc74.tar.gz chromium_src-e5dad137bfa58430440138fbd76699d176fabc74.tar.bz2 |
Http Cache: Additional byte-range support.
* Now we can serve byte range requests from cached 200s.
* When we receive 304 we make sure that we were expecting it.
* A range request that doesn't fit the currently stored entry
only deletes the entry if the server confirms that it has
changed.
* Make sure that LOAD_ONLY_FROM_CACHE causes cache misses for
byte range requests.
BUG=12258
TEST=unittests
Review URL: http://codereview.chromium.org/165479
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23601 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/http/http_cache.cc | 68 | ||||
-rw-r--r-- | net/http/http_cache_unittest.cc | 233 | ||||
-rw-r--r-- | net/http/partial_data.cc | 70 | ||||
-rw-r--r-- | net/http/partial_data.h | 9 |
4 files changed, 327 insertions, 53 deletions
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index f40f463..7f7dd61 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -178,6 +178,7 @@ class HttpCache::Transaction callback_(NULL), mode_(NONE), reading_(false), + invalid_range_(false), read_offset_(0), effective_load_flags_(0), final_upload_progress_(0), @@ -312,6 +313,9 @@ class HttpCache::Transaction // Makes sure that a 206 response is expected. Returns a network error code. bool ValidatePartialResponse(const HttpResponseHeaders* headers); + // Handles a response validation error by bypassing the cache. + void IgnoreRangeRequest(); + // Reads data from the network. int ReadFromNetwork(IOBuffer* data, int data_len); @@ -380,6 +384,7 @@ class HttpCache::Transaction std::string cache_key_; Mode mode_; bool reading_; // We are already reading. + bool invalid_range_; // We may bypass the cache for this request. scoped_refptr<IOBuffer> read_buf_; int read_buf_len_; int read_offset_; @@ -856,8 +861,17 @@ int HttpCache::Transaction::BeginCacheRead() { DCHECK(mode_ == READ); // Read response headers. - // TODO(rvargas): Handle partial content (206). - return HandleResult(ReadResponseInfoFromEntry()); + int rv = ReadResponseInfoFromEntry(); + if (rv != OK) + return HandleResult(rv); + + // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges. + if (response_.headers->response_code() == 206 || partial_.get()) { + NOTREACHED(); + return HandleResult(ERR_CACHE_MISS); + } + + return HandleResult(rv); } int HttpCache::Transaction::BeginCacheValidation() { @@ -888,7 +902,7 @@ int HttpCache::Transaction::BeginPartialCacheValidation() { return HandleResult(rv); } - if (response_.headers->response_code() != 206) + if (response_.headers->response_code() != 206 && !partial_.get()) return BeginCacheValidation(); #if !defined(ENABLE_RANGE_SUPPORT) @@ -914,6 +928,11 @@ int HttpCache::Transaction::BeginPartialCacheValidation() { return AddToEntry(); } + if (!partial_->IsRequestedRangeOK()) { + // The stored data is fine, but the request may be invalid. + invalid_range_ = true; + } + return ContinuePartialCacheValidation(); } @@ -1109,19 +1128,34 @@ bool HttpCache::Transaction::ConditionalizeRequest() { bool HttpCache::Transaction::ValidatePartialResponse( const HttpResponseHeaders* headers) { + int response_code = headers->response_code(); #ifdef ENABLE_RANGE_SUPPORT - bool partial_content = headers->response_code() == 206; + bool partial_content = response_code == 206; #else bool partial_content = false; #endif + if (invalid_range_) { + // We gave up trying to match this request with the stored data. If the + // server is ok with the request, delete the entry, otherwise just ignore + // this request + if (partial_content || response_code == 200 || response_code == 304) { + DoomPartialEntry(true); + mode_ = NONE; + } else { + IgnoreRangeRequest(); + } + return false; + } + + // TODO(rvargas): Handle 206 when the current range is already cached. bool failure = false; if (!partial_content) { if (!partial_.get()) return false; // TODO(rvargas): Do we need to consider other results here?. - if (headers->response_code() == 200 || headers->response_code() == 416) + if (response_code == 200 || response_code == 416) failure = true; if (!reading_ && failure) { @@ -1131,11 +1165,19 @@ bool HttpCache::Transaction::ValidatePartialResponse( mode_ = NONE; return false; } + + if (response_code == 304 && partial_->ResponseHeadersOK(headers)) + return false; } if (!failure && partial_.get() && partial_->ResponseHeadersOK(headers)) return true; + IgnoreRangeRequest(); + return false; +} + +void HttpCache::Transaction::IgnoreRangeRequest() { // We have a problem. We may or may not be reading already (in which case we // returned the headers), but we'll just pretend that this request is not // using the cache and see what happens. Most likely this is the first @@ -1146,9 +1188,9 @@ bool HttpCache::Transaction::ValidatePartialResponse( cache_->DoneReadingFromEntry(entry_, this); } + partial_.reset(NULL); entry_ = NULL; mode_ = NONE; - return false; } int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { @@ -1291,6 +1333,12 @@ void HttpCache::Transaction::OnNetworkInfoAvailable(int result) { auth_response_ = *new_response; } else { bool partial_content = ValidatePartialResponse(new_response->headers); + if (partial_content && mode_ == READ_WRITE && + response_.headers->response_code() == 200) { + // We have stored the full entry, but it changed and the server is + // sending a range. We have to delete the old entry. + DoneWritingToEntry(false); + } // Are we expecting a response to a conditional query? if (mode_ == READ_WRITE || mode_ == UPDATE) { @@ -1316,15 +1364,13 @@ void HttpCache::Transaction::OnNetworkInfoAvailable(int result) { DoneWritingToEntry(true); } else if (entry_ && !partial_content) { DCHECK_EQ(READ_WRITE, mode_); - if (!partial_.get() || partial_->IsLastRange()) + if (!partial_.get() || partial_->IsLastRange()) { cache_->ConvertWriterToReader(entry_); + mode_ = READ; + } // We no longer need the network transaction, so destroy it. final_upload_progress_ = network_trans_->GetUploadProgress(); network_trans_.reset(); - if (!partial_.get() || partial_->IsLastRange()) { - DCHECK_NE(UPDATE, mode_); - mode_ = READ; - } } } else { mode_ = WRITE; diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 482b463..96118d8 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -464,11 +464,13 @@ const MockTransaction kFastNoStoreGET_Transaction = { class RangeTransactionServer { public: RangeTransactionServer() { - no_store = false; + not_modified_ = false; + } + ~RangeTransactionServer() { + not_modified_ = false; } - ~RangeTransactionServer() {} - void set_no_store(bool value) { no_store = value; } + void set_not_modified(bool value) { not_modified_ = value; } static void RangeHandler(const net::HttpRequestInfo* request, std::string* response_status, @@ -476,9 +478,10 @@ class RangeTransactionServer { std::string* response_data); private: - static bool no_store; + static bool not_modified_; DISALLOW_COPY_AND_ASSIGN(RangeTransactionServer); }; +bool RangeTransactionServer::not_modified_ = false; // Static. void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, @@ -490,12 +493,22 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, return; } + if (not_modified_) { + response_status->assign("HTTP/1.1 304 Not Modified"); + return; + } + std::vector<net::HttpByteRange> ranges; if (!net::HttpUtil::ParseRanges(request->extra_headers, &ranges) || ranges.size() != 1) return; // We can handle this range request. net::HttpByteRange byte_range = ranges[0]; + if (byte_range.first_byte_position() > 79) { + response_status->assign("HTTP/1.1 416 Requested Range Not Satisfiable"); + return; + } + EXPECT_TRUE(byte_range.ComputeBounds(80)); int start = static_cast<int>(byte_range.first_byte_position()); int end = static_cast<int>(byte_range.last_byte_position()); @@ -1645,11 +1658,10 @@ TEST(HttpCache, RangeGET_SkipsCache) { EXPECT_EQ(0, cache.disk_cache()->create_count()); } +// Tests that receiving 206 for a regular request is handled correctly. TEST(HttpCache, GET_Crazy206) { MockHttpCache cache; - // Test that receiving 206 for a regular request is handled correctly. - // Write to the cache. MockTransaction transaction(kRangeGET_TransactionOK); AddMockTransaction(&transaction); @@ -1670,13 +1682,11 @@ TEST(HttpCache, GET_Crazy206) { RemoveMockTransaction(&transaction); } +// Tests that we can cache range requests and fetch random blocks from the +// cache and the network. TEST(HttpCache, DISABLED_RangeGET_OK) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); - - // Test that we can cache range requests and fetch random blocks from the - // cache and the network. - std::string headers; // Write to the cache (40-49). @@ -1727,13 +1737,40 @@ TEST(HttpCache, DISABLED_RangeGET_OK) { RemoveMockTransaction(&kRangeGET_TransactionOK); } -TEST(HttpCache, DISABLED_UnknownRangeGET_1) { +// Tests that we deal with 304s for range requests. +TEST(HttpCache, DISABLED_RangeGET_304) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); + std::string headers; + + // Write to the cache (40-49). + RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, + &headers); + + EXPECT_TRUE(Verify206Response(headers, 40, 49)); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Read from the cache (40-49). + RangeTransactionServer handler; + handler.set_not_modified(true); + RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, + &headers); - // Test that we can cache range requests when the start or end is unknown. - // We start with one suffix request, followed by a request from a given point. + EXPECT_TRUE(Verify206Response(headers, 40, 49)); + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RemoveMockTransaction(&kRangeGET_TransactionOK); +} +// Tests that we can cache range requests when the start or end is unknown. +// We start with one suffix request, followed by a request from a given point. +TEST(HttpCache, DISABLED_UnknownRangeGET_1) { + MockHttpCache cache; + AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; // Write to the cache (70-79). @@ -1763,13 +1800,11 @@ TEST(HttpCache, DISABLED_UnknownRangeGET_1) { RemoveMockTransaction(&kRangeGET_TransactionOK); } +// Tests that we can cache range requests when the start or end is unknown. +// We start with one request from a given point, followed by a suffix request. +// We'll also verify that synchronous cache responses work as intended. TEST(HttpCache, DISABLED_UnknownRangeGET_2) { MockHttpCache cache; - - // Test that we can cache range requests when the start or end is unknown. - // We start with one request from a given point, followed by a suffix request. - // We'll also verify that synchronous cache responses work as intended. - std::string headers; MockTransaction transaction(kRangeGET_TransactionOK); @@ -1803,12 +1838,39 @@ TEST(HttpCache, DISABLED_UnknownRangeGET_2) { RemoveMockTransaction(&transaction); } -TEST(HttpCache, DISABLED_GET_Previous206) { +// Tests that receiving Not Modified when asking for an open range doesn't mess +// up things. +TEST(HttpCache, DISABLED_UnknownRangeGET_304) { MockHttpCache cache; - AddMockTransaction(&kRangeGET_TransactionOK); + std::string headers; + + MockTransaction transaction(kRangeGET_TransactionOK); + AddMockTransaction(&transaction); + + RangeTransactionServer handler; + handler.set_not_modified(true); + + // Ask for the end of the file, without knowing the length. + transaction.request_headers = "Range: bytes = 70-\r\n"; + transaction.data = "rg: 70-79 "; + RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); + + // We just bypass the cache. + EXPECT_EQ(0U, headers.find("HTTP/1.1 304 Not Modified\n")); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RunTransactionTest(cache.http_cache(), transaction); + EXPECT_EQ(2, cache.disk_cache()->create_count()); - // Test that we can handle non-range requests when we have cached a range. + RemoveMockTransaction(&transaction); +} +// Tests that we can handle non-range requests when we have cached a range. +TEST(HttpCache, DISABLED_GET_Previous206) { + MockHttpCache cache; + AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; // Write to the cache (40-49). @@ -1835,11 +1897,10 @@ TEST(HttpCache, DISABLED_GET_Previous206) { RemoveMockTransaction(&kRangeGET_TransactionOK); } +// Tests that we can handle cached 206 responses that are not sparse. TEST(HttpCache, DISABLED_GET_Previous206_NotSparse) { MockHttpCache cache; - // Test that we can handle cached 206 responses that are not sparse. - // Create a disk cache entry that stores 206 headers while not being sparse. disk_cache::Entry* entry; ASSERT_TRUE(cache.disk_cache()->CreateEntry(kSimpleGET_Transaction.url, @@ -1876,13 +1937,12 @@ TEST(HttpCache, DISABLED_GET_Previous206_NotSparse) { EXPECT_EQ(2, cache.disk_cache()->create_count()); } -TEST(HttpCache, DISABLED_GET_Previous206_NotSparse_2) { +// Tests that we can handle cached 206 responses that are not sparse. This time +// we issue a range request and expect to receive a range. +TEST(HttpCache, DISABLED_RangeGET_Previous206_NotSparse_2) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); - // Test that we can handle cached 206 responses that are not sparse. This time - // we issue a range request and expect to receive a range. - // Create a disk cache entry that stores 206 headers while not being sparse. disk_cache::Entry* entry; ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, @@ -1918,12 +1978,56 @@ TEST(HttpCache, DISABLED_GET_Previous206_NotSparse_2) { RemoveMockTransaction(&kRangeGET_TransactionOK); } -TEST(HttpCache, DISABLED_RangeRequestResultsIn200) { +// Tests that we can handle range requests with cached 200 responses. +TEST(HttpCache, DISABLED_RangeGET_Previous200) { MockHttpCache cache; + + // Store the whole thing with status 200. + MockTransaction transaction(kTypicalGET_Transaction); + transaction.url = kRangeGET_TransactionOK.url; + transaction.data = "rg: 00-09 rg: 10-19 rg: 20-29 rg: 30-39 rg: 40-49 " + "rg: 50-59 rg: 60-69 rg: 70-79 "; + AddMockTransaction(&transaction); + RunTransactionTest(cache.http_cache(), transaction); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RemoveMockTransaction(&transaction); AddMockTransaction(&kRangeGET_TransactionOK); - // Test that we can handle a 200 response when dealing with sparse entries. + // Now see that we use the stored entry. + std::string headers; + MockTransaction transaction2(kRangeGET_TransactionOK); + RangeTransactionServer handler; + handler.set_not_modified(true); + RunTransactionTestWithResponse(cache.http_cache(), transaction2, &headers); + + // We are expecting a 206. + EXPECT_TRUE(Verify206Response(headers, 40, 49)); + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Now we should receive a range from the server and drop the stored entry. + handler.set_not_modified(false); + transaction2.request_headers = kRangeGET_TransactionOK.request_headers; + RunTransactionTestWithResponse(cache.http_cache(), transaction2, &headers); + EXPECT_TRUE(Verify206Response(headers, 40, 49)); + EXPECT_EQ(3, cache.network_layer()->transaction_count()); + EXPECT_EQ(2, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RunTransactionTest(cache.http_cache(), transaction2); + EXPECT_EQ(2, cache.disk_cache()->create_count()); + + RemoveMockTransaction(&kRangeGET_TransactionOK); +} +// Tests that we can handle a 200 response when dealing with sparse entries. +TEST(HttpCache, DISABLED_RangeRequestResultsIn200) { + MockHttpCache cache; + AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; // Write to the cache (70-79). @@ -1959,6 +2063,77 @@ TEST(HttpCache, DISABLED_RangeRequestResultsIn200) { RemoveMockTransaction(&transaction2); } +// Tests that a range request that falls outside of the size that we know about +// only deletes the entry if the resource has indeed changed. +TEST(HttpCache, DISABLED_RangeGET_MoreThanCurrentSize) { + MockHttpCache cache; + AddMockTransaction(&kRangeGET_TransactionOK); + std::string headers; + + // Write to the cache (40-49). + RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, + &headers); + + EXPECT_TRUE(Verify206Response(headers, 40, 49)); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // A weird request should not delete this entry. Ask for bytes 120-. + MockTransaction transaction(kRangeGET_TransactionOK); + transaction.request_headers = "Range: bytes = 120-\r\n"; + RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); + + EXPECT_EQ(0U, headers.find("HTTP/1.1 416 ")); + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); + EXPECT_EQ(2, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RemoveMockTransaction(&kRangeGET_TransactionOK); +} + +#ifdef NDEBUG +// This test hits a NOTREACHED so it is a release mode only test. +TEST(HttpCache, DISABLED_RangeGET_OK_LoadOnlyFromCache) { + MockHttpCache cache; + AddMockTransaction(&kRangeGET_TransactionOK); + + // Write to the cache (40-49). + RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Force this transaction to read from the cache. + MockTransaction transaction(kRangeGET_TransactionOK); + transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE; + + MockHttpRequest request(transaction); + TestCompletionCallback callback; + + scoped_ptr<net::HttpTransaction> trans( + cache.http_cache()->CreateTransaction()); + ASSERT_TRUE(trans.get()); + + int rv = trans->Start(&request, &callback, NULL); + if (rv == net::ERR_IO_PENDING) + rv = callback.WaitForResult(); + ASSERT_EQ(net::ERR_CACHE_MISS, rv); + + trans.reset(); + + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + RemoveMockTransaction(&kRangeGET_TransactionOK); +} +#endif + TEST(HttpCache, SyncRead) { MockHttpCache cache; diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc index a4d5976..d24d6fa 100644 --- a/net/http/partial_data.cc +++ b/net/http/partial_data.cc @@ -16,6 +16,7 @@ namespace { // The headers that we have to process. const char kLengthHeader[] = "Content-Length"; const char kRangeHeader[] = "Content-Range"; +const int kDataStream = 1; } @@ -61,8 +62,14 @@ int PartialData::PrepareCacheValidation(disk_cache::Entry* entry, return 0; range_present_ = false; - cached_min_len_ = entry->GetAvailableRange(current_range_start_, len, - &cached_start_); + if (sparse_entry_) { + cached_min_len_ = entry->GetAvailableRange(current_range_start_, len, + &cached_start_); + } else { + cached_min_len_ = len; + cached_start_ = current_range_start_; + } + if (cached_min_len_ < 0) { DCHECK(cached_min_len_ != ERR_IO_PENDING); return cached_min_len_; @@ -104,12 +111,28 @@ bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers, disk_cache::Entry* entry) { std::string length_value; resource_size_ = 0; + if (headers->response_code() == 200) { + DCHECK(byte_range_.IsValid()); + sparse_entry_ = false; + resource_size_ = entry->GetDataSize(kDataStream); + return true; + } + if (!headers->GetNormalizedHeader(kLengthHeader, &length_value)) return false; // We must have stored the resource length. if (!StringToInt64(length_value, &resource_size_) || !resource_size_) return false; + // Make sure that this is really a sparse entry. + int64 n; + if (ERR_CACHE_OPERATION_NOT_SUPPORTED == entry->GetAvailableRange(0, 5, &n)) + return false; + + return true; +} + +bool PartialData::IsRequestedRangeOK() { if (byte_range_.IsValid()) { if (!byte_range_.ComputeBounds(resource_size_)) return false; @@ -122,15 +145,20 @@ bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers, byte_range_.set_last_byte_position(resource_size_ - 1); } - // Make sure that this is really a sparse entry. - int64 n; - if (ERR_CACHE_OPERATION_NOT_SUPPORTED == entry->GetAvailableRange(0, 5, &n)) - return false; + bool rv = current_range_start_ >= 0; + if (!rv) + current_range_start_ = 0; - return current_range_start_ >= 0; + return rv; } bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) { + if (headers->response_code() == 304) { + // We must have a complete range here. + return byte_range_.HasFirstBytePosition() && + byte_range_.HasLastBytePosition(); + } + int64 start, end, total_length; if (!headers->GetContentRange(&start, &end, &total_length)) return false; @@ -168,6 +196,9 @@ void PartialData::FixResponseHeaders(HttpResponseHeaders* headers) { int64 range_len; if (byte_range_.IsValid()) { + if (!sparse_entry_) + headers->ReplaceStatusLine("HTTP/1.1 206 Partial Content"); + DCHECK(byte_range_.HasFirstBytePosition()); DCHECK(byte_range_.HasLastBytePosition()); headers->AddHeader(StringPrintf("%s: bytes %lld-%lld/%lld", kRangeHeader, @@ -194,15 +225,32 @@ void PartialData::FixContentLength(HttpResponseHeaders* headers) { int PartialData::CacheRead(disk_cache::Entry* entry, IOBuffer* data, int data_len, CompletionCallback* callback) { int read_len = std::min(data_len, cached_min_len_); - int rv = entry->ReadSparseData(current_range_start_, data, read_len, - callback); + int rv = 0; + if (sparse_entry_) { + rv = entry->ReadSparseData(current_range_start_, data, read_len, + callback); + } else { + if (current_range_start_ > kint32max) + return ERR_INVALID_ARGUMENT; + + rv = entry->ReadData(kDataStream, static_cast<int>(current_range_start_), + data, read_len, callback); + } return rv; } int PartialData::CacheWrite(disk_cache::Entry* entry, IOBuffer* data, int data_len, CompletionCallback* callback) { - return entry->WriteSparseData(current_range_start_, data, data_len, - callback); + if (sparse_entry_) { + return entry->WriteSparseData(current_range_start_, data, data_len, + callback); + } else { + if (current_range_start_ > kint32max) + return ERR_INVALID_ARGUMENT; + + return entry->WriteData(kDataStream, static_cast<int>(current_range_start_), + data, data_len, callback, false); + } } void PartialData::OnCacheReadCompleted(int result) { diff --git a/net/http/partial_data.h b/net/http/partial_data.h index ade720d..460ff21 100644 --- a/net/http/partial_data.h +++ b/net/http/partial_data.h @@ -31,7 +31,8 @@ class IOBuffer; // of those individual network / cache requests. class PartialData { public: - PartialData() : range_present_(false), final_range_(false) {} + PartialData() + : range_present_(false), final_range_(false), sparse_entry_(true) {} ~PartialData() {} // Performs initialization of the object by parsing the request |headers| @@ -61,10 +62,13 @@ class PartialData { bool IsLastRange() const; // Extracts info from headers already stored in the cache. Returns false if - // there is any problem with the headers or the requested range. + // there is any problem with the headers. bool UpdateFromStoredHeaders(const HttpResponseHeaders* headers, disk_cache::Entry* entry); + // Returns true if the requested range is valid given the stored data. + bool IsRequestedRangeOK(); + // Returns true if the response headers match what we expect, false otherwise. bool ResponseHeadersOK(const HttpResponseHeaders* headers); @@ -106,6 +110,7 @@ class PartialData { std::string extra_headers_; // The clean set of extra headers (no ranges). bool range_present_; // True if next range entry is already stored. bool final_range_; + bool sparse_entry_; DISALLOW_COPY_AND_ASSIGN(PartialData); }; |