blob: f5e538cf44c5e932cccbee563d2a12111226e551 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/loader/throttling_resource_handler.h"
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/test/scoped_task_environment.h"
#include "content/browser/loader/mock_resource_loader.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/browser/loader/test_resource_handler.h"
#include "content/public/browser/resource_throttle.h"
#include "net/base/request_priority.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "services/network/public/cpp/resource_response.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
namespace {
const char kInitialUrl[] = "http://initial/";
const char kRedirectUrl[] = "http://redirect/";
class TestResourceThrottle : public ResourceThrottle {
public:
explicit TestResourceThrottle(TestResourceThrottle* previous_throttle) {
if (previous_throttle) {
DCHECK(!previous_throttle->next_throttle_);
previous_throttle_ = previous_throttle;
previous_throttle_->next_throttle_ = this;
}
}
~TestResourceThrottle() override {}
// Sets the throttle after this one, to enable checks that they're called in
// the expected order.
void SetNextThrottle(TestResourceThrottle* throttle) {
DCHECK(!next_throttle_);
DCHECK(!throttle->previous_throttle_);
next_throttle_ = throttle;
throttle->previous_throttle_ = this;
}
// ResourceThrottle implemenation:
void WillStartRequest(bool* defer) override {
EXPECT_EQ(0, will_start_request_called_);
EXPECT_EQ(0, will_redirect_request_called_);
EXPECT_EQ(0, will_process_response_called_);
if (previous_throttle_) {
EXPECT_EQ(1, previous_throttle_->will_start_request_called_);
EXPECT_EQ(0, previous_throttle_->will_redirect_request_called_);
EXPECT_EQ(0, previous_throttle_->will_process_response_called_);
}
if (next_throttle_) {
EXPECT_EQ(0, next_throttle_->will_start_request_called_);
EXPECT_EQ(0, next_throttle_->will_redirect_request_called_);
EXPECT_EQ(0, next_throttle_->will_process_response_called_);
}
++will_start_request_called_;
*defer = defer_on_will_start_request_;
if (cancel_on_will_start_request_)
CancelWithError(net::ERR_UNEXPECTED);
}
void WillRedirectRequest(const net::RedirectInfo& redirect_info,
bool* defer) override {
EXPECT_EQ(GURL(kRedirectUrl), redirect_info.new_url);
EXPECT_EQ(1, will_start_request_called_);
// None of these tests use multiple redirects.
EXPECT_EQ(0, will_redirect_request_called_);
EXPECT_EQ(0, will_process_response_called_);
if (previous_throttle_) {
EXPECT_EQ(1, previous_throttle_->will_start_request_called_);
EXPECT_EQ(1, previous_throttle_->will_redirect_request_called_);
EXPECT_EQ(0, previous_throttle_->will_process_response_called_);
}
if (next_throttle_) {
EXPECT_EQ(1, next_throttle_->will_start_request_called_);
EXPECT_EQ(0, next_throttle_->will_redirect_request_called_);
EXPECT_EQ(0, next_throttle_->will_process_response_called_);
}
++will_redirect_request_called_;
*defer = defer_on_will_redirect_request_;
if (cancel_on_will_redirect_request_)
CancelWithError(net::ERR_UNEXPECTED);
}
void WillProcessResponse(bool* defer) override {
EXPECT_EQ(0, will_process_response_called_);
if (previous_throttle_)
EXPECT_EQ(1, previous_throttle_->will_process_response_called_);
if (next_throttle_)
EXPECT_EQ(0, next_throttle_->will_process_response_called_);
++will_process_response_called_;
*defer = defer_on_will_process_response_;
if (cancel_on_will_process_response_)
CancelWithError(net::ERR_UNEXPECTED);
}
const char* GetNameForLogging() const override { return "Hank"; }
int will_start_request_called() const { return will_start_request_called_; }
int will_redirect_request_called() const {
return will_redirect_request_called_;
}
int will_process_response_called() const {
return will_process_response_called_;
}
void set_defer_on_will_start_request(bool defer_on_will_start_request) {
defer_on_will_start_request_ = defer_on_will_start_request;
}
void set_defer_on_will_redirect_request(bool defer_on_will_redirect_request) {
defer_on_will_redirect_request_ = defer_on_will_redirect_request;
}
void set_defer_on_will_process_response(bool defer_on_will_process_response) {
defer_on_will_process_response_ = defer_on_will_process_response;
}
void set_cancel_on_will_start_request(bool cancel_on_will_start_request) {
cancel_on_will_start_request_ = cancel_on_will_start_request;
}
void set_cancel_on_will_redirect_request(
bool cancel_on_will_redirect_request) {
cancel_on_will_redirect_request_ = cancel_on_will_redirect_request;
}
void set_cancel_on_will_process_response(
bool cancel_on_will_process_response) {
cancel_on_will_process_response_ = cancel_on_will_process_response;
}
using ResourceThrottle::Resume;
using ResourceThrottle::CancelWithError;
private:
int will_start_request_called_ = 0;
int will_redirect_request_called_ = 0;
int will_process_response_called_ = 0;
bool defer_on_will_start_request_ = false;
bool defer_on_will_redirect_request_ = false;
bool defer_on_will_process_response_ = false;
bool cancel_on_will_start_request_ = false;
bool cancel_on_will_redirect_request_ = false;
bool cancel_on_will_process_response_ = false;
TestResourceThrottle* previous_throttle_ = nullptr;
TestResourceThrottle* next_throttle_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TestResourceThrottle);
};
class ThrottlingResourceHandlerTest : public testing::Test {
public:
ThrottlingResourceHandlerTest()
: never_started_url_request_(
request_context_.CreateRequest(GURL(kInitialUrl),
net::DEFAULT_PRIORITY,
&never_started_url_request_delegate_,
TRAFFIC_ANNOTATION_FOR_TESTS)),
throttle1_(new TestResourceThrottle(nullptr)),
throttle2_(new TestResourceThrottle(throttle1_)),
test_handler_(new TestResourceHandler()) {
std::vector<std::unique_ptr<ResourceThrottle>> throttles;
throttles.push_back(base::WrapUnique(throttle1_));
throttles.push_back(base::WrapUnique(throttle2_));
throttling_handler_.reset(new ThrottlingResourceHandler(
base::WrapUnique(test_handler_), never_started_url_request_.get(),
std::move(throttles)));
mock_loader_.reset(new MockResourceLoader(throttling_handler_.get()));
// Basic initial state sanity checks.
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
}
// Finish the request with a 0-byte read and success. Reads are not passed
// to ResourceThrottles, so are uninteresting for the purposes of these tests.
void FinishRequestSuccessfully() {
EXPECT_EQ(0, test_handler_->on_will_read_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead());
EXPECT_EQ(1, test_handler_->on_will_read_called());
EXPECT_EQ(0, test_handler_->on_read_completed_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnReadCompleted(nullptr));
EXPECT_EQ(1, test_handler_->on_read_completed_called());
EXPECT_EQ(0, test_handler_->on_response_completed_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::OK)));
EXPECT_EQ(net::OK, mock_loader_->error_code());
EXPECT_EQ(1, test_handler_->on_read_completed_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
protected:
// Needs to be first, so it's destroyed last.
base::test::ScopedTaskEnvironment task_environment_{
base::test::ScopedTaskEnvironment::MainThreadType::IO};
// Machinery to construct a URLRequest that's just used as an argument to
// methods that expect one, and is never actually started.
net::TestURLRequestContext request_context_;
net::TestDelegate never_started_url_request_delegate_;
std::unique_ptr<net::URLRequest> never_started_url_request_;
// Owned by test_handler_;
TestResourceThrottle* throttle1_;
TestResourceThrottle* throttle2_;
// Owned by |throttling_handler_|.
TestResourceHandler* test_handler_;
std::unique_ptr<ThrottlingResourceHandler> throttling_handler_;
std::unique_ptr<MockResourceLoader> mock_loader_;
private:
DISALLOW_COPY_AND_ASSIGN(ThrottlingResourceHandlerTest);
};
TEST_F(ThrottlingResourceHandlerTest, Sync) {
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
ASSERT_EQ(
MockResourceLoader::Status::IDLE,
mock_loader_->OnRequestRedirected(
redirect_info, base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_redirect_request_called());
EXPECT_EQ(1, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseStarted(
base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_request_redirected_called());
EXPECT_EQ(1, test_handler_->on_response_started_called());
EXPECT_EQ(0, test_handler_->on_read_completed_called());
FinishRequestSuccessfully();
}
TEST_F(ThrottlingResourceHandlerTest, Async) {
throttle1_->set_defer_on_will_start_request(true);
throttle1_->set_defer_on_will_redirect_request(true);
throttle1_->set_defer_on_will_process_response(true);
throttle2_->set_defer_on_will_start_request(true);
throttle2_->set_defer_on_will_redirect_request(true);
throttle2_->set_defer_on_will_process_response(true);
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
throttle1_->Resume();
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->status());
throttle2_->Resume();
EXPECT_EQ(1, test_handler_->on_will_start_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
ASSERT_EQ(
MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnRequestRedirected(
redirect_info, base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
throttle1_->Resume();
EXPECT_EQ(1, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->status());
throttle2_->Resume();
EXPECT_EQ(1, test_handler_->on_request_redirected_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
EXPECT_EQ(0, throttle1_->will_process_response_called());
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnResponseStarted(
base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
throttle1_->Resume();
EXPECT_EQ(1, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->status());
throttle2_->Resume();
EXPECT_EQ(1, test_handler_->on_request_redirected_called());
EXPECT_EQ(1, test_handler_->on_response_started_called());
EXPECT_EQ(0, test_handler_->on_read_completed_called());
ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
FinishRequestSuccessfully();
}
// For a given method (WillStartRequest, WillRedirectRequest,
// WillProcessResponse), each of the two throttles can cancel asynchronously or
// synchronously, and the second throttle can cancel synchronously or
// asynchronously after the first throttle completes synchronously or
// asynchronously, for a total of 6 combinations where one of the
// ResourceThrottle cancels in each phase. However:
// 1) Whenever the second throttle cancels asynchronously, it doesn't matter if
// the first one completed synchronously or asynchronously, the state when it
// cancels is the same.
// 2) The second cancelling asynchronously is much like the first one
// cancelling asynchronously, so isn't worth testing individually.
// 3) Similarly, the second cancelling synchronously after the first one
// completes synchronously doesn't really add anything to the first cancelling
// synchronously. The case where the second cancels synchronously after the
// first completes asynchronously is more interesting - the cancellation happens
// in a Resume() call rather in the initial WillFoo call.
// So that leaves 3 interesting test cases for each of the three points
// throttles can cancel.
TEST_F(ThrottlingResourceHandlerTest, FirstThrottleSyncCancelOnWillStart) {
throttle1_->set_cancel_on_will_start_request(true);
ASSERT_EQ(MockResourceLoader::Status::CANCELED,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, FirstThrottleAsyncCancelOnWillStart) {
throttle1_->set_defer_on_will_start_request(true);
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
// The first throttle also defers and then resumes the request, so that this
// cancel happens with Resume() on the top of the callstack, instead of
// OnWillStart(), unlike the test where the first throttle synchronously
// cancels.
TEST_F(ThrottlingResourceHandlerTest, SecondThrottleSyncCancelOnWillStart) {
throttle1_->set_defer_on_will_start_request(true);
throttle2_->set_cancel_on_will_start_request(true);
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
throttle1_->Resume();
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest,
FirstThrottleSyncCancelOnRequestRedirected) {
throttle1_->set_cancel_on_will_redirect_request(true);
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
ASSERT_EQ(
MockResourceLoader::Status::CANCELED,
mock_loader_->OnRequestRedirected(
redirect_info, base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest,
FirstThrottleAsyncCancelOnRequestRedirected) {
throttle1_->set_defer_on_will_redirect_request(true);
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
ASSERT_EQ(
MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnRequestRedirected(
redirect_info, base::MakeRefCounted<network::ResourceResponse>()));
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
// The first throttle also defers and then resumes the request, so that this
// cancel happens with Resume() on the top of the callstack, instead of
// OnRequestRedirected(), unlike the test where the first throttle synchronously
// cancels.
TEST_F(ThrottlingResourceHandlerTest,
SecondThrottleSyncCancelOnRequestRedirected) {
throttle1_->set_defer_on_will_redirect_request(true);
throttle2_->set_cancel_on_will_redirect_request(true);
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
ASSERT_EQ(
MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnRequestRedirected(
redirect_info, base::MakeRefCounted<network::ResourceResponse>()));
throttle1_->Resume();
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(1, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(1, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest,
FirstThrottleSyncCancelOnWillProcessResponse) {
throttle1_->set_cancel_on_will_process_response(true);
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
ASSERT_EQ(MockResourceLoader::Status::CANCELED,
mock_loader_->OnResponseStarted(
base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest,
FirstThrottleAsyncCancelOnWillProcessResponse) {
throttle1_->set_defer_on_will_process_response(true);
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnResponseStarted(
base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
// The first throttle also defers and then resumes the request, so that this
// cancel happens with Resume() on the top of the callstack, instead of
// OnWillProcessResponse(), unlike the test where the first throttle
// synchronously cancels.
TEST_F(ThrottlingResourceHandlerTest,
SecondThrottleSyncCancelOnWillProcessResponse) {
throttle1_->set_defer_on_will_process_response(true);
throttle2_->set_cancel_on_will_process_response(true);
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnResponseStarted(
base::MakeRefCounted<network::ResourceResponse>()));
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
throttle1_->Resume();
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
ASSERT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
ASSERT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(1, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, OutOfBandCancelBeforeWillStart) {
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(0, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, OutOfBandCancelAfterWillStart) {
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, OutOfBandCancelAfterRequestRedirected) {
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
EXPECT_EQ(
MockResourceLoader::Status::IDLE,
mock_loader_->OnRequestRedirected(
redirect_info, base::MakeRefCounted<network::ResourceResponse>()));
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(1, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(1, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, OutOfBandCancelAfterResponseStarted) {
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
net::RedirectInfo redirect_info;
redirect_info.status_code = 301;
redirect_info.new_url = GURL(kRedirectUrl);
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnRequestRedirected(redirect_info,
new network::ResourceResponse()));
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseStarted(
base::MakeRefCounted<network::ResourceResponse>()));
throttle1_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(1, throttle1_->will_redirect_request_called());
EXPECT_EQ(1, throttle1_->will_process_response_called());
EXPECT_EQ(1, throttle2_->will_start_request_called());
EXPECT_EQ(1, throttle2_->will_redirect_request_called());
EXPECT_EQ(1, throttle2_->will_process_response_called());
EXPECT_EQ(1, test_handler_->on_will_start_called());
EXPECT_EQ(1, test_handler_->on_request_redirected_called());
EXPECT_EQ(1, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, OutOfBandCancelAndResumeDuringWillStart) {
throttle1_->set_defer_on_will_start_request(1);
EXPECT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
// |throttle2_| cancels.
throttle2_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// |throttle1_|, blissfully unaware of cancellation, resumes the request.
throttle1_->Resume();
// The MockResourceLoader now informs the ResourceHandler of cancellation.
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
TEST_F(ThrottlingResourceHandlerTest, DoubleCancelDuringWillStart) {
throttle1_->set_defer_on_will_start_request(1);
EXPECT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
mock_loader_->OnWillStart(GURL(kInitialUrl)));
// |throttle2_| cancels.
throttle2_->CancelWithError(net::ERR_UNEXPECTED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// |throttle1_|, unaware of the cancellation, also cancels.
throttle1_->CancelWithError(net::ERR_FAILED);
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
EXPECT_EQ(net::ERR_UNEXPECTED, mock_loader_->error_code());
// The MockResourceLoader now informs the ResourceHandler of cancellation.
EXPECT_EQ(MockResourceLoader::Status::IDLE,
mock_loader_->OnResponseCompleted(
net::URLRequestStatus::FromError(net::ERR_UNEXPECTED)));
EXPECT_EQ(1, throttle1_->will_start_request_called());
EXPECT_EQ(0, throttle1_->will_redirect_request_called());
EXPECT_EQ(0, throttle1_->will_process_response_called());
EXPECT_EQ(0, throttle2_->will_start_request_called());
EXPECT_EQ(0, throttle2_->will_redirect_request_called());
EXPECT_EQ(0, throttle2_->will_process_response_called());
EXPECT_EQ(0, test_handler_->on_will_start_called());
EXPECT_EQ(0, test_handler_->on_request_redirected_called());
EXPECT_EQ(0, test_handler_->on_response_started_called());
EXPECT_EQ(1, test_handler_->on_response_completed_called());
}
} // namespace
} // namespace content