Http Cache: Improve handling of unexpected responses with byte ranges.
The main change here is to keep track of the end of the requested range
so that when a server returns a different range, we can make sure we
detect the condition and update the response accordingly. Previously we
could detect the condition but fail to update the returned headers (or
more preciselly, overwrite the range header as if nothing happen).
The second change is to avoid reissuing the same network requests twice.
When we detect an unexpected response or an error, we often try to
remove headers changed by the cache an reissue the request; This could
cause the same request issued again (if we didn't add anything to start
with). Now we avoid reissuing requests if there was nothing cached to
start with (so we did not have to modify the requested range).
BUG=421787, 421266
TEST=net_unittests
Review URL: https://codereview.chromium.org/739803002
Cr-Commit-Position: refs/heads/master@{#310015}
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 8e60427..50e9da10 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -2718,9 +2718,13 @@
return true;
} else {
// We asked for "If-Range: " so a 206 means just another range.
- if (partial_response && partial_->ResponseHeadersOK(headers)) {
- handling_206_ = true;
- return true;
+ if (partial_response) {
+ if (partial_->ResponseHeadersOK(headers)) {
+ handling_206_ = true;
+ return true;
+ } else {
+ failure = true;
+ }
}
if (!reading_ && !is_sparse_ && !partial_response) {
@@ -2747,17 +2751,24 @@
if (failure) {
// We cannot truncate this entry, it has to be deleted.
UpdateTransactionPattern(PATTERN_NOT_COVERED);
+ bool is_sparse = is_sparse_;
DoomPartialEntry(false);
mode_ = NONE;
- if (!reading_ && !partial_->IsLastRange()) {
- // We'll attempt to issue another network request, this time without us
- // messing up the headers.
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- partial_.reset();
- truncated_ = false;
- return false;
+ if (is_sparse || truncated_) {
+ // There was something cached to start with, either sparsed data (206), or
+ // a truncated 200, which means that we probably modified the request,
+ // adding a byte range or modifying the range requested by the caller.
+ if (!reading_ && !partial_->IsLastRange()) {
+ // We have not returned anything to the caller yet so it should be safe
+ // to issue another network request, this time without us messing up the
+ // headers.
+ partial_->RestoreHeaders(&custom_request_->extra_headers);
+ partial_.reset();
+ truncated_ = false;
+ return false;
+ }
+ LOG(WARNING) << "Failed to revalidate partial entry";
}
- LOG(WARNING) << "Failed to revalidate partial entry";
partial_.reset();
return true;
}
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 2a7968af..d38d455 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -293,6 +293,10 @@
// Returns 200 instead of 206 (a malformed response overall).
void set_bad_200(bool value) { bad_200_ = value; }
+ // Other than regular range related behavior (and the flags mentioned above),
+ // the server reacts to requests headers like so:
+ // X-Require-Mock-Auth -> return 401.
+ // X-Return-Default-Range -> assume 40-49 was requested.
static void RangeHandler(const net::HttpRequestInfo* request,
std::string* response_status,
std::string* response_headers,
@@ -362,6 +366,12 @@
// We can handle this range request.
net::HttpByteRange byte_range = ranges[0];
+
+ if (request->extra_headers.HasHeader("X-Return-Default-Range")) {
+ byte_range.set_first_byte_position(40);
+ byte_range.set_last_byte_position(49);
+ }
+
if (byte_range.first_byte_position() > 79) {
response_status->assign("HTTP/1.1 416 Requested Range Not Satisfiable");
response_data->clear();
@@ -426,6 +436,10 @@
net::OK
};
+const char kFullRangeData[] =
+ "rg: 00-09 rg: 10-19 rg: 20-29 rg: 30-39 "
+ "rg: 40-49 rg: 50-59 rg: 60-69 rg: 70-79 ";
+
// Verifies the response headers (|response|) match a partial content
// response for the range starting at |start| and ending at |end|.
void Verify206Response(std::string response, int start, int end) {
@@ -4111,6 +4125,251 @@
RemoveMockTransaction(&kRangeGET_TransactionOK);
}
+// Tests that when a server returns 206 with a sub-range of the requested range,
+// and there is nothing stored in the cache, the returned response is passed to
+// the caller as is. In this context, a subrange means a response that starts
+// with the same byte that was requested, but that is not the whole range that
+// was requested.
+TEST(HttpCache, RangeGET_206ReturnsSubrangeRange_NoCachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Request a large range (40-59). The server sends 40-49.
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 40-59\r\n" EXTRA_HEADER;
+ transaction.response_headers =
+ "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n"
+ "ETag: \"foo\"\n"
+ "Accept-Ranges: bytes\n"
+ "Content-Length: 10\n"
+ "Content-Range: bytes 40-49/80\n";
+ transaction.handler = nullptr;
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ 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());
+}
+
+// Tests that when a server returns 206 with a sub-range of the requested range,
+// and there was an entry stored in the cache, the cache gets out of the way.
+TEST(HttpCache, RangeGET_206ReturnsSubrangeRange_CachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Write to the cache (70-79).
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 70-79\r\n" EXTRA_HEADER;
+ transaction.data = "rg: 70-79 ";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+ Verify206Response(headers, 70, 79);
+
+ // Request a large range (40-79). The cache will ask the server for 40-59.
+ // The server returns 40-49. The cache should consider the server confused and
+ // abort caching, restarting the request without caching.
+ transaction.request_headers = "Range: bytes = 40-79\r\n" EXTRA_HEADER;
+ transaction.response_headers =
+ "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n"
+ "ETag: \"foo\"\n"
+ "Accept-Ranges: bytes\n"
+ "Content-Length: 10\n"
+ "Content-Range: bytes 40-49/80\n";
+ transaction.handler = nullptr;
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ // Two new network requests were issued, one from the cache and another after
+ // deleting the entry.
+ Verify206Response(headers, 40, 49);
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // The entry was deleted.
+ RunTransactionTest(cache.http_cache(), transaction);
+ EXPECT_EQ(4, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Tests that when a server returns 206 with a sub-range of the requested range,
+// and there was an entry stored in the cache, the cache gets out of the way,
+// when the caller is not using ranges.
+TEST(HttpCache, GET_206ReturnsSubrangeRange_CachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Write to the cache (70-79).
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 70-79\r\n" EXTRA_HEADER;
+ transaction.data = "rg: 70-79 ";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+ Verify206Response(headers, 70, 79);
+
+ // Don't ask for a range. The cache will ask the server for 0-69.
+ // The server returns 40-49. The cache should consider the server confused and
+ // abort caching, restarting the request.
+ // The second network request should not be a byte range request so the server
+ // should return 200 + "Not a range"
+ transaction.request_headers = "X-Return-Default-Range:\r\n" EXTRA_HEADER;
+ transaction.data = "Not a range";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ EXPECT_EQ(0U, headers.find("HTTP/1.1 200 OK\n"));
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // The entry was deleted.
+ RunTransactionTest(cache.http_cache(), transaction);
+ EXPECT_EQ(4, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Tests that when a server returns 206 with a random range and there is
+// nothing stored in the cache, the returned response is passed to the caller
+// as is. In this context, a WrongRange means that the returned range may or may
+// not have any relationship with the requested range (may or may not be
+// contained). The important part is that the first byte doesn't match the first
+// requested byte.
+TEST(HttpCache, RangeGET_206ReturnsWrongRange_NoCachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Request a large range (30-59). The server sends (40-49).
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 30-59\r\n" EXTRA_HEADER;
+ transaction.response_headers =
+ "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n"
+ "ETag: \"foo\"\n"
+ "Accept-Ranges: bytes\n"
+ "Content-Length: 10\n"
+ "Content-Range: bytes 40-49/80\n";
+ transaction.handler = nullptr;
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ 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());
+
+ // The entry was deleted.
+ RunTransactionTest(cache.http_cache(), transaction);
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Tests that when a server returns 206 with a random range and there is
+// an entry stored in the cache, the cache gets out of the way.
+TEST(HttpCache, RangeGET_206ReturnsWrongRange_CachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Write to the cache (70-79).
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 70-79\r\n" EXTRA_HEADER;
+ transaction.data = "rg: 70-79 ";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+ Verify206Response(headers, 70, 79);
+
+ // Request a large range (30-79). The cache will ask the server for 30-69.
+ // The server returns 40-49. The cache should consider the server confused and
+ // abort caching, returning the weird range to the caller.
+ transaction.request_headers = "Range: bytes = 30-79\r\n" EXTRA_HEADER;
+ transaction.response_headers =
+ "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n"
+ "ETag: \"foo\"\n"
+ "Accept-Ranges: bytes\n"
+ "Content-Length: 10\n"
+ "Content-Range: bytes 40-49/80\n";
+ transaction.handler = nullptr;
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ Verify206Response(headers, 40, 49);
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // The entry was deleted.
+ RunTransactionTest(cache.http_cache(), transaction);
+ EXPECT_EQ(4, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Tests that when a caller asks for a range beyond EOF, with an empty cache,
+// the response matches the one provided by the server.
+TEST(HttpCache, RangeGET_206ReturnsSmallerFile_NoCachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Request a large range (70-99). The server sends 70-79.
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 70-99\r\n" EXTRA_HEADER;
+ transaction.data = "rg: 70-79 ";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ Verify206Response(headers, 70, 79);
+ 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(), kRangeGET_TransactionOK);
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+}
+
+// Tests that when a caller asks for a range beyond EOF, with a cached entry,
+// the cache automatically fixes the request.
+TEST(HttpCache, RangeGET_206ReturnsSmallerFile_CachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Write to the cache (40-49).
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ // Request a large range (70-99). The server sends 70-79.
+ transaction.request_headers = "Range: bytes = 70-99\r\n" EXTRA_HEADER;
+ transaction.data = "rg: 70-79 ";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ Verify206Response(headers, 70, 79);
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // The entry was not deleted (the range was automatically fixed).
+ RunTransactionTest(cache.http_cache(), transaction);
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ EXPECT_EQ(2, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+}
+
+// Tests that when a caller asks for a not-satisfiable range, the server's
+// response is forwarded to the caller.
+TEST(HttpCache, RangeGET_416_NoCachedContent) {
+ MockHttpCache cache;
+ std::string headers;
+
+ // Request a range beyond EOF (80-99).
+ ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = 80-99\r\n" EXTRA_HEADER;
+ transaction.data = "";
+ transaction.status = "HTTP/1.1 416 Requested Range Not Satisfiable";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ EXPECT_EQ(0U, headers.find(transaction.status));
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // The entry was deleted.
+ RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK);
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
// Tests that we cache 301s for range requests.
TEST(HttpCache, RangeGET_301) {
MockHttpCache cache;
@@ -4119,7 +4378,6 @@
transaction.response_headers = "Location: http://www.bar.com/\n";
transaction.data = "";
transaction.handler = NULL;
- AddMockTransaction(&transaction);
// Write to the cache.
RunTransactionTest(cache.http_cache(), transaction);
@@ -4132,8 +4390,6 @@
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(&transaction);
}
// Tests that we can cache range requests when the start or end is unknown.
@@ -4260,8 +4516,7 @@
// Write and read from the cache (0-79), when not asked for a range.
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = EXTRA_HEADER;
- 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 ";
+ transaction.data = kFullRangeData;
RunTransactionTestWithResponseAndGetTiming(
cache.http_cache(), transaction, &headers, log.bound(),
&load_timing_info);
@@ -4311,8 +4566,7 @@
// Read from the cache (0-9), write and read from cache (10 - 79).
transaction.load_flags |= net::LOAD_VALIDATE_CACHE;
transaction.request_headers = "Foo: bar\r\n" EXTRA_HEADER;
- 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 ";
+ transaction.data = kFullRangeData;
RunTransactionTestWithResponseAndGetTiming(
cache.http_cache(), transaction, &headers, log.bound(),
&load_timing_info);
@@ -4512,8 +4766,7 @@
// 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 ";
+ transaction.data = kFullRangeData;
AddMockTransaction(&transaction);
RunTransactionTest(cache.http_cache(), transaction);
EXPECT_EQ(1, cache.network_layer()->transaction_count());
@@ -4846,7 +5099,7 @@
}
// Tests that if a server tells us conflicting information about a resource we
-// ignore the response.
+// drop the entry.
TEST(HttpCache, RangeGET_InvalidResponse3) {
MockHttpCache cache;
std::string headers;
@@ -4878,17 +5131,10 @@
EXPECT_EQ(1, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
- // Verify that we cached the first response but not the second one.
- disk_cache::Entry* en;
- ASSERT_TRUE(cache.OpenBackendEntry(kRangeGET_TransactionOK.url, &en));
-
- int64 cached_start = 0;
- net::TestCompletionCallback cb;
- int rv = en->GetAvailableRange(40, 20, &cached_start, cb.callback());
- EXPECT_EQ(10, cb.GetResult(rv));
- EXPECT_EQ(50, cached_start);
- en->Close();
-
+ // Verify that the entry is gone.
+ RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK);
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
RemoveMockTransaction(&kRangeGET_TransactionOK);
}
@@ -5346,8 +5592,7 @@
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = EXTRA_HEADER;
- 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 ";
+ transaction.data = kFullRangeData;
RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
// We update the headers with the ones received while revalidating.
@@ -5395,8 +5640,7 @@
std::string response_headers(transaction.response_headers);
response_headers += ("Cache-Control: no-store\n");
transaction.response_headers = response_headers.c_str();
- 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 ";
+ transaction.data = kFullRangeData;
AddMockTransaction(&transaction);
std::string headers;
@@ -5441,8 +5685,7 @@
std::string response_headers(transaction.response_headers);
response_headers += ("Cache-Control: no-store\n");
transaction.response_headers = response_headers.c_str();
- 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 ";
+ transaction.data = kFullRangeData;
AddMockTransaction(&transaction);
MockHttpRequest request(transaction);
@@ -5536,8 +5779,7 @@
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = EXTRA_HEADER;
- 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 ";
+ transaction.data = kFullRangeData;
scoped_ptr<Context> c(new Context);
int rv = cache.CreateTransaction(&c->trans);
@@ -5571,8 +5813,7 @@
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = "X-Require-Mock-Auth: dummy\r\n"
EXTRA_HEADER;
- 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 ";
+ transaction.data = kFullRangeData;
RangeTransactionServer handler;
scoped_ptr<Context> c(new Context);
@@ -6662,8 +6903,7 @@
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = EXTRA_HEADER;
- 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 ";
+ transaction.data = kFullRangeData;
scoped_ptr<net::HttpTransaction> trans;
ASSERT_EQ(net::OK,
diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc
index 247d76b..565623b8 100644
--- a/net/http/partial_data.cc
+++ b/net/http/partial_data.cc
@@ -103,7 +103,12 @@
// -----------------------------------------------------------------------------
PartialData::PartialData()
- : range_present_(false),
+ : current_range_start_(0),
+ current_range_end_(0),
+ cached_start_(0),
+ resource_size_(0),
+ cached_min_len_(0),
+ range_present_(false),
final_range_(false),
sparse_entry_(true),
truncated_(false),
@@ -130,7 +135,6 @@
if (!byte_range_.IsValid())
return false;
- resource_size_ = 0;
current_range_start_ = byte_range_.first_byte_position();
DVLOG(1) << "Range start: " << current_range_start_ << " end: " <<
@@ -222,19 +226,20 @@
if (current_range_start_ == cached_start_) {
// The data lives in the cache.
range_present_ = true;
+ current_range_end_ = cached_start_ + cached_min_len_ - 1;
if (len == cached_min_len_)
final_range_ = true;
headers->SetHeader(
HttpRequestHeaders::kRange,
- net::HttpByteRange::Bounded(
- current_range_start_,
- cached_start_ + cached_min_len_ - 1).GetHeaderValue());
+ HttpByteRange::Bounded(current_range_start_, current_range_end_)
+ .GetHeaderValue());
} else {
// This range is not in the cache.
+ current_range_end_ = cached_start_ - 1;
headers->SetHeader(
HttpRequestHeaders::kRange,
- net::HttpByteRange::Bounded(
- current_range_start_, cached_start_ - 1).GetHeaderValue());
+ HttpByteRange::Bounded(current_range_start_, current_range_end_)
+ .GetHeaderValue());
}
}
@@ -371,7 +376,21 @@
if (start != current_range_start_)
return false;
- if (byte_range_.IsValid() && end > byte_range_.last_byte_position())
+ if (!current_range_end_) {
+ // There is nothing in the cache.
+ DCHECK(byte_range_.HasLastBytePosition());
+ current_range_end_ = byte_range_.last_byte_position();
+ if (current_range_end_ >= resource_size_) {
+ // We didn't know the real file size, and the server is saying that the
+ // requested range goes beyond the size. Fix it.
+ current_range_end_ = end;
+ byte_range_.set_last_byte_position(end);
+ }
+ }
+
+ // If we received a range, but it's not exactly the range we asked for, avoid
+ // trouble and signal an error.
+ if (end != current_range_end_)
return false;
return true;
diff --git a/net/http/partial_data.h b/net/http/partial_data.h
index 45bda39..ea98ff0 100644
--- a/net/http/partial_data.h
+++ b/net/http/partial_data.h
@@ -123,6 +123,7 @@
void GetAvailableRangeCompleted(int result, int64 start);
int64 current_range_start_;
+ int64 current_range_end_;
int64 cached_start_;
int64 resource_size_;
int cached_min_len_;