summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/http/http_cache.cc106
-rw-r--r--net/http/http_cache_unittest.cc192
-rw-r--r--net/http/http_response_headers.cc9
-rw-r--r--net/http/http_response_headers.h4
-rw-r--r--net/http/http_response_headers_unittest.cc55
-rw-r--r--net/http/partial_data.cc53
-rw-r--r--net/http/partial_data.h3
7 files changed, 374 insertions, 48 deletions
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 5035fb9..b7707d1 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -309,6 +309,9 @@ class HttpCache::Transaction
// copy is valid). Returns true if able to make the request conditional.
bool ConditionalizeRequest();
+ // Makes sure that a 206 response is expected. Returns a network error code.
+ bool ValidatePartialResponse(const HttpResponseHeaders* headers);
+
// Reads data from the network.
int ReadFromNetwork(IOBuffer* data, int data_len);
@@ -335,6 +338,10 @@ class HttpCache::Transaction
// Called when we are done writing to the cache entry.
void DoneWritingToEntry(bool success);
+ // Deletes the current partial cache entry (sparse), and optionally removes
+ // the control object (partial_).
+ void DoomPartialEntry(bool delete_object);
+
// Performs the needed work after receiving data from the network.
int DoNetworkReadCompleted(int result);
@@ -798,6 +805,7 @@ void HttpCache::Transaction::SetRequest(const HttpRequestInfo* request) {
} else {
// The range is invalid or we cannot handle it properly.
effective_load_flags_ |= LOAD_DISABLE_CACHE;
+ partial_.reset(NULL);
}
}
@@ -883,15 +891,23 @@ int HttpCache::Transaction::BeginPartialCacheValidation() {
return BeginCacheValidation();
#endif
- if (!partial_.get()) {
+ bool byte_range_requested = partial_.get() != NULL;
+ if (!byte_range_requested) {
// The request is not for a range, but we have stored just ranges.
- // TODO(rvargas): Add support for this case.
- NOTREACHED();
+ partial_.reset(new PartialData());
+ if (!custom_request_.get()) {
+ custom_request_.reset(new HttpRequestInfo(*request_));
+ request_ = custom_request_.get();
+ DCHECK(custom_request_->extra_headers.empty());
+ }
}
- if (!partial_->UpdateFromStoredHeaders(response_.headers)) {
- // TODO(rvargas): Handle this error.
- NOTREACHED();
+ if (!partial_->UpdateFromStoredHeaders(response_.headers,
+ entry_->disk_entry)) {
+ // The stored data cannot be used. Get rid of it and restart this request.
+ DoomPartialEntry(!byte_range_requested);
+ mode_ = WRITE;
+ return AddToEntry();
}
return ContinuePartialCacheValidation();
@@ -899,8 +915,6 @@ int HttpCache::Transaction::BeginPartialCacheValidation() {
int HttpCache::Transaction::ContinuePartialCacheValidation() {
DCHECK(mode_ == READ_WRITE);
- // TODO(rvargas): Avoid re-validation of each cached piece.
-
int rv = partial_->PrepareCacheValidation(entry_->disk_entry,
&custom_request_->extra_headers);
@@ -914,6 +928,15 @@ int HttpCache::Transaction::ContinuePartialCacheValidation() {
return HandleResult(rv);
}
+ if (reading_ && partial_->IsCurrentRangeCached()) {
+ rv = ReadFromEntry(read_buf_, read_buf_len_);
+
+ // We are supposed to hanlde errors here.
+ if (rv < 0 && rv != ERR_IO_PENDING)
+ HandleResult(rv);
+ return rv;
+ }
+
return BeginCacheValidation();
}
@@ -1080,6 +1103,50 @@ bool HttpCache::Transaction::ConditionalizeRequest() {
return true;
}
+bool HttpCache::Transaction::ValidatePartialResponse(
+ const HttpResponseHeaders* headers) {
+#ifdef ENABLE_RANGE_SUPPORT
+ bool partial_content = headers->response_code() == 206;
+#else
+ bool partial_content = false;
+#endif
+
+ 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)
+ failure = true;
+
+ if (!reading_ && failure) {
+ // We are expecting 206 or 304 because we asked for a range. Given that
+ // the server is refusing the request we'll remove the sparse entry.
+ DoomPartialEntry(true);
+ mode_ = NONE;
+ return false;
+ }
+ }
+
+ if (!failure && partial_.get() && partial_->ResponseHeadersOK(headers))
+ return true;
+
+ // 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
+ // response from the server (it's not changing its mind midway, right?).
+ if (mode_ & WRITE) {
+ DoneWritingToEntry(mode_ != WRITE);
+ } else if (mode_ & READ && entry_) {
+ cache_->DoneReadingFromEntry(entry_, this);
+ }
+
+ entry_ = NULL;
+ mode_ = NONE;
+ return false;
+}
+
int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) {
int rv = network_trans_->Read(data, data_len, &network_read_callback_);
read_buf_ = data;
@@ -1197,6 +1264,14 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) {
mode_ = NONE; // switch to 'pass through' mode
}
+void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
+ cache_->DoneWithEntry(entry_, this);
+ cache_->DoomEntry(cache_key_);
+ entry_ = NULL;
+ if (delete_object)
+ partial_.reset(NULL);
+}
+
void HttpCache::Transaction::OnNetworkInfoAvailable(int result) {
DCHECK(result != ERR_IO_PENDING);
@@ -1211,19 +1286,8 @@ void HttpCache::Transaction::OnNetworkInfoAvailable(int result) {
new_response->headers->response_code() == 407) {
auth_response_ = *new_response;
} else {
-#ifdef ENABLE_RANGE_SUPPORT
- bool partial_content = new_response->headers->response_code() == 206;
-#else
- bool partial_content = false;
-#endif
- // TODO(rvargas): Validate partial_content vs partial_ and mode_
- if (partial_content) {
- DCHECK(partial_.get());
- if (!partial_->ResponseHeadersOK(new_response->headers)) {
- // TODO(rvargas): Handle this error.
- NOTREACHED();
- }
- }
+ bool partial_content = ValidatePartialResponse(new_response->headers);
+
// Are we expecting a response to a conditional query?
if (mode_ == READ_WRITE || mode_ == UPDATE) {
if (new_response->headers->response_code() == 304 || partial_content) {
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 3f9e667..2efd751 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -485,8 +485,10 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request,
std::string* response_status,
std::string* response_headers,
std::string* response_data) {
- if (request->extra_headers.empty())
+ if (request->extra_headers.empty()) {
+ response_status->assign("HTTP/1.1 416 Requested Range Not Satisfiable");
return;
+ }
std::vector<net::HttpByteRange> ranges;
if (!net::HttpUtil::ParseRanges(request->extra_headers, &ranges) ||
@@ -505,9 +507,20 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request,
response_headers->append(content_range);
if (request->extra_headers.find("If-None-Match") == std::string::npos) {
- EXPECT_EQ(9, end - start);
- std::string data = StringPrintf("rg: %02d-%02d ", start, end);
+ EXPECT_EQ(9, (end - start) % 10);
+ std::string data;
+ for (int block_start = start; block_start < end; block_start += 10)
+ StringAppendF(&data, "rg: %02d-%02d ", block_start, block_start + 9);
*response_data = data;
+
+ if (end - start != 9) {
+ // We also have to fix content-length.
+ int len = end - start + 1;
+ EXPECT_EQ(0, len % 10);
+ std::string content_length = StringPrintf("Content-Length: %d\n", len);
+ response_headers->replace(response_headers->find("Content-Length:"),
+ content_length.size(), content_length);
+ }
} else {
response_status->assign("HTTP/1.1 304 Not Modified");
response_data->clear();
@@ -1634,13 +1647,14 @@ TEST(HttpCache, RangeGET_SkipsCache) {
TEST(HttpCache, GET_Crazy206) {
MockHttpCache cache;
- AddMockTransaction(&kRangeGET_TransactionOK);
// Test that receiving 206 for a regular request is handled correctly.
// Write to the cache.
MockTransaction transaction(kRangeGET_TransactionOK);
+ AddMockTransaction(&transaction);
transaction.request_headers = "";
+ transaction.handler = NULL;
RunTransactionTest(cache.http_cache(), transaction);
EXPECT_EQ(1, cache.network_layer()->transaction_count());
@@ -1653,7 +1667,7 @@ TEST(HttpCache, GET_Crazy206) {
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);
+ RemoveMockTransaction(&transaction);
}
TEST(HttpCache, DISABLED_RangeGET_OK) {
@@ -1706,7 +1720,7 @@ TEST(HttpCache, DISABLED_RangeGET_OK) {
RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
EXPECT_TRUE(Verify206Response(headers, 20, 59));
- EXPECT_EQ(6, cache.network_layer()->transaction_count());
+ EXPECT_EQ(5, cache.network_layer()->transaction_count());
EXPECT_EQ(3, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
@@ -1742,7 +1756,7 @@ TEST(HttpCache, DISABLED_UnknownRangeGET_1) {
RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
EXPECT_TRUE(Verify206Response(headers, 60, 79));
- EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(2, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
@@ -1751,15 +1765,19 @@ TEST(HttpCache, DISABLED_UnknownRangeGET_1) {
TEST(HttpCache, DISABLED_UnknownRangeGET_2) {
MockHttpCache cache;
- AddMockTransaction(&kRangeGET_TransactionOK);
// 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;
- // Write to the cache (70-79).
MockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.test_mode = TEST_MODE_SYNC_CACHE_START |
+ TEST_MODE_SYNC_CACHE_READ;
+ AddMockTransaction(&transaction);
+
+ // Write to the cache (70-79).
transaction.request_headers = "Range: bytes = 70-\r\n";
transaction.data = "rg: 70-79 ";
RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
@@ -1778,6 +1796,38 @@ TEST(HttpCache, DISABLED_UnknownRangeGET_2) {
RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
EXPECT_TRUE(Verify206Response(headers, 60, 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());
+
+ RemoveMockTransaction(&transaction);
+}
+
+TEST(HttpCache, DISABLED_GET_Previous206) {
+ MockHttpCache cache;
+ AddMockTransaction(&kRangeGET_TransactionOK);
+
+ // Test that we can handle non-range requests when we have cached a range.
+
+ 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());
+
+ // Write and read from the cache (0-79), when not asked for a range.
+ MockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "";
+ 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 ";
+ 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());
@@ -1785,6 +1835,130 @@ TEST(HttpCache, DISABLED_UnknownRangeGET_2) {
RemoveMockTransaction(&kRangeGET_TransactionOK);
}
+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,
+ &entry));
+
+ std::string raw_headers(kRangeGET_TransactionOK.status);
+ raw_headers.append("\n");
+ raw_headers.append(kRangeGET_TransactionOK.response_headers);
+ raw_headers = net::HttpUtil::AssembleRawHeaders(raw_headers.data(),
+ raw_headers.size());
+
+ net::HttpResponseInfo response;
+ response.headers = new net::HttpResponseHeaders(raw_headers);
+ net::HttpCache::WriteResponseInfo(entry, &response, true);
+
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(500));
+ int len = static_cast<int>(base::strlcpy(buf->data(),
+ kRangeGET_TransactionOK.data, 500));
+ EXPECT_EQ(len, entry->WriteData(1, 0, buf, len, NULL, true));
+ entry->Close();
+
+ // Now see that we don't use the stored entry.
+ std::string headers;
+ RunTransactionTestWithResponse(cache.http_cache(), kSimpleGET_Transaction,
+ &headers);
+
+ // We are expecting a 200.
+ std::string expected_headers(kSimpleGET_Transaction.status);
+ expected_headers.append("\n");
+ expected_headers.append(kSimpleGET_Transaction.response_headers);
+ EXPECT_EQ(expected_headers, headers);
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+TEST(HttpCache, DISABLED_GET_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,
+ &entry));
+
+ std::string raw_headers(kRangeGET_TransactionOK.status);
+ raw_headers.append("\n");
+ raw_headers.append(kRangeGET_TransactionOK.response_headers);
+ raw_headers = net::HttpUtil::AssembleRawHeaders(raw_headers.data(),
+ raw_headers.size());
+
+ net::HttpResponseInfo response;
+ response.headers = new net::HttpResponseHeaders(raw_headers);
+ net::HttpCache::WriteResponseInfo(entry, &response, true);
+
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(500));
+ int len = static_cast<int>(base::strlcpy(buf->data(),
+ kRangeGET_TransactionOK.data, 500));
+ EXPECT_EQ(len, entry->WriteData(1, 0, buf, len, NULL, true));
+ entry->Close();
+
+ // Now see that we don't use the stored entry.
+ std::string headers;
+ RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK,
+ &headers);
+
+ // We are expecting a 206.
+ EXPECT_TRUE(Verify206Response(headers, 40, 49));
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+
+ RemoveMockTransaction(&kRangeGET_TransactionOK);
+}
+
+TEST(HttpCache, DISABLED_RangeRequestResultsIn200) {
+ MockHttpCache cache;
+ AddMockTransaction(&kRangeGET_TransactionOK);
+
+ // Test that we can handle a 200 response when dealing with sparse entries.
+
+ std::string headers;
+
+ // Write to the cache (70-79).
+ MockTransaction transaction(kRangeGET_TransactionOK);
+ transaction.request_headers = "Range: bytes = -10\r\n";
+ transaction.data = "rg: 70-79 ";
+ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
+
+ EXPECT_TRUE(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());
+
+ // Now we'll issue a request that results in a plain 200 response, but to
+ // the to the same URL that we used to store sparse data, and making sure
+ // that we ask for a range.
+ RemoveMockTransaction(&kRangeGET_TransactionOK);
+ MockTransaction transaction2(kSimpleGET_Transaction);
+ transaction2.url = kRangeGET_TransactionOK.url;
+ transaction2.request_headers = kRangeGET_TransactionOK.request_headers;
+ AddMockTransaction(&transaction2);
+
+ RunTransactionTestWithResponse(cache.http_cache(), transaction2, &headers);
+
+ std::string expected_headers(kSimpleGET_Transaction.status);
+ expected_headers.append("\n");
+ expected_headers.append(kSimpleGET_Transaction.response_headers);
+ EXPECT_EQ(expected_headers, headers);
+ 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(&transaction2);
+}
+
TEST(HttpCache, SyncRead) {
MockHttpCache cache;
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index f86eff8..9cbd72f 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -256,6 +256,15 @@ void HttpResponseHeaders::AddHeader(const std::string& header) {
Parse(new_raw_headers);
}
+void HttpResponseHeaders::ReplaceStatusLine(const std::string& new_status) {
+ // Copy up to the null byte. This just copies the status line.
+ std::string new_raw_headers(new_status);
+ new_raw_headers.push_back('\0');
+
+ HeaderSet empty_to_remove;
+ MergeWithHeaders(new_raw_headers, empty_to_remove);
+}
+
void HttpResponseHeaders::Parse(const std::string& raw_input) {
raw_headers_.reserve(raw_input.size());
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index 0552904..547370d 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -71,6 +71,10 @@ class HttpResponseHeaders :
// end of the list.
void AddHeader(const std::string& header);
+ // Replaces the current status line with the provided one (|new_status| should
+ // not have any EOL).
+ void ReplaceStatusLine(const std::string& new_status);
+
// Creates a normalized header string. The output will be formatted exactly
// like so:
// HTTP/<version> <status_code> <status_text>\n
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index ad03107..9f0cfde 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -1504,3 +1504,58 @@ TEST(HttpResponseHeadersTest, RemoveHeader) {
EXPECT_EQ(string(tests[i].expected_headers), resulting_headers);
}
}
+
+TEST(HttpResponseHeadersTest, ReplaceStatus) {
+ const struct {
+ const char* orig_headers;
+ const char* new_status;
+ const char* expected_headers;
+ } tests[] = {
+ { "HTTP/1.1 206 Partial Content\n"
+ "connection: keep-alive\n"
+ "Cache-control: max-age=10000\n"
+ "Content-Length: 450\n",
+
+ "HTTP/1.1 200 OK",
+
+ "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Cache-control: max-age=10000\n"
+ "Content-Length: 450\n"
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n",
+
+ "HTTP/1.1 304 Not Modified",
+
+ "HTTP/1.1 304 Not Modified\n"
+ "connection: keep-alive\n"
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive \n"
+ "Content-Length : 450 \n"
+ "Cache-control: max-age=10000\n",
+
+ "HTTP/1//1 304 Not Modified",
+
+ "HTTP/1.0 304 Not Modified\n"
+ "connection: keep-alive\n"
+ "Content-Length: 450\n"
+ "Cache-control: max-age=10000\n"
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ string orig_headers(tests[i].orig_headers);
+ HeadersToRaw(&orig_headers);
+ scoped_refptr<HttpResponseHeaders> parsed =
+ new HttpResponseHeaders(orig_headers);
+
+ string name(tests[i].new_status);
+ parsed->ReplaceStatusLine(name);
+
+ string resulting_headers;
+ parsed->GetNormalizedHeaders(&resulting_headers);
+ EXPECT_EQ(string(tests[i].expected_headers), resulting_headers);
+ }
+}
diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc
index 8d56966..a4d5976 100644
--- a/net/http/partial_data.cc
+++ b/net/http/partial_data.cc
@@ -53,7 +53,7 @@ int PartialData::PrepareCacheValidation(disk_cache::Entry* entry,
// Scan the disk cache for the first cached portion within this range.
int64 range_len = byte_range_.HasLastBytePosition() ?
- byte_range_.last_byte_position() - current_range_start_ + 1: kint32max;
+ byte_range_.last_byte_position() - current_range_start_ + 1 : kint32max;
if (range_len > kint32max)
range_len = kint32max;
int len = static_cast<int32>(range_len);
@@ -100,20 +100,32 @@ bool PartialData::IsLastRange() const {
return final_range_;
}
-bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers) {
+bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
+ disk_cache::Entry* entry) {
std::string length_value;
resource_size_ = 0;
if (!headers->GetNormalizedHeader(kLengthHeader, &length_value))
return false; // We must have stored the resource length.
- if (!StringToInt64(length_value, &resource_size_))
+ if (!StringToInt64(length_value, &resource_size_) || !resource_size_)
return false;
- if (resource_size_ && !byte_range_.ComputeBounds(resource_size_))
- return false;
+ if (byte_range_.IsValid()) {
+ if (!byte_range_.ComputeBounds(resource_size_))
+ return false;
+
+ if (current_range_start_ < 0)
+ current_range_start_ = byte_range_.first_byte_position();
+ } else {
+ // This is not a range request but we have partial data stored.
+ current_range_start_ = 0;
+ byte_range_.set_last_byte_position(resource_size_ - 1);
+ }
- if (current_range_start_ < 0)
- current_range_start_ = byte_range_.first_byte_position();
+ // 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 current_range_start_ >= 0;
}
@@ -141,7 +153,7 @@ bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
if (start != current_range_start_)
return false;
- if (end > byte_range_.last_byte_position())
+ if (byte_range_.IsValid() && end > byte_range_.last_byte_position())
return false;
return true;
@@ -154,15 +166,23 @@ void PartialData::FixResponseHeaders(HttpResponseHeaders* headers) {
headers->RemoveHeader(kLengthHeader);
headers->RemoveHeader(kRangeHeader);
- DCHECK(byte_range_.HasFirstBytePosition());
- DCHECK(byte_range_.HasLastBytePosition());
- headers->AddHeader(StringPrintf("%s: bytes %lld-%lld/%lld", kRangeHeader,
- byte_range_.first_byte_position(),
- byte_range_.last_byte_position(),
- resource_size_));
+ int64 range_len;
+ if (byte_range_.IsValid()) {
+ DCHECK(byte_range_.HasFirstBytePosition());
+ DCHECK(byte_range_.HasLastBytePosition());
+ headers->AddHeader(StringPrintf("%s: bytes %lld-%lld/%lld", kRangeHeader,
+ byte_range_.first_byte_position(),
+ byte_range_.last_byte_position(),
+ resource_size_));
+ range_len = byte_range_.last_byte_position() -
+ byte_range_.first_byte_position() + 1;
+ } else {
+ // TODO(rvargas): Is it safe to change the protocol version?
+ headers->ReplaceStatusLine("HTTP/1.1 200 OK");
+ DCHECK_NE(resource_size_, 0);
+ range_len = resource_size_;
+ }
- int64 range_len = byte_range_.last_byte_position() -
- byte_range_.first_byte_position() + 1;
headers->AddHeader(StringPrintf("%s: %lld", kLengthHeader, range_len));
}
@@ -214,5 +234,4 @@ void PartialData::AddRangeHeader(int64 start, int64 end, std::string* headers) {
my_end.c_str()));
}
-
} // namespace net
diff --git a/net/http/partial_data.h b/net/http/partial_data.h
index 8c3471d..ade720d 100644
--- a/net/http/partial_data.h
+++ b/net/http/partial_data.h
@@ -62,7 +62,8 @@ class PartialData {
// Extracts info from headers already stored in the cache. Returns false if
// there is any problem with the headers or the requested range.
- bool UpdateFromStoredHeaders(const HttpResponseHeaders* headers);
+ bool UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
+ disk_cache::Entry* entry);
// Returns true if the response headers match what we expect, false otherwise.
bool ResponseHeadersOK(const HttpResponseHeaders* headers);