| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/public/common/loader/throttling_url_loader.h" |
| |
| #include "base/functional/bind.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/notreached.h" |
| #include "base/run_loop.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/task_environment.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/public/mojom/early_hints.mojom.h" |
| #include "services/network/public/mojom/url_loader.mojom.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| #include "services/network/public/mojom/url_response_head.mojom.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/loader/url_loader_throttle.h" |
| |
| namespace blink { |
| namespace { |
| |
| GURL request_url = GURL("http://example.org"); |
| GURL redirect_url = GURL("http://example.com"); |
| using RestartWithURLReset = URLLoaderThrottle::RestartWithURLReset; |
| |
| class TestURLLoaderFactory : public network::mojom::URLLoaderFactory, |
| public network::mojom::URLLoader { |
| public: |
| TestURLLoaderFactory() { |
| receiver_.Bind(factory_remote_.BindNewPipeAndPassReceiver()); |
| shared_factory_ = |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| factory_remote_.get()); |
| } |
| TestURLLoaderFactory(const TestURLLoaderFactory&) = delete; |
| TestURLLoaderFactory& operator=(const TestURLLoaderFactory&) = delete; |
| |
| ~TestURLLoaderFactory() override { shared_factory_->Detach(); } |
| |
| mojo::Remote<network::mojom::URLLoaderFactory>& factory_remote() { |
| return factory_remote_; |
| } |
| mojo::Receiver<network::mojom::URLLoader>& url_loader_receiver() { |
| return url_loader_receiver_; |
| } |
| scoped_refptr<network::SharedURLLoaderFactory> shared_factory() { |
| return shared_factory_; |
| } |
| |
| size_t create_loader_and_start_called() const { |
| return create_loader_and_start_called_; |
| } |
| |
| const std::vector<std::string>& headers_removed_on_redirect() const { |
| return headers_removed_on_redirect_; |
| } |
| |
| const net::HttpRequestHeaders& headers_modified_on_redirect() const { |
| return headers_modified_on_redirect_; |
| } |
| |
| const net::HttpRequestHeaders& cors_exempt_headers_modified_on_redirect() |
| const { |
| return cors_exempt_headers_modified_on_redirect_; |
| } |
| |
| void NotifyClientOnReceiveResponse() { |
| client_remote_->OnReceiveResponse(network::mojom::URLResponseHead::New(), |
| mojo::ScopedDataPipeConsumerHandle(), |
| std::nullopt); |
| } |
| |
| void NotifyClientOnReceiveRedirect() { |
| net::RedirectInfo info; |
| info.new_url = redirect_url; |
| client_remote_->OnReceiveRedirect(info, |
| network::mojom::URLResponseHead::New()); |
| } |
| |
| void NotifyClientOnComplete(int error_code) { |
| network::URLLoaderCompletionStatus data; |
| data.error_code = error_code; |
| client_remote_->OnComplete(data); |
| } |
| |
| void CloseClientPipe() { client_remote_.reset(); } |
| |
| using OnCreateLoaderAndStartCallback = base::RepeatingCallback<void( |
| const network::ResourceRequest& url_request)>; |
| void set_on_create_loader_and_start( |
| const OnCreateLoaderAndStartCallback& callback) { |
| on_create_loader_and_start_callback_ = callback; |
| } |
| |
| private: |
| // network::mojom::URLLoaderFactory implementation. |
| void CreateLoaderAndStart( |
| mojo::PendingReceiver<network::mojom::URLLoader> receiver, |
| int32_t request_id, |
| uint32_t options, |
| const network::ResourceRequest& url_request, |
| mojo::PendingRemote<network::mojom::URLLoaderClient> client, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) |
| override { |
| create_loader_and_start_called_++; |
| |
| url_loader_receiver_.reset(); |
| url_loader_receiver_.Bind(std::move(receiver)); |
| client_remote_.reset(); |
| client_remote_.Bind(std::move(client)); |
| |
| if (on_create_loader_and_start_callback_) |
| on_create_loader_and_start_callback_.Run(url_request); |
| } |
| |
| void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) |
| override { |
| NOTREACHED(); |
| } |
| |
| // network::mojom::URLLoader implementation. |
| void FollowRedirect( |
| const std::vector<std::string>& removed_headers, |
| const net::HttpRequestHeaders& modified_headers, |
| const net::HttpRequestHeaders& modified_cors_exempt_headers, |
| const std::optional<GURL>& new_url) override { |
| headers_removed_on_redirect_ = removed_headers; |
| headers_modified_on_redirect_ = modified_headers; |
| cors_exempt_headers_modified_on_redirect_ = modified_cors_exempt_headers; |
| } |
| |
| void SetPriority(net::RequestPriority priority, |
| int32_t intra_priority_value) override {} |
| |
| size_t create_loader_and_start_called_ = 0; |
| std::vector<std::string> headers_removed_on_redirect_; |
| net::HttpRequestHeaders headers_modified_on_redirect_; |
| net::HttpRequestHeaders cors_exempt_headers_modified_on_redirect_; |
| |
| mojo::Receiver<network::mojom::URLLoaderFactory> receiver_{this}; |
| mojo::Receiver<network::mojom::URLLoader> url_loader_receiver_{this}; |
| mojo::Remote<network::mojom::URLLoaderFactory> factory_remote_; |
| mojo::Remote<network::mojom::URLLoaderClient> client_remote_; |
| scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> shared_factory_; |
| OnCreateLoaderAndStartCallback on_create_loader_and_start_callback_; |
| }; |
| |
| class TestURLLoaderClient : public network::mojom::URLLoaderClient { |
| public: |
| TestURLLoaderClient() = default; |
| TestURLLoaderClient(const TestURLLoaderClient&) = delete; |
| TestURLLoaderClient& operator=(const TestURLLoaderClient&) = delete; |
| |
| size_t on_received_response_called() const { |
| return on_received_response_called_; |
| } |
| |
| size_t on_received_redirect_called() const { |
| return on_received_redirect_called_; |
| } |
| |
| size_t on_complete_called() const { return on_complete_called_; } |
| |
| void set_on_received_redirect_callback( |
| const base::RepeatingClosure& callback) { |
| on_received_redirect_callback_ = callback; |
| } |
| |
| void set_on_received_response_callback(base::OnceClosure callback) { |
| on_received_response_callback_ = std::move(callback); |
| } |
| |
| using OnCompleteCallback = base::OnceCallback<void(int error_code)>; |
| void set_on_complete_callback(OnCompleteCallback callback) { |
| on_complete_callback_ = std::move(callback); |
| } |
| |
| private: |
| // network::mojom::URLLoaderClient implementation: |
| void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override { |
| } |
| |
| void OnReceiveResponse( |
| network::mojom::URLResponseHeadPtr response_head, |
| mojo::ScopedDataPipeConsumerHandle body, |
| std::optional<mojo_base::BigBuffer> cached_metadata) override { |
| on_received_response_called_++; |
| if (on_received_response_callback_) |
| std::move(on_received_response_callback_).Run(); |
| } |
| void OnReceiveRedirect( |
| const net::RedirectInfo& redirect_info, |
| network::mojom::URLResponseHeadPtr response_head) override { |
| on_received_redirect_called_++; |
| if (on_received_redirect_callback_) |
| on_received_redirect_callback_.Run(); |
| } |
| void OnUploadProgress(int64_t current_position, |
| int64_t total_size, |
| OnUploadProgressCallback ack_callback) override {} |
| void OnTransferSizeUpdated(int32_t transfer_size_diff) override {} |
| void OnComplete(const network::URLLoaderCompletionStatus& status) override { |
| on_complete_called_++; |
| if (on_complete_callback_) |
| std::move(on_complete_callback_).Run(status.error_code); |
| } |
| |
| size_t on_received_response_called_ = 0; |
| size_t on_received_redirect_called_ = 0; |
| size_t on_complete_called_ = 0; |
| |
| base::RepeatingClosure on_received_redirect_callback_; |
| base::OnceClosure on_received_response_callback_; |
| OnCompleteCallback on_complete_callback_; |
| }; |
| |
| class TestURLLoaderThrottle : public blink::URLLoaderThrottle { |
| public: |
| TestURLLoaderThrottle() = default; |
| explicit TestURLLoaderThrottle(base::OnceClosure destruction_notifier) |
| : destruction_notifier_(std::move(destruction_notifier)) {} |
| |
| TestURLLoaderThrottle(const TestURLLoaderThrottle&) = delete; |
| TestURLLoaderThrottle& operator=(const TestURLLoaderThrottle&) = delete; |
| |
| ~TestURLLoaderThrottle() override { |
| if (destruction_notifier_) |
| std::move(destruction_notifier_).Run(); |
| } |
| |
| using ThrottleCallback = |
| base::RepeatingCallback<void(URLLoaderThrottle::Delegate* delegate, |
| bool* defer)>; |
| using ThrottleRedirectCallback = base::OnceCallback<void( |
| blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers)>; |
| |
| using BeforeThrottleCallback = base::RepeatingCallback<void( |
| URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset)>; |
| using BeforeThrottleRedirectCallback = base::OnceCallback<void( |
| blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers)>; |
| |
| size_t will_start_request_called() const { |
| return will_start_request_called_; |
| } |
| size_t will_redirect_request_called() const { |
| return will_redirect_request_called_; |
| } |
| size_t will_process_response_called() const { |
| return will_process_response_called_; |
| } |
| size_t before_will_process_response_called() const { |
| return before_will_process_response_called_; |
| } |
| |
| size_t before_will_redirect_request_called() const { |
| return before_will_redirect_request_called_; |
| } |
| |
| GURL observed_response_url() const { return *response_url_; } |
| |
| void set_will_start_request_callback(const ThrottleCallback& callback) { |
| will_start_request_callback_ = callback; |
| } |
| |
| void set_will_redirect_request_callback(ThrottleRedirectCallback callback) { |
| will_redirect_request_callback_ = std::move(callback); |
| } |
| |
| void set_will_process_response_callback(const ThrottleCallback& callback) { |
| will_process_response_callback_ = callback; |
| } |
| |
| void set_before_will_process_response_callback( |
| const BeforeThrottleCallback& callback) { |
| before_will_process_response_callback_ = callback; |
| } |
| |
| void set_before_will_redirect_request_callback( |
| BeforeThrottleRedirectCallback callback) { |
| before_will_redirect_request_callback_ = std::move(callback); |
| } |
| |
| void set_modify_url_in_will_start(const GURL& url) { |
| modify_url_in_will_start_ = url; |
| } |
| |
| Delegate* delegate() const { return delegate_; } |
| |
| private: |
| // blink::URLLoaderThrottle implementation. |
| void WillStartRequest(network::ResourceRequest* request, |
| bool* defer) override { |
| will_start_request_called_++; |
| if (!modify_url_in_will_start_.is_empty()) |
| request->url = modify_url_in_will_start_; |
| |
| if (will_start_request_callback_) |
| will_start_request_callback_.Run(delegate_.get(), defer); |
| } |
| |
| void WillRedirectRequest( |
| net::RedirectInfo* redirect_info, |
| const network::mojom::URLResponseHead& response_head, |
| bool* defer, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers) override { |
| will_redirect_request_called_++; |
| if (will_redirect_request_callback_) { |
| std::move(will_redirect_request_callback_) |
| .Run(delegate_.get(), defer, removed_headers, modified_headers, |
| modified_cors_exempt_headers); |
| } |
| } |
| |
| void WillProcessResponse(const GURL& response_url, |
| network::mojom::URLResponseHead* response_head, |
| bool* defer) override { |
| will_process_response_called_++; |
| response_url_ = response_url; |
| if (will_process_response_callback_) |
| will_process_response_callback_.Run(delegate_.get(), defer); |
| } |
| |
| void BeforeWillProcessResponse( |
| const GURL& response_url, |
| const network::mojom::URLResponseHead& response_head, |
| RestartWithURLReset* restart_with_url_reset) override { |
| before_will_process_response_called_++; |
| if (before_will_process_response_callback_) { |
| before_will_process_response_callback_.Run(delegate_.get(), |
| restart_with_url_reset); |
| } |
| } |
| |
| void BeforeWillRedirectRequest( |
| net::RedirectInfo* redirect_info, |
| const network::mojom::URLResponseHead& response_head, |
| RestartWithURLReset* restart_with_url_reset, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers) override { |
| before_will_redirect_request_called_++; |
| if (before_will_redirect_request_callback_) { |
| std::move(before_will_redirect_request_callback_) |
| .Run(delegate_.get(), restart_with_url_reset, removed_headers, |
| modified_headers, modified_cors_exempt_headers); |
| } |
| } |
| |
| size_t will_start_request_called_ = 0; |
| size_t will_redirect_request_called_ = 0; |
| size_t will_process_response_called_ = 0; |
| size_t before_will_process_response_called_ = 0; |
| size_t before_will_redirect_request_called_ = 0; |
| |
| std::optional<GURL> response_url_; |
| |
| ThrottleCallback will_start_request_callback_; |
| ThrottleRedirectCallback will_redirect_request_callback_; |
| ThrottleCallback will_process_response_callback_; |
| BeforeThrottleCallback before_will_process_response_callback_; |
| BeforeThrottleRedirectCallback before_will_redirect_request_callback_; |
| |
| GURL modify_url_in_will_start_; |
| |
| base::OnceClosure destruction_notifier_; |
| }; |
| |
| class ThrottlingURLLoaderTest : public testing::Test { |
| public: |
| ThrottlingURLLoaderTest() = default; |
| ThrottlingURLLoaderTest(const ThrottlingURLLoaderTest&) = delete; |
| ThrottlingURLLoaderTest& operator=(const ThrottlingURLLoaderTest&) = delete; |
| |
| std::unique_ptr<ThrottlingURLLoader>& loader() { return loader_; } |
| TestURLLoaderThrottle* throttle() const { return throttle_; } |
| |
| protected: |
| // testing::Test implementation. |
| void SetUp() override { |
| auto throttle = std::make_unique<TestURLLoaderThrottle>( |
| base::BindOnce(&ThrottlingURLLoaderTest::ResetThrottleRawPointer, |
| weak_factory_.GetWeakPtr())); |
| |
| throttle_ = throttle.get(); |
| |
| throttles_.push_back(std::move(throttle)); |
| } |
| |
| void CreateLoaderAndStart( |
| std::optional<network::ResourceRequest::TrustedParams> trusted_params = |
| std::nullopt) { |
| network::ResourceRequest request; |
| request.url = request_url; |
| request.trusted_params = std::move(trusted_params); |
| loader_ = ThrottlingURLLoader::CreateLoaderAndStart( |
| factory_.shared_factory(), std::move(throttles_), /*request_id=*/0, |
| /*options=*/0, &request, &client_, TRAFFIC_ANNOTATION_FOR_TESTS, |
| base::SingleThreadTaskRunner::GetCurrentDefault()); |
| factory_.factory_remote().FlushForTesting(); |
| } |
| |
| void ResetLoader() { |
| ResetThrottleRawPointer(); |
| loader_.reset(); |
| } |
| |
| void ResetThrottleRawPointer() { throttle_ = nullptr; } |
| |
| // Be the first member so it is destroyed last. |
| base::test::TaskEnvironment task_environment_; |
| |
| std::unique_ptr<ThrottlingURLLoader> loader_; |
| std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles_; |
| |
| TestURLLoaderFactory factory_; |
| TestURLLoaderClient client_; |
| |
| // Owned by |throttles_| or |loader_|. |
| raw_ptr<TestURLLoaderThrottle> throttle_ = nullptr; |
| |
| base::WeakPtrFactory<ThrottlingURLLoaderTest> weak_factory_{this}; |
| }; |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeStart) { |
| throttle_->set_will_start_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeleteBeforeStart) { |
| base::RunLoop run_loop; |
| throttle_->set_will_start_request_callback(base::BindLambdaForTesting( |
| [this, &run_loop](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { |
| ResetLoader(); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeferBeforeStart) { |
| throttle_->set_will_start_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::OK, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| |
| throttle_->delegate()->Resume(); |
| factory_.factory_remote().FlushForTesting(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| EXPECT_EQ(1u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, ModifyURLBeforeStart) { |
| throttle_->set_modify_url_in_will_start(GURL("http://example.org/foo")); |
| |
| CreateLoaderAndStart(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, |
| CrossOriginRedirectBeforeStartWithIsolationInfo) { |
| const GURL modified_url = GURL("https://example.org"); |
| |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| network::ResourceRequest::TrustedParams trusted_params; |
| trusted_params.isolation_info = net::IsolationInfo::Create( |
| net::IsolationInfo::RequestType::kMainFrame, |
| url::Origin::Create(request_url), url::Origin::Create(request_url), |
| net::SiteForCookies()); |
| |
| const auto expected_redirected_isolation_info = |
| trusted_params.isolation_info.CreateForRedirect( |
| url::Origin::Create(modified_url)); |
| ASSERT_FALSE(trusted_params.isolation_info.IsEqualForTesting( |
| expected_redirected_isolation_info)); |
| |
| CreateLoaderAndStart(std::move(trusted_params)); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| base::RunLoop run_loop; |
| factory_.set_on_create_loader_and_start(base::BindLambdaForTesting( |
| [&](const network::ResourceRequest& url_request) { |
| run_loop.Quit(); |
| |
| ASSERT_TRUE(url_request.trusted_params); |
| EXPECT_TRUE( |
| url_request.trusted_params->isolation_info.IsEqualForTesting( |
| expected_redirected_isolation_info)); |
| })); |
| |
| loader_->FollowRedirect({}, {}, {}); |
| |
| run_loop.Run(); |
| } |
| |
| // Regression test for crbug.com/933538 |
| TEST_F(ThrottlingURLLoaderTest, ModifyURLAndDeferRedirect) { |
| throttle_->set_modify_url_in_will_start(GURL("http://example.org/foo")); |
| throttle_->set_will_start_request_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* /* delegate */, |
| bool* defer) { *defer = true; })); |
| base::RunLoop run_loop; |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [&](blink::URLLoaderThrottle::Delegate* /* delegate */, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| *defer = true; |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| |
| throttle_->delegate()->Resume(); |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| |
| throttle_->delegate()->Resume(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(1u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| } |
| |
| // Regression test for crbug.com/1053700. |
| TEST_F(ThrottlingURLLoaderTest, |
| RedirectCallbackShouldNotBeCalledAfterDestruction) { |
| throttle_->set_modify_url_in_will_start(GURL("http://example.org/foo")); |
| base::RunLoop run_loop; |
| bool called = false; |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [&](blink::URLLoaderThrottle::Delegate* /* delegate */, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| *defer = true; |
| called = true; |
| })); |
| |
| // We don't use CreateLoaderAndStart because we don't want to call |
| // FlushForTesting(). |
| network::ResourceRequest request; |
| request.url = request_url; |
| loader_ = ThrottlingURLLoader::CreateLoaderAndStart( |
| factory_.shared_factory(), std::move(throttles_), 0, 0, &request, |
| &client_, TRAFFIC_ANNOTATION_FOR_TESTS, |
| base::SingleThreadTaskRunner::GetCurrentDefault()); |
| |
| loader_ = nullptr; |
| |
| run_loop.RunUntilIdle(); |
| EXPECT_FALSE(called); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeRedirect) { |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveRedirect(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeleteBeforeRedirect) { |
| base::RunLoop run_loop; |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [this, &run_loop]( |
| blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| ResetLoader(); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveRedirect(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeWillRedirect) { |
| throttle_->set_before_will_redirect_request_callback( |
| base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveRedirect(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeleteBeforeWillRedirect) { |
| base::RunLoop run_loop; |
| throttle_->set_before_will_redirect_request_callback( |
| base::BindLambdaForTesting( |
| [this, &run_loop]( |
| blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| ResetLoader(); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveRedirect(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeferBeforeRedirect) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [&run_loop1]( |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| *defer = true; |
| run_loop1.Quit(); |
| })); |
| |
| base::RunLoop run_loop2; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop2](int error) { |
| EXPECT_EQ(net::ERR_UNEXPECTED, error); |
| run_loop2.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveRedirect(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| factory_.NotifyClientOnComplete(net::ERR_UNEXPECTED); |
| |
| base::RunLoop run_loop3; |
| run_loop3.RunUntilIdle(); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| |
| throttle_->delegate()->Resume(); |
| run_loop2.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(1u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, ModifyHeadersBeforeRedirect) { |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers) { |
| removed_headers->push_back("X-Test-Header-1"); |
| modified_headers->SetHeader("X-Test-Header-2", "Foo"); |
| modified_headers->SetHeader("X-Test-Header-3", "Throttle Value"); |
| modified_cors_exempt_headers->SetHeader("X-Test-Cors-Exempt-Header-1", |
| "Bubble"); |
| })); |
| |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| modified_headers.SetHeader("X-Test-Header-3", "Client Value"); |
| modified_headers.SetHeader("X-Test-Header-4", "Bar"); |
| net::HttpRequestHeaders modified_cors_exempt_headers; |
| modified_cors_exempt_headers.SetHeader("X-Test-Cors-Exempt-Header-1", |
| "Bobble"); |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers), |
| std::move(modified_cors_exempt_headers)); |
| })); |
| |
| CreateLoaderAndStart(); |
| factory_.NotifyClientOnReceiveRedirect(); |
| base::RunLoop().RunUntilIdle(); |
| |
| ASSERT_FALSE(factory_.headers_removed_on_redirect().empty()); |
| EXPECT_THAT(factory_.headers_removed_on_redirect(), |
| testing::ElementsAre("X-Test-Header-1")); |
| ASSERT_FALSE(factory_.headers_modified_on_redirect().IsEmpty()); |
| EXPECT_EQ( |
| "X-Test-Header-2: Foo\r\n" |
| "X-Test-Header-3: Client Value\r\n" |
| "X-Test-Header-4: Bar\r\n\r\n", |
| factory_.headers_modified_on_redirect().ToString()); |
| ASSERT_FALSE(factory_.cors_exempt_headers_modified_on_redirect().IsEmpty()); |
| EXPECT_EQ("X-Test-Cors-Exempt-Header-1: Bobble\r\n\r\n", |
| factory_.cors_exempt_headers_modified_on_redirect().ToString()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, MultipleThrottlesModifyHeadersBeforeRedirect) { |
| auto* throttle2 = new TestURLLoaderThrottle(); |
| throttles_.push_back(base::WrapUnique(throttle2)); |
| |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers) { |
| removed_headers->push_back("X-Test-Header-0"); |
| removed_headers->push_back("X-Test-Header-1"); |
| modified_headers->SetHeader("X-Test-Header-3", "Foo"); |
| modified_headers->SetHeader("X-Test-Header-4", "Throttle1"); |
| })); |
| |
| throttle2->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers, |
| net::HttpRequestHeaders* modified_cors_exempt_headers) { |
| removed_headers->push_back("X-Test-Header-1"); |
| removed_headers->push_back("X-Test-Header-2"); |
| modified_headers->SetHeader("X-Test-Header-4", "Throttle2"); |
| })); |
| |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting( |
| [&]() { loader_->FollowRedirect({}, {}, {}); })); |
| |
| CreateLoaderAndStart(); |
| factory_.NotifyClientOnReceiveRedirect(); |
| base::RunLoop().RunUntilIdle(); |
| |
| ASSERT_FALSE(factory_.headers_removed_on_redirect().empty()); |
| EXPECT_THAT(factory_.headers_removed_on_redirect(), |
| testing::ElementsAre("X-Test-Header-0", "X-Test-Header-1", |
| "X-Test-Header-2")); |
| ASSERT_FALSE(factory_.headers_modified_on_redirect().IsEmpty()); |
| EXPECT_EQ( |
| "X-Test-Header-3: Foo\r\n" |
| "X-Test-Header-4: Throttle2\r\n\r\n", |
| factory_.headers_modified_on_redirect().ToString()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeResponse) { |
| throttle_->set_will_process_response_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeleteBeforeResponse) { |
| base::RunLoop run_loop; |
| throttle_->set_will_process_response_callback(base::BindLambdaForTesting( |
| [this, &run_loop](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { |
| ResetLoader(); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeWillProcessResponse) { |
| throttle_->set_before_will_process_response_callback( |
| base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeleteBeforeWillProcessResponse) { |
| base::RunLoop run_loop; |
| throttle_->set_before_will_process_response_callback( |
| base::BindLambdaForTesting( |
| [this, &run_loop](blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset) { |
| ResetLoader(); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, DeferBeforeResponse) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| base::RunLoop run_loop2; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop2](int error) { |
| EXPECT_EQ(net::ERR_UNEXPECTED, error); |
| run_loop2.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| factory_.NotifyClientOnComplete(net::ERR_UNEXPECTED); |
| |
| base::RunLoop run_loop3; |
| run_loop3.RunUntilIdle(); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| |
| throttle_->delegate()->Resume(); |
| run_loop2.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| EXPECT_EQ(1u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, PipeClosure) { |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ABORTED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.CloseClientPipe(); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, ResumeNoOpIfNotDeferred) { |
| auto resume_callback = base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */) { |
| delegate->Resume(); |
| delegate->Resume(); |
| }); |
| throttle_->set_will_start_request_callback(resume_callback); |
| throttle_->set_will_process_response_callback(std::move(resume_callback)); |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| delegate->Resume(); |
| delegate->Resume(); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::OK, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| factory_.NotifyClientOnReceiveRedirect(); |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(redirect_url)); |
| |
| EXPECT_EQ(1u, client_.on_received_response_called()); |
| EXPECT_EQ(1u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelNoOpIfAlreadyCanceled) { |
| throttle_->set_will_start_request_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| delegate->CancelWithError(net::ERR_UNEXPECTED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| throttle_->delegate()->CancelWithError(net::ERR_INVALID_ARGUMENT); |
| run_loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, ResumeNoOpIfAlreadyCanceled) { |
| throttle_->set_will_process_response_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| delegate->Resume(); |
| })); |
| |
| base::RunLoop run_loop1; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop1](int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| run_loop1.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop1.Run(); |
| |
| throttle_->delegate()->Resume(); |
| |
| base::RunLoop run_loop2; |
| run_loop2.RunUntilIdle(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, MultipleThrottlesBasicSupport) { |
| throttles_.emplace_back(std::make_unique<TestURLLoaderThrottle>()); |
| auto* throttle2 = |
| static_cast<TestURLLoaderThrottle*>(throttles_.back().get()); |
| CreateLoaderAndStart(); |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle2->will_start_request_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, BlockWithOneOfMultipleThrottles) { |
| throttles_.emplace_back(std::make_unique<TestURLLoaderThrottle>()); |
| auto* throttle2 = |
| static_cast<TestURLLoaderThrottle*>(throttles_.back().get()); |
| throttle2->set_will_start_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| |
| base::RunLoop loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&loop](int error) { |
| EXPECT_EQ(net::OK, error); |
| loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle2->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle2->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle2->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| EXPECT_EQ(0u, throttle2->will_process_response_called()); |
| |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| |
| throttle2->delegate()->Resume(); |
| factory_.factory_remote().FlushForTesting(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle2->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle2->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle2->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| EXPECT_EQ(1u, throttle2->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| EXPECT_TRUE( |
| throttle2->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| EXPECT_EQ(1u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, BlockWithMultipleThrottles) { |
| throttles_.emplace_back(std::make_unique<TestURLLoaderThrottle>()); |
| auto* throttle2 = |
| static_cast<TestURLLoaderThrottle*>(throttles_.back().get()); |
| |
| // Defers a request on both throttles. |
| throttle_->set_will_start_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| throttle2->set_will_start_request_callback(base::BindLambdaForTesting( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| |
| base::RunLoop loop; |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&loop](int error) { |
| EXPECT_EQ(net::OK, error); |
| loop.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle2->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle2->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle2->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| EXPECT_EQ(0u, throttle2->will_process_response_called()); |
| |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| EXPECT_EQ(0u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(0u, client_.on_complete_called()); |
| |
| throttle_->delegate()->Resume(); |
| |
| // Should still not have started because there's |throttle2| is still blocking |
| // the request. |
| factory_.factory_remote().FlushForTesting(); |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| throttle2->delegate()->Resume(); |
| |
| // Now it should have started. |
| factory_.factory_remote().FlushForTesting(); |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| loop.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle2->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle2->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle2->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| EXPECT_EQ(1u, throttle2->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| EXPECT_TRUE( |
| throttle2->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| EXPECT_EQ(1u, client_.on_received_response_called()); |
| EXPECT_EQ(0u, client_.on_received_redirect_called()); |
| EXPECT_EQ(1u, client_.on_complete_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, |
| DestroyingThrottlingURLLoaderInDelegateCall_Response) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_process_response_callback(base::BindLambdaForTesting( |
| [&run_loop1](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| run_loop1.Quit(); |
| })); |
| |
| base::RunLoop run_loop2; |
| client_.set_on_received_response_callback(base::BindLambdaForTesting([&]() { |
| // Destroy the ThrottlingURLLoader while inside a delegate call from a |
| // throttle. |
| loader().reset(); |
| |
| // The throttle should stay alive. |
| EXPECT_NE(nullptr, throttle()); |
| |
| run_loop2.Quit(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| |
| EXPECT_TRUE( |
| throttle_->observed_response_url().EqualsIgnoringRef(request_url)); |
| |
| throttle_->delegate()->Resume(); |
| run_loop2.Run(); |
| |
| // The ThrottlingURLLoader should be gone. |
| EXPECT_EQ(nullptr, loader_); |
| // The throttle should stay alive and destroyed later. |
| EXPECT_NE(nullptr, throttle_); |
| |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(nullptr, throttle_.get()); |
| } |
| |
| // Regression test for crbug.com/833292. |
| TEST_F(ThrottlingURLLoaderTest, |
| DestroyingThrottlingURLLoaderInDelegateCall_Redirect) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting( |
| [&run_loop1]( |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| *defer = true; |
| run_loop1.Quit(); |
| })); |
| |
| base::RunLoop run_loop2; |
| client_.set_on_received_redirect_callback(base::BindRepeating( |
| [](ThrottlingURLLoaderTest* test, |
| const base::RepeatingClosure& quit_closure) { |
| // Destroy the ThrottlingURLLoader while inside a delegate call from a |
| // throttle. |
| test->loader().reset(); |
| |
| // The throttle should stay alive. |
| EXPECT_NE(nullptr, test->throttle()); |
| |
| quit_closure.Run(); |
| }, |
| base::Unretained(this), run_loop2.QuitClosure())); |
| |
| CreateLoaderAndStart(); |
| |
| factory_.NotifyClientOnReceiveRedirect(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| throttle_->delegate()->Resume(); |
| run_loop2.Run(); |
| |
| // The ThrottlingURLLoader should be gone. |
| EXPECT_EQ(nullptr, loader_); |
| // The throttle should stay alive and destroyed later. |
| EXPECT_NE(nullptr, throttle_); |
| |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(nullptr, throttle_.get()); |
| } |
| |
| // Call RestartWithURLReset() from a single throttle while processing |
| // BeforeWillProcessResponse(), and verify that it restarts with the original |
| // URL. |
| TEST_F(ThrottlingURLLoaderTest, RestartWithURLReset) { |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| base::RunLoop run_loop3; |
| |
| // URL for internal redirect. |
| const GURL modified_url = GURL("http://www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| factory_.set_on_create_loader_and_start(base::BindLambdaForTesting( |
| [&run_loop1](const network::ResourceRequest& url_request) { |
| run_loop1.Quit(); |
| })); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback( |
| base::BindLambdaForTesting([this]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers), |
| {} /* modified_cors_exempt_headers */); |
| })); |
| |
| CreateLoaderAndStart(); |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| // Restart the request with URL reset when processing |
| // BeforeWillProcessResponse(). |
| throttle_->set_before_will_process_response_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset) { |
| *restart_with_url_reset = RestartWithURLReset(true); |
| })); |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request. |
| factory_.set_on_create_loader_and_start(base::BindLambdaForTesting( |
| [&run_loop2](const network::ResourceRequest& url_request) { |
| run_loop2.Quit(); |
| })); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| run_loop2.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse() so it doesn't restart the request yet again. |
| throttle_->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::BeforeThrottleCallback()); |
| |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop3](int error) { |
| EXPECT_EQ(net::OK, error); |
| run_loop3.Quit(); |
| })); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop3.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(2u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| EXPECT_EQ(throttle_->observed_response_url(), request_url); |
| } |
| |
| // Call RestartWithURLReset() from multiple throttles while processing |
| // BeforeWillProcessResponse(). Ensures that the request is restarted exactly |
| // once with the original URL. |
| TEST_F(ThrottlingURLLoaderTest, MultipleRestartWithURLReset) { |
| // Create two additional TestURLLoaderThrottles for a total of 3, and keep |
| // local unowned pointers to them in |throttles|. |
| std::vector<TestURLLoaderThrottle*> throttles; |
| ASSERT_EQ(1u, throttles_.size()); |
| throttles.push_back(throttle_); |
| for (size_t i = 0; i < 2u; ++i) { |
| auto throttle = std::make_unique<TestURLLoaderThrottle>(); |
| throttles.push_back(throttle.get()); |
| throttles_.push_back(std::move(throttle)); |
| } |
| ASSERT_EQ(3u, throttles_.size()); |
| ASSERT_EQ(3u, throttles.size()); |
| |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| base::RunLoop run_loop3; |
| |
| // URL for internal redirect. |
| const GURL modified_url = GURL("http://www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| factory_.set_on_create_loader_and_start(base::BindLambdaForTesting( |
| [&run_loop1](const network::ResourceRequest& url_request) { |
| run_loop1.Quit(); |
| })); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback( |
| base::BindLambdaForTesting([this]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers), |
| {} /* modified_cors_exempt_headers */); |
| })); |
| |
| CreateLoaderAndStart(); |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (const auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(1u, throttle->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle->will_process_response_called()); |
| } |
| |
| // Have two of the three throttles restart with URL reset when processing |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : {throttles[0], throttles[2]}) { |
| throttle->set_before_will_process_response_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset) { |
| *restart_with_url_reset = RestartWithURLReset(true); |
| })); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request. |
| factory_.set_on_create_loader_and_start(base::BindLambdaForTesting( |
| [&run_loop2](const network::ResourceRequest& url_request) { |
| run_loop2.Quit(); |
| })); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| run_loop2.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (const auto* throttle : {throttles[0], throttles[2]}) { |
| EXPECT_EQ(1u, throttle->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle->will_process_response_called()); |
| } |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse() so it doesn't restart the request yet again. |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::BeforeThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop3](int error) { |
| EXPECT_EQ(net::OK, error); |
| run_loop3.Quit(); |
| })); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop3.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(2u, throttle->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle->will_process_response_called()); |
| EXPECT_EQ(throttle_->observed_response_url(), request_url); |
| } |
| } |
| |
| // Test restarts from "BeforeWillRedirectRequest". |
| TEST_F(ThrottlingURLLoaderTest, RestartWithURLResetBeforeWillRedirectRequest) { |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("http://www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // When we intercept CreateLoaderAndStart() it is for the restarted request |
| // already. |
| factory_.set_on_create_loader_and_start(base::BindLambdaForTesting( |
| [&run_loop1](const network::ResourceRequest& url_request) { |
| run_loop1.Quit(); |
| })); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback( |
| base::BindLambdaForTesting([this]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers), |
| {} /* modified_cors_exempt_headers */); |
| })); |
| |
| // Restart the request with URL reset when processing |
| // BeforeWillRedirectRequest(). |
| throttle_->set_before_will_redirect_request_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, |
| RestartWithURLReset* restart_with_url_reset, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */, |
| net::HttpRequestHeaders* /* modified_cors_exempt_headers */) { |
| *restart_with_url_reset = RestartWithURLReset(true); |
| })); |
| |
| CreateLoaderAndStart(); |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(2u, throttle_->before_will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(0u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(0u, throttle_->will_process_response_called()); |
| |
| client_.set_on_complete_callback( |
| base::BindLambdaForTesting([&run_loop2](int error) { |
| EXPECT_EQ(net::OK, error); |
| run_loop2.Quit(); |
| })); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop2.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(2u, throttle_->before_will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(1u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| EXPECT_EQ(throttle_->observed_response_url(), request_url); |
| } |
| |
| } // namespace |
| } // namespace blink |