summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-18 00:53:41 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-18 00:53:41 +0000
commite5dad137bfa58430440138fbd76699d176fabc74 (patch)
tree2153c280bd7b6978b1c50456f415e5ee29cf8884
parent28b6b9a8ca66f94390e78214c2ad7acfa11f6b78 (diff)
downloadchromium_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.cc68
-rw-r--r--net/http/http_cache_unittest.cc233
-rw-r--r--net/http/partial_data.cc70
-rw-r--r--net/http/partial_data.h9
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);
};