Commit 03c9f1f8 authored by Maks Orlovich's avatar Maks Orlovich Committed by Commit Bot

HttpCache: don't mess up status on range requests getting a non-200/206

We would sometimes do it to a cached 301, and then get really confused trying to read
a body that wasn't there. 200 and 206 responses are the only in-caches ones (wire could
also have a 304) which could possibly result in a 206 to our client, so others should just
have range handling dropped; we do that already for things gotten on the wire but not
from cache.

Bug: 1015829
Change-Id: I6ba127aec8e88a7cbf72d7a87b94e5e7f10a3973
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899890Reviewed-by: default avatarShivani Sharma <shivanisha@chromium.org>
Commit-Queue: Maksim Orlovich <morlovich@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714995}
parent 8856b5f4
...@@ -2068,8 +2068,14 @@ int HttpCache::Transaction::DoPartialHeadersReceived() { ...@@ -2068,8 +2068,14 @@ int HttpCache::Transaction::DoPartialHeadersReceived() {
if (partial_ && mode_ != NONE && !reading_) { if (partial_ && mode_ != NONE && !reading_) {
// We are about to return the headers for a byte-range request to the user, // We are about to return the headers for a byte-range request to the user,
// so let's fix them. // so let's fix them. This only makes sense if the response is something
partial_->FixResponseHeaders(response_.headers.get(), true); // that can be turned into a 206, of course.
if (response_.headers->response_code() == 200 ||
response_.headers->response_code() == 206) {
partial_->FixResponseHeaders(response_.headers.get(), true);
} else {
partial_.reset();
}
} }
TransitionToState(STATE_FINISH_HEADERS); TransitionToState(STATE_FINISH_HEADERS);
return OK; return OK;
......
...@@ -391,12 +391,14 @@ class RangeTransactionServer { ...@@ -391,12 +391,14 @@ class RangeTransactionServer {
not_modified_ = false; not_modified_ = false;
modified_ = false; modified_ = false;
bad_200_ = false; bad_200_ = false;
redirect_ = false;
length_ = 80; length_ = 80;
} }
~RangeTransactionServer() { ~RangeTransactionServer() {
not_modified_ = false; not_modified_ = false;
modified_ = false; modified_ = false;
bad_200_ = false; bad_200_ = false;
redirect_ = false;
length_ = 80; length_ = 80;
} }
...@@ -412,6 +414,9 @@ class RangeTransactionServer { ...@@ -412,6 +414,9 @@ class RangeTransactionServer {
// Sets how long the resource is. (Default is 80) // Sets how long the resource is. (Default is 80)
void set_length(int64_t length) { length_ = length; } void set_length(int64_t length) { length_ = length; }
// Sets whether to return a 301 instead of normal return.
void set_redirect(bool redirect) { redirect_ = redirect; }
// Other than regular range related behavior (and the flags mentioned above), // Other than regular range related behavior (and the flags mentioned above),
// the server reacts to requests headers like so: // the server reacts to requests headers like so:
// X-Require-Mock-Auth -> return 401. // X-Require-Mock-Auth -> return 401.
...@@ -428,12 +433,14 @@ class RangeTransactionServer { ...@@ -428,12 +433,14 @@ class RangeTransactionServer {
static bool not_modified_; static bool not_modified_;
static bool modified_; static bool modified_;
static bool bad_200_; static bool bad_200_;
static bool redirect_;
static int64_t length_; static int64_t length_;
DISALLOW_COPY_AND_ASSIGN(RangeTransactionServer); DISALLOW_COPY_AND_ASSIGN(RangeTransactionServer);
}; };
bool RangeTransactionServer::not_modified_ = false; bool RangeTransactionServer::not_modified_ = false;
bool RangeTransactionServer::modified_ = false; bool RangeTransactionServer::modified_ = false;
bool RangeTransactionServer::bad_200_ = false; bool RangeTransactionServer::bad_200_ = false;
bool RangeTransactionServer::redirect_ = false;
int64_t RangeTransactionServer::length_ = 80; int64_t RangeTransactionServer::length_ = 80;
// A dummy extra header that must be preserved on a given request. // A dummy extra header that must be preserved on a given request.
...@@ -472,6 +479,13 @@ void RangeTransactionServer::RangeHandler(const HttpRequestInfo* request, ...@@ -472,6 +479,13 @@ void RangeTransactionServer::RangeHandler(const HttpRequestInfo* request,
return; return;
} }
if (redirect_) {
response_status->assign("HTTP/1.1 301 Moved Permanently");
response_headers->assign("Location: /elsewhere\nContent-Length: 5");
response_data->assign("12345");
return;
}
if (not_modified_) { if (not_modified_) {
response_status->assign("HTTP/1.1 304 Not Modified"); response_status->assign("HTTP/1.1 304 Not Modified");
response_data->clear(); response_data->clear();
...@@ -2785,6 +2799,77 @@ TEST_F(HttpCacheTest, RangeGET_ParallelValidationRestartDoneHeaders) { ...@@ -2785,6 +2799,77 @@ TEST_F(HttpCacheTest, RangeGET_ParallelValidationRestartDoneHeaders) {
EXPECT_EQ(1, cache.disk_cache()->create_count()); EXPECT_EQ(1, cache.disk_cache()->create_count());
} }
// A test of doing a range request to a cached 301 response
TEST_F(HttpCacheTest, RangeGET_CachedRedirect) {
RangeTransactionServer handler;
handler.set_redirect(true);
MockHttpCache cache;
ScopedMockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = "Range: bytes = 0-\r\n" EXTRA_HEADER;
transaction.status = "HTTP/1.1 301 Moved Permanently";
transaction.response_headers = "Location: /elsewhere\nContent-Length:5";
transaction.data = "12345";
MockHttpRequest request(transaction);
TestCompletionCallback callback;
// Write to the cache.
{
std::unique_ptr<HttpTransaction> trans;
ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
ASSERT_THAT(rv, IsOk());
const HttpResponseInfo* info = trans->GetResponseInfo();
ASSERT_TRUE(info);
EXPECT_EQ(info->headers->response_code(), 301);
std::string location;
info->headers->EnumerateHeader(nullptr, "Location", &location);
EXPECT_EQ(location, "/elsewhere");
ReadAndVerifyTransaction(trans.get(), 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());
// Active entries in the cache are not retired synchronously. Make
// sure the next run hits the MockHttpCache and open_count is
// correct.
base::RunLoop().RunUntilIdle();
// Read from the cache.
{
std::unique_ptr<HttpTransaction> trans;
ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
ASSERT_THAT(rv, IsOk());
const HttpResponseInfo* info = trans->GetResponseInfo();
ASSERT_TRUE(info);
EXPECT_EQ(info->headers->response_code(), 301);
std::string location;
info->headers->EnumerateHeader(nullptr, "Location", &location);
EXPECT_EQ(location, "/elsewhere");
trans->DoneReading();
}
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
}
// A transaction that fails to validate an entry, while attempting to write // A transaction that fails to validate an entry, while attempting to write
// the response, should still get data to its consumer even if the attempt to // the response, should still get data to its consumer even if the attempt to
// create a new entry fails. // create a new entry fails.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment