| // Copyright 2017 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/common/throttling_url_loader.h" |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind_test_util.h" |
| #include "base/test/task_environment.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/public/mojom/url_loader.mojom.h" |
| #include "services/network/public/mojom/url_loader_factory.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 content { |
| namespace { |
| |
| GURL request_url = GURL("http://example.org"); |
| GURL redirect_url = GURL("http://example.com"); |
| |
| class TestURLLoaderFactory : public network::mojom::URLLoaderFactory, |
| public network::mojom::URLLoader { |
| public: |
| TestURLLoaderFactory() : binding_(this), url_loader_binding_(this) { |
| binding_.Bind(mojo::MakeRequest(&factory_ptr_)); |
| shared_factory_ = |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| factory_ptr_.get()); |
| } |
| |
| ~TestURLLoaderFactory() override { shared_factory_->Detach(); } |
| |
| network::mojom::URLLoaderFactoryPtr& factory_ptr() { return factory_ptr_; } |
| network::mojom::URLLoaderClientPtr& client_ptr() { return client_ptr_; } |
| mojo::Binding<network::mojom::URLLoader>& url_loader_binding() { |
| return url_loader_binding_; |
| } |
| 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_; |
| } |
| |
| size_t pause_reading_body_from_net_called() const { |
| return pause_reading_body_from_net_called_; |
| } |
| |
| size_t resume_reading_body_from_net_called() const { |
| return resume_reading_body_from_net_called_; |
| } |
| |
| void NotifyClientOnReceiveResponse() { |
| client_ptr_->OnReceiveResponse(network::ResourceResponseHead()); |
| } |
| |
| void NotifyClientOnReceiveRedirect() { |
| net::RedirectInfo info; |
| info.new_url = redirect_url; |
| client_ptr_->OnReceiveRedirect(info, network::ResourceResponseHead()); |
| } |
| |
| void NotifyClientOnComplete(int error_code) { |
| network::URLLoaderCompletionStatus data; |
| data.error_code = error_code; |
| client_ptr_->OnComplete(data); |
| } |
| |
| void CloseClientPipe() { client_ptr_.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(network::mojom::URLLoaderRequest request, |
| int32_t routing_id, |
| int32_t request_id, |
| uint32_t options, |
| const network::ResourceRequest& url_request, |
| network::mojom::URLLoaderClientPtr client, |
| const net::MutableNetworkTrafficAnnotationTag& |
| traffic_annotation) override { |
| create_loader_and_start_called_++; |
| |
| if (url_loader_binding_.is_bound()) |
| url_loader_binding_.Unbind(); |
| |
| url_loader_binding_.Bind(std::move(request)); |
| client_ptr_ = std::move(client); |
| |
| if (on_create_loader_and_start_callback_) |
| on_create_loader_and_start_callback_.Run(url_request); |
| } |
| |
| void Clone(network::mojom::URLLoaderFactoryRequest request) override { |
| NOTREACHED(); |
| } |
| |
| // network::mojom::URLLoader implementation. |
| void FollowRedirect(const std::vector<std::string>& removed_headers, |
| const net::HttpRequestHeaders& modified_headers, |
| const base::Optional<GURL>& new_url) override { |
| headers_removed_on_redirect_ = removed_headers; |
| headers_modified_on_redirect_ = modified_headers; |
| } |
| |
| void SetPriority(net::RequestPriority priority, |
| int32_t intra_priority_value) override {} |
| |
| void PauseReadingBodyFromNet() override { |
| pause_reading_body_from_net_called_++; |
| } |
| |
| void ResumeReadingBodyFromNet() override { |
| resume_reading_body_from_net_called_++; |
| } |
| |
| size_t create_loader_and_start_called_ = 0; |
| std::vector<std::string> headers_removed_on_redirect_; |
| net::HttpRequestHeaders headers_modified_on_redirect_; |
| size_t pause_reading_body_from_net_called_ = 0; |
| size_t resume_reading_body_from_net_called_ = 0; |
| |
| mojo::Binding<network::mojom::URLLoaderFactory> binding_; |
| mojo::Binding<network::mojom::URLLoader> url_loader_binding_; |
| network::mojom::URLLoaderFactoryPtr factory_ptr_; |
| network::mojom::URLLoaderClientPtr client_ptr_; |
| scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> shared_factory_; |
| OnCreateLoaderAndStartCallback on_create_loader_and_start_callback_; |
| DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory); |
| }; |
| |
| class TestURLLoaderClient : public network::mojom::URLLoaderClient { |
| public: |
| TestURLLoaderClient() {} |
| |
| 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( |
| const base::RepeatingClosure& callback) { |
| on_received_response_callback_ = callback; |
| } |
| |
| using OnCompleteCallback = base::Callback<void(int error_code)>; |
| void set_on_complete_callback(const OnCompleteCallback& callback) { |
| on_complete_callback_ = callback; |
| } |
| |
| private: |
| // network::mojom::URLLoaderClient implementation: |
| void OnReceiveResponse( |
| network::mojom::URLResponseHeadPtr response_head) override { |
| on_received_response_called_++; |
| if (on_received_response_callback_) |
| 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 OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {} |
| void OnTransferSizeUpdated(int32_t transfer_size_diff) override {} |
| void OnStartLoadingResponseBody( |
| mojo::ScopedDataPipeConsumerHandle body) override {} |
| void OnComplete(const network::URLLoaderCompletionStatus& status) override { |
| on_complete_called_++; |
| if (on_complete_callback_) |
| 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::RepeatingClosure on_received_response_callback_; |
| OnCompleteCallback on_complete_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestURLLoaderClient); |
| }; |
| |
| class TestURLLoaderThrottle : public blink::URLLoaderThrottle { |
| public: |
| TestURLLoaderThrottle() {} |
| explicit TestURLLoaderThrottle(const base::Closure& destruction_notifier) |
| : destruction_notifier_(destruction_notifier) {} |
| |
| ~TestURLLoaderThrottle() override { |
| if (destruction_notifier_) |
| destruction_notifier_.Run(); |
| } |
| |
| using ThrottleCallback = |
| base::RepeatingCallback<void(URLLoaderThrottle::Delegate* delegate, |
| bool* defer)>; |
| using ThrottleRedirectCallback = |
| base::RepeatingCallback<void(blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_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_; |
| } |
| |
| 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( |
| const ThrottleRedirectCallback& callback) { |
| will_redirect_request_callback_ = callback; |
| } |
| |
| void set_will_process_response_callback(const ThrottleCallback& callback) { |
| will_process_response_callback_ = callback; |
| } |
| |
| void set_before_will_process_response_callback( |
| const ThrottleCallback& callback) { |
| before_will_process_response_callback_ = 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_, defer); |
| } |
| |
| void WillRedirectRequest(net::RedirectInfo* redirect_info, |
| const network::ResourceResponseHead& response_head, |
| bool* defer, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers) override { |
| will_redirect_request_called_++; |
| if (will_redirect_request_callback_) { |
| will_redirect_request_callback_.Run(delegate_, defer, removed_headers, |
| modified_headers); |
| } |
| } |
| |
| void WillProcessResponse(const GURL& response_url, |
| network::ResourceResponseHead* response_head, |
| bool* defer) override { |
| will_process_response_called_++; |
| if (will_process_response_callback_) |
| will_process_response_callback_.Run(delegate_, defer); |
| response_url_ = response_url; |
| } |
| |
| void BeforeWillProcessResponse( |
| const GURL& response_url, |
| const network::ResourceResponseHead& response_head, |
| bool* defer) override { |
| before_will_process_response_called_++; |
| if (before_will_process_response_callback_) |
| before_will_process_response_callback_.Run(delegate_, defer); |
| } |
| |
| 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; |
| |
| GURL response_url_; |
| |
| ThrottleCallback will_start_request_callback_; |
| ThrottleRedirectCallback will_redirect_request_callback_; |
| ThrottleCallback will_process_response_callback_; |
| ThrottleCallback before_will_process_response_callback_; |
| |
| GURL modify_url_in_will_start_; |
| |
| base::Closure destruction_notifier_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestURLLoaderThrottle); |
| }; |
| |
| class ThrottlingURLLoaderTest : public testing::Test { |
| public: |
| ThrottlingURLLoaderTest() {} |
| |
| 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::Bind(&ThrottlingURLLoaderTest::ResetThrottleRawPointer, |
| weak_factory_.GetWeakPtr())); |
| |
| throttle_ = throttle.get(); |
| |
| throttles_.push_back(std::move(throttle)); |
| } |
| |
| void CreateLoaderAndStart(bool sync = false) { |
| uint32_t options = 0; |
| if (sync) |
| options |= network::mojom::kURLLoadOptionSynchronous; |
| network::ResourceRequest request; |
| request.url = request_url; |
| loader_ = ThrottlingURLLoader::CreateLoaderAndStart( |
| factory_.shared_factory(), std::move(throttles_), 0, 0, options, |
| &request, &client_, TRAFFIC_ANNOTATION_FOR_TESTS, |
| base::ThreadTaskRunnerHandle::Get()); |
| factory_.factory_ptr().FlushForTesting(); |
| } |
| |
| 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_|. |
| TestURLLoaderThrottle* throttle_ = nullptr; |
| |
| base::WeakPtrFactory<ThrottlingURLLoaderTest> weak_factory_{this}; |
| |
| DISALLOW_COPY_AND_ASSIGN(ThrottlingURLLoaderTest); |
| }; |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeStart) { |
| throttle_->set_will_start_request_callback( |
| base::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback(base::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| quit_closure.Run(); |
| }, |
| run_loop.QuitClosure())); |
| |
| 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, DeferBeforeStart) { |
| throttle_->set_will_start_request_callback( |
| base::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback(base::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop.QuitClosure())); |
| |
| 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_ptr().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, ModifyHeaderInResumeBeforeStart) { |
| throttle_->set_will_start_request_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { *defer = true; })); |
| |
| CreateLoaderAndStart(); |
| |
| base::RunLoop run_loop; |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ("X-Test-Header-1: Foo\r\n\r\n", |
| url_request.headers.ToString()); |
| EXPECT_EQ("X-Test-Header-2: Bar\r\n\r\n", |
| url_request.cors_exempt_headers.ToString()); |
| quit_closure.Run(); |
| }, |
| run_loop.QuitClosure())); |
| |
| net::HttpRequestHeaders modified_headers; |
| net::HttpRequestHeaders modified_cors_exempt_headers; |
| modified_headers.SetHeader("X-Test-Header-1", "Foo"); |
| modified_cors_exempt_headers.SetHeader("X-Test-Header-2", "Bar"); |
| throttle_->delegate()->UpdateDeferredRequestHeaders( |
| modified_headers, modified_cors_exempt_headers); |
| throttle_->delegate()->Resume(); |
| |
| run_loop.Run(); |
| } |
| |
| 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()); |
| } |
| |
| // 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; })); |
| throttle_->set_will_redirect_request_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* /* delegate */, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */) { *defer = true; })); |
| |
| CreateLoaderAndStart(); |
| |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| |
| throttle_->delegate()->Resume(); |
| |
| 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()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, CancelBeforeRedirect) { |
| throttle_->set_will_redirect_request_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_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, DeferBeforeRedirect) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_redirect_request_callback(base::Bind( |
| [](const base::Closure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| base::RunLoop run_loop2; |
| client_.set_on_complete_callback(base::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_UNEXPECTED, error); |
| quit_closure.Run(); |
| }, |
| 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()); |
| |
| 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::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_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"); |
| })); |
| |
| 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"); |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_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()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, ModifyHeaderInResumeBeforeRedirect) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_redirect_request_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_headers) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| CreateLoaderAndStart(); |
| factory_.NotifyClientOnReceiveRedirect(); |
| run_loop1.Run(); |
| |
| net::HttpRequestHeaders modified_headers; |
| net::HttpRequestHeaders modified_cors_exempt_headers; |
| modified_headers.SetHeader("X-Test-Header-1", "Foo"); |
| modified_cors_exempt_headers.SetHeader("X-Test-Header-2", "Bar"); |
| throttle_->delegate()->UpdateDeferredRequestHeaders( |
| modified_headers, modified_cors_exempt_headers); |
| throttle_->delegate()->Resume(); |
| |
| loader_->FollowRedirect({}, {}); |
| |
| base::RunLoop run_loop2; |
| run_loop2.RunUntilIdle(); |
| |
| EXPECT_EQ( |
| "X-Test-Header-1: Foo\r\n" |
| "X-Test-Header-2: Bar\r\n\r\n", |
| factory_.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::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_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::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* removed_headers, |
| net::HttpRequestHeaders* modified_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::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| })); |
| |
| base::RunLoop run_loop; |
| client_.set_on_complete_callback(base::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| quit_closure.Run(); |
| }, |
| run_loop.QuitClosure())); |
| |
| 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, DeferBeforeResponse) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_process_response_callback(base::Bind( |
| [](const base::Closure& 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::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_UNEXPECTED, error); |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| 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::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_ABORTED, error); |
| quit_closure.Run(); |
| }, |
| run_loop.QuitClosure())); |
| |
| 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::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_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::Bind([](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::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| quit_closure.Run(); |
| }, |
| run_loop.QuitClosure())); |
| |
| 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::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->CancelWithError(net::ERR_ACCESS_DENIED); |
| delegate->Resume(); |
| })); |
| |
| base::RunLoop run_loop1; |
| client_.set_on_complete_callback(base::Bind( |
| [](const base::Closure& quit_closure, int error) { |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, error); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| 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::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| |
| base::RunLoop loop; |
| client_.set_on_complete_callback(base::Bind( |
| [](base::RunLoop* loop, int error) { |
| EXPECT_EQ(net::OK, error); |
| loop->Quit(); |
| }, |
| &loop)); |
| |
| 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_ptr().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::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| throttle2->set_will_start_request_callback( |
| base::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| })); |
| |
| base::RunLoop loop; |
| client_.set_on_complete_callback(base::Bind( |
| [](base::RunLoop* loop, int error) { |
| EXPECT_EQ(net::OK, error); |
| loop->Quit(); |
| }, |
| &loop)); |
| |
| 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_ptr().FlushForTesting(); |
| EXPECT_EQ(0u, factory_.create_loader_and_start_called()); |
| |
| throttle2->delegate()->Resume(); |
| |
| // Now it should have started. |
| factory_.factory_ptr().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, PauseResumeReadingBodyFromNet) { |
| throttles_.emplace_back(std::make_unique<TestURLLoaderThrottle>()); |
| auto* throttle2 = |
| static_cast<TestURLLoaderThrottle*>(throttles_.back().get()); |
| |
| // Test that it is okay to call delegate->PauseReadingBodyFromNet() even |
| // before the loader is created. |
| throttle_->set_will_start_request_callback( |
| base::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->PauseReadingBodyFromNet(); |
| *defer = true; |
| })); |
| throttle2->set_will_start_request_callback( |
| base::Bind([](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->PauseReadingBodyFromNet(); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| throttle_->delegate()->Resume(); |
| |
| factory_.factory_ptr().FlushForTesting(); |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| |
| // Make sure all URLLoader calls before this point are delivered to the impl |
| // side. |
| factory_.url_loader_binding().FlushForTesting(); |
| |
| // Although there were two calls to delegate->PauseReadingBodyFromNet(), only |
| // one URLLoader::PauseReadingBodyFromNet() Mojo call was made. |
| EXPECT_EQ(1u, factory_.pause_reading_body_from_net_called()); |
| EXPECT_EQ(0u, factory_.resume_reading_body_from_net_called()); |
| |
| // Reading body from network is still paused by |throttle2|. Calling |
| // ResumeReadingBodyFromNet() on |throttle_| shouldn't have any effect. |
| throttle_->delegate()->ResumeReadingBodyFromNet(); |
| factory_.url_loader_binding().FlushForTesting(); |
| EXPECT_EQ(1u, factory_.pause_reading_body_from_net_called()); |
| EXPECT_EQ(0u, factory_.resume_reading_body_from_net_called()); |
| |
| // Even if we call ResumeReadingBodyFromNet() on |throttle_| one more time. |
| throttle_->delegate()->ResumeReadingBodyFromNet(); |
| factory_.url_loader_binding().FlushForTesting(); |
| EXPECT_EQ(1u, factory_.pause_reading_body_from_net_called()); |
| EXPECT_EQ(0u, factory_.resume_reading_body_from_net_called()); |
| |
| throttle2->delegate()->ResumeReadingBodyFromNet(); |
| factory_.url_loader_binding().FlushForTesting(); |
| EXPECT_EQ(1u, factory_.pause_reading_body_from_net_called()); |
| EXPECT_EQ(1u, factory_.resume_reading_body_from_net_called()); |
| } |
| |
| TEST_F(ThrottlingURLLoaderTest, |
| DestroyingThrottlingURLLoaderInDelegateCall_Response) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_process_response_callback(base::Bind( |
| [](const base::Closure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| base::RunLoop run_loop2; |
| client_.set_on_received_response_callback(base::Bind( |
| [](ThrottlingURLLoaderTest* test, const base::Closure& 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_.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_); |
| } |
| |
| // Regression test for crbug.com/833292. |
| TEST_F(ThrottlingURLLoaderTest, |
| DestroyingThrottlingURLLoaderInDelegateCall_Redirect) { |
| base::RunLoop run_loop1; |
| throttle_->set_will_redirect_request_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer, |
| std::vector<std::string>* /* removed_headers */, |
| net::HttpRequestHeaders* /* modified_headers */) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| 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_); |
| } |
| |
| // Call RestartWithFlags() from a single throttle while processing |
| // BeforeWillProcessResponse(). |
| TEST_F(ThrottlingURLLoaderTest, RestartWithFlags) { |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| base::RunLoop run_loop3; |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Restart the request when processing BeforeWillProcessResponse(), using |
| // different load flags (1). |
| throttle_->set_before_will_process_response_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { delegate->RestartWithFlags(1); })); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| 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()); |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(1, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| // 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::ThrottleCallback()); |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| // 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(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| } |
| |
| // Call RestartWithFlags() from a single throttle after having deferred |
| // BeforeWillProcessResponse(). |
| TEST_F(ThrottlingURLLoaderTest, DeferThenRestartWithFlags) { |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| base::RunLoop run_loop3; |
| base::RunLoop run_loop4; |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Defer BeforeWillProcessResponse(). |
| throttle_->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| 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()); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| 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()); |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(1, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| throttle_->delegate()->RestartWithFlags(1); |
| throttle_->delegate()->Resume(); |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| throttle_->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(0u, throttle_->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle_->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle_->will_process_response_called()); |
| } |
| |
| // Call RestartWithFlags() from a multiple throttles while processing |
| // BeforeWillProcessResponse(). Ensures that the request is restarted exactly |
| // once, using the combination of all additional load flags. |
| TEST_F(ThrottlingURLLoaderTest, MultipleRestartWithFlags) { |
| // 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; |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Have two of the three throttles restart whe processing |
| // BeforeWillProcessResponse(), using |
| // different load flags (2 and 8). |
| throttles[0]->set_before_will_process_response_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { delegate->RestartWithFlags(2); })); |
| throttles[2]->set_before_will_process_response_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { delegate->RestartWithFlags(8); })); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 10 = (2 | 8)). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(10, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| // 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::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| // 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(0u, throttle->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle->will_process_response_called()); |
| } |
| } |
| |
| // Call RestartWithFlags() from multiple throttles after having deferred |
| // BeforeWillProcessResponse() in each. Ensures that the request is started |
| // exactly once, using the combination of all additional load flags. |
| TEST_F(ThrottlingURLLoaderTest, MultipleDeferThenRestartWithFlags) { |
| // 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; |
| base::RunLoop run_loop4; |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Have all of the throttles defer. Once they have all been deferred, quit |
| // run_loop2. |
| int throttle_counter = 0; |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| } |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1 | 2 | 4). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(7, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| int next_load_flag = 1; |
| for (auto* throttle : throttles) { |
| throttle->delegate()->RestartWithFlags(next_load_flag); |
| throttle->delegate()->Resume(); |
| next_load_flag <<= 1; |
| } |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(0u, throttle->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle->will_process_response_called()); |
| } |
| } |
| |
| // Call RestartWithFlags() from multiple throttles -- two while deferred, and |
| // one while processing BeforeWillProcessResponse(). Ensures that the request is |
| // restarted exactly once, using the combination of all additional load flags. |
| TEST_F(ThrottlingURLLoaderTest, MultipleRestartWithFlagsDeferAndSync) { |
| // 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; |
| base::RunLoop run_loop4; |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Have two of the throttles defer, and one call restart |
| // synchronously. Once all are run, quit run_loop2. |
| int throttle_counter = 0; |
| for (size_t i = 0; i < 2u; ++i) { |
| throttles[i]->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| } |
| throttles[2]->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithFlags(4); |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1 | 2 | 4). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(7, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| int next_load_flag = 1; |
| for (auto* throttle : throttles) { |
| throttle->delegate()->RestartWithFlags(next_load_flag); |
| throttle->delegate()->Resume(); |
| next_load_flag <<= 1; |
| } |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(0u, throttle->will_redirect_request_called()); |
| EXPECT_EQ(2u, throttle->before_will_process_response_called()); |
| EXPECT_EQ(1u, throttle->will_process_response_called()); |
| } |
| } |
| |
| // Call RestartWithURLResetAndFlags() from a single throttle while processing |
| // BeforeWillProcessResponse(), and verify that it restarts with the original |
| // URL. |
| TEST_F(ThrottlingURLLoaderTest, RestartWithURLResetAndFlags) { |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| base::RunLoop run_loop3; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Restart the request when processing BeforeWillProcessResponse(), using |
| // different load flags (1), and an URL reset. |
| throttle_->set_before_will_process_response_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithURLResetAndFlags(1); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| 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(throttle_->observed_response_url(), modified_url); |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(1, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| // 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::ThrottleCallback()); |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| // 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(1u, 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 RestartWithURLResetAndFlags() from a single throttle after having |
| // deferred BeforeWillProcessResponse(), and verify it uses the original URL. |
| TEST_F(ThrottlingURLLoaderTest, DeferThenRestartWithURLResetAndFlags) { |
| base::RunLoop run_loop1; |
| base::RunLoop run_loop2; |
| base::RunLoop run_loop3; |
| base::RunLoop run_loop4; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Defer BeforeWillProcessResponse(). |
| throttle_->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| 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(throttle_->observed_response_url(), modified_url); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| 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()); |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(1, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| throttle_->delegate()->RestartWithURLResetAndFlags(1); |
| throttle_->delegate()->Resume(); |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| throttle_->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| EXPECT_EQ(1u, throttle_->will_start_request_called()); |
| EXPECT_EQ(1u, 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 RestartWithURLResetFlags() from a multiple throttles while processing |
| // BeforeWillProcessResponse(). Ensures that the request is restarted exactly |
| // once, using the combination of all additional load flags, and with the |
| // original URL. |
| TEST_F(ThrottlingURLLoaderTest, MultipleRestartWithURLResetAndFlags) { |
| // 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. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Have two of the three throttles restart whe processing |
| // BeforeWillProcessResponse(), using |
| // different load flags (2 and 8), but both with URL resets. |
| throttles[0]->set_before_will_process_response_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithURLResetAndFlags(2); |
| })); |
| throttles[2]->set_before_will_process_response_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithURLResetAndFlags(8); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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(throttle_->observed_response_url(), modified_url); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 10 = (2 | 8)). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(10, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| // 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::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| // 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(1u, 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 RestartWithURLResetAndFlags() from multiple throttles after having |
| // deferred BeforeWillProcessResponse() in each. Ensures that the request is |
| // started exactly once, using the combination of all additional load flags, |
| // and with the original URL. |
| TEST_F(ThrottlingURLLoaderTest, MultipleDeferThenRestartWithURLResetAndFlags) { |
| // 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; |
| base::RunLoop run_loop4; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Have all of the throttles defer. Once they have all been deferred, quit |
| // run_loop2. |
| int throttle_counter = 0; |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| } |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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(throttle_->observed_response_url(), modified_url); |
| } |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1 | 2 | 4). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(7, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| int next_load_flag = 1; |
| for (auto* throttle : throttles) { |
| throttle->delegate()->RestartWithURLResetAndFlags(next_load_flag); |
| throttle->delegate()->Resume(); |
| next_load_flag <<= 1; |
| } |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(1u, 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 RestartWithURLResetAndFlags() from multiple throttles -- two while |
| // deferred, and one while processing BeforeWillProcessResponse(). Ensures that |
| // the request is restarted exactly once, using the combination of all |
| // additional load flags, and that the restarted requests use the original URL. |
| TEST_F(ThrottlingURLLoaderTest, |
| MultipleRestartWithURLResetAndFlagsDeferAndSync) { |
| // 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; |
| base::RunLoop run_loop4; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Have two of the throttles defer, and one call restart |
| // synchronously. Once all are run, quit run_loop2. |
| int throttle_counter = 0; |
| for (size_t i = 0; i < 2u; ++i) { |
| throttles[i]->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| } |
| throttles[2]->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithURLResetAndFlags(4); |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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(throttle_->observed_response_url(), modified_url); |
| } |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1 | 2 | 4). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(7, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| int next_load_flag = 1; |
| for (auto* throttle : throttles) { |
| throttle->delegate()->RestartWithURLResetAndFlags(next_load_flag); |
| throttle->delegate()->Resume(); |
| next_load_flag <<= 1; |
| } |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(1u, 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 RestartWithFlags() and RestartWithURLResetFlags() from separate |
| // throttles while processing BeforeWillProcessResponse(). Ensures that the |
| // request is restarted exactly once, using the combination of all additional |
| // load flags, and with the original URL. |
| TEST_F(ThrottlingURLLoaderTest, MultipleRestartsOfMultipleTypes) { |
| // 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. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Have two of the three throttles restart when processing |
| // BeforeWillProcessResponse(), using |
| // different load flags (2 and 8), and one with URL resets. |
| throttles[0]->set_before_will_process_response_callback( |
| base::BindRepeating([](blink::URLLoaderThrottle::Delegate* delegate, |
| bool* defer) { delegate->RestartWithFlags(2); })); |
| throttles[2]->set_before_will_process_response_callback(base::BindRepeating( |
| [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithURLResetAndFlags(8); |
| })); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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(throttle_->observed_response_url(), modified_url); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 10 = (2 | 8)). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(10, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop2.QuitClosure())); |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| // 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::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| // 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(1u, 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 RestartWithURLResetAndFlags() and RestartWithFlags from separate |
| // throttles after having deferred BeforeWillProcessResponse() in each. Ensures |
| // that the request is started exactly once, using the combination of all |
| // additional load flags, and with the original URL. |
| TEST_F(ThrottlingURLLoaderTest, MultipleDeferThenRestartsOfMultipleTypes) { |
| // 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; |
| base::RunLoop run_loop4; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Have all of the throttles defer. Once they have all been deferred, quit |
| // run_loop2. |
| int throttle_counter = 0; |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| } |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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(throttle_->observed_response_url(), modified_url); |
| } |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1 | 2 | 4). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(7, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| // Restart throttles with different load flags, one with an URL reset. |
| int next_load_flag = 1; |
| bool with_url_reset = true; |
| for (auto* throttle : throttles) { |
| if (with_url_reset) { |
| throttle->delegate()->RestartWithURLResetAndFlags(next_load_flag); |
| with_url_reset = false; |
| } |
| throttle->delegate()->RestartWithFlags(next_load_flag); |
| throttle->delegate()->Resume(); |
| next_load_flag <<= 1; |
| } |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(1u, 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 RestartWithURLResetAndFlags() from two throttles while |
| // deferred, and one RestartWithFlags() while processing |
| // BeforeWillProcessResponse(). Ensures that the request is restarted exactly |
| // once, using the combination of all additional load flags, and that the |
| // restarted requests use the original URL. |
| TEST_F(ThrottlingURLLoaderTest, MultipleRestartOfMultipleTypesDeferAndSync) { |
| // 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; |
| base::RunLoop run_loop4; |
| |
| // URL for internal redirect. |
| GURL modified_url = GURL("www.example.uk.com"); |
| throttle_->set_modify_url_in_will_start(modified_url); |
| |
| // Check that the initial loader uses the default load flags (0). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(0, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop1.QuitClosure())); |
| |
| // Set the client to actually follow redirects to allow URL resetting to |
| // occur. |
| client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() { |
| net::HttpRequestHeaders modified_headers; |
| loader_->FollowRedirect({} /* removed_headers */, |
| std::move(modified_headers)); |
| })); |
| |
| // Have two of the throttles defer, and one call restart |
| // synchronously. Once all are run, quit run_loop2. |
| int throttle_counter = 0; |
| for (size_t i = 0; i < 2u; ++i) { |
| throttles[i]->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| *defer = true; |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| } |
| throttles[2]->set_before_will_process_response_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int* count, |
| blink::URLLoaderThrottle::Delegate* delegate, bool* defer) { |
| delegate->RestartWithFlags(4); |
| if (++(*count) == 3) { |
| quit_closure.Run(); |
| } |
| }, |
| run_loop2.QuitClosure(), &throttle_counter)); |
| |
| CreateLoaderAndStart(); |
| |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| 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(throttle_->observed_response_url(), modified_url); |
| } |
| |
| factory_.NotifyClientOnReceiveResponse(); |
| |
| run_loop2.Run(); |
| |
| for (auto* throttle : throttles) { |
| 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()); |
| } |
| |
| // The next time we intercept CreateLoaderAndStart() should be for the |
| // restarted request (load flags of 1 | 2 | 4). |
| factory_.set_on_create_loader_and_start(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const network::ResourceRequest& url_request) { |
| EXPECT_EQ(7, url_request.load_flags); |
| quit_closure.Run(); |
| }, |
| run_loop3.QuitClosure())); |
| |
| int next_load_flag = 1; |
| for (auto* throttle : throttles) { |
| throttle->delegate()->RestartWithURLResetAndFlags(next_load_flag); |
| throttle->delegate()->Resume(); |
| next_load_flag <<= 1; |
| } |
| |
| run_loop3.Run(); |
| |
| // Now that the restarted request has been made, clear |
| // BeforeWillProcessResponse(). |
| for (auto* throttle : throttles) { |
| throttle->set_before_will_process_response_callback( |
| TestURLLoaderThrottle::ThrottleCallback()); |
| } |
| |
| client_.set_on_complete_callback(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, int error) { |
| EXPECT_EQ(net::OK, error); |
| quit_closure.Run(); |
| }, |
| run_loop4.QuitClosure())); |
| |
| // Complete the response. |
| factory_.NotifyClientOnReceiveResponse(); |
| factory_.NotifyClientOnComplete(net::OK); |
| |
| run_loop4.Run(); |
| |
| EXPECT_EQ(2u, factory_.create_loader_and_start_called()); |
| for (auto* throttle : throttles) { |
| EXPECT_EQ(1u, throttle->will_start_request_called()); |
| EXPECT_EQ(1u, 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); |
| } |
| } |
| |
| } // namespace |
| } // namespace content |