diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/blink/common/loader | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/common/loader')
3 files changed, 350 insertions, 12 deletions
diff --git a/chromium/third_party/blink/common/loader/throttling_url_loader.cc b/chromium/third_party/blink/common/loader/throttling_url_loader.cc index 878131ce029..181ef0f4960 100644 --- a/chromium/third_party/blink/common/loader/throttling_url_loader.cc +++ b/chromium/third_party/blink/common/loader/throttling_url_loader.cc @@ -12,6 +12,7 @@ #include "net/http/http_status_code.h" #include "net/http/http_util.h" #include "net/url_request/redirect_util.h" +#include "services/network/public/cpp/cors/cors.h" #include "services/network/public/cpp/features.h" #include "services/network/public/mojom/url_response_head.mojom.h" @@ -28,6 +29,43 @@ void MergeRemovedHeaders(std::vector<std::string>* removed_headers_A, } } +#if DCHECK_IS_ON() +void CheckThrottleWillNotCauseCorsPreflight( + const std::set<std::string>& initial_headers, + const std::set<std::string>& initial_cors_exempt_headers, + const net::HttpRequestHeaders& headers, + const net::HttpRequestHeaders& cors_exempt_headers, + const std::vector<std::string> cors_exempt_header_list) { + base::flat_set<std::string> cors_exempt_header_flat_set( + cors_exempt_header_list); + for (auto& header : headers.GetHeaderVector()) { + if (initial_headers.find(header.key) == initial_headers.end() && + !network::cors::IsCorsSafelistedHeader(header.key, header.value)) { + bool is_cors_exempt = cors_exempt_header_flat_set.count(header.key); + NOTREACHED() + << "Throttle added cors unsafe header " << header.key + << (is_cors_exempt + ? " . Header is cors exempt so should have " + "been added to RequestHeaders::cors_exempt_headers " + "instead of " + "of RequestHeaders::cors_exempt_headers." + : ""); + } + } + + for (auto& header : cors_exempt_headers.GetHeaderVector()) { + if (cors_exempt_header_flat_set.count(header.key) == 0 && + initial_cors_exempt_headers.find(header.key) == + initial_cors_exempt_headers.end()) { + NOTREACHED() << "Throttle added cors exempt header " << header.key + << " but it wasn't configured as cors exempt by the " + "browser. See " + << "StoragePartition::UpdateCorsMitigationList()."; + } + } +} +#endif + } // namespace const char ThrottlingURLLoader::kFollowRedirectReason[] = "FollowRedirect"; @@ -133,6 +171,14 @@ class ThrottlingURLLoader::ForwardingThrottleDelegate loader_->RestartWithURLResetAndFlags(additional_load_flags); } + void RestartWithURLResetAndFlagsNow(int additional_load_flags) override { + if (!loader_) + return; + + ScopedDelegateCall scoped_delegate_call(this); + loader_->RestartWithURLResetAndFlagsNow(additional_load_flags); + } + void Detach() { loader_ = nullptr; } private: @@ -173,13 +219,16 @@ ThrottlingURLLoader::StartInfo::StartInfo( int32_t in_request_id, uint32_t in_options, network::ResourceRequest* in_url_request, - scoped_refptr<base::SingleThreadTaskRunner> in_task_runner) + scoped_refptr<base::SingleThreadTaskRunner> in_task_runner, + base::Optional<std::vector<std::string>> in_cors_exempt_header_list) : url_loader_factory(std::move(in_url_loader_factory)), routing_id(in_routing_id), request_id(in_request_id), options(in_options), url_request(*in_url_request), - task_runner(std::move(in_task_runner)) {} + task_runner(std::move(in_task_runner)) { + cors_exempt_header_list = std::move(in_cors_exempt_header_list); +} ThrottlingURLLoader::StartInfo::~StartInfo() = default; @@ -212,11 +261,14 @@ std::unique_ptr<ThrottlingURLLoader> ThrottlingURLLoader::CreateLoaderAndStart( network::ResourceRequest* url_request, network::mojom::URLLoaderClient* client, const net::NetworkTrafficAnnotationTag& traffic_annotation, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + base::Optional<std::vector<std::string>> cors_exempt_header_list) { + DCHECK(url_request); std::unique_ptr<ThrottlingURLLoader> loader(new ThrottlingURLLoader( std::move(throttles), client, traffic_annotation)); loader->Start(std::move(factory), routing_id, request_id, options, - url_request, std::move(task_runner)); + url_request, std::move(task_runner), + std::move(cors_exempt_header_list)); return loader; } @@ -224,7 +276,7 @@ ThrottlingURLLoader::~ThrottlingURLLoader() { if (inside_delegate_calls_ > 0) { // A throttle is calling into this object. In this case, delay destruction // of the throttles, so that throttles don't need to worry about any - // delegate calls may destory them synchronously. + // delegate calls may destroy them synchronously. for (auto& entry : throttles_) entry.delegate->Detach(); @@ -351,7 +403,8 @@ void ThrottlingURLLoader::Start( int32_t request_id, uint32_t options, network::ResourceRequest* url_request, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + base::Optional<std::vector<std::string>> cors_exempt_header_list) { DCHECK_EQ(DEFERRED_NONE, deferred_stage_); DCHECK(!loader_completed_); @@ -362,7 +415,28 @@ void ThrottlingURLLoader::Start( for (auto& entry : throttles_) { auto* throttle = entry.throttle.get(); bool throttle_deferred = false; + +#if DCHECK_IS_ON() + std::set<std::string> initial_headers, initial_cors_exempt_headers; + if (cors_exempt_header_list) { + for (auto& header : url_request->headers.GetHeaderVector()) + initial_headers.insert(header.key); + + for (auto& header : url_request->cors_exempt_headers.GetHeaderVector()) + initial_cors_exempt_headers.insert(header.key); + } +#endif + throttle->WillStartRequest(url_request, &throttle_deferred); + +#if DCHECK_IS_ON() + if (cors_exempt_header_list) { + CheckThrottleWillNotCauseCorsPreflight( + initial_headers, initial_cors_exempt_headers, url_request->headers, + url_request->cors_exempt_headers, *cors_exempt_header_list); + } +#endif + if (original_url_ != url_request->url) { DCHECK(throttle_will_start_redirect_url_.is_empty()) << "ThrottlingURLLoader doesn't support multiple throttles " @@ -384,9 +458,9 @@ void ThrottlingURLLoader::Start( } } - start_info_ = - std::make_unique<StartInfo>(factory, routing_id, request_id, options, - url_request, std::move(task_runner)); + start_info_ = std::make_unique<StartInfo>( + factory, routing_id, request_id, options, url_request, + std::move(task_runner), std::move(cors_exempt_header_list)); if (deferred) deferred_stage_ = DEFERRED_START; else @@ -534,6 +608,13 @@ void ThrottlingURLLoader::RestartWithURLResetAndFlags( has_pending_restart_ = true; } +void ThrottlingURLLoader::RestartWithURLResetAndFlagsNow( + int additional_load_flags) { + RestartWithURLResetAndFlags(additional_load_flags); + if (!did_receive_response_) + RestartWithFlagsNow(); +} + void ThrottlingURLLoader::OnReceiveResponse( network::mojom::URLResponseHeadPtr response_head) { DCHECK_EQ(DEFERRED_NONE, deferred_stage_); @@ -541,6 +622,7 @@ void ThrottlingURLLoader::OnReceiveResponse( DCHECK(deferring_throttles_.empty()); TRACE_EVENT1("loading", "ThrottlingURLLoader::OnReceiveResponse", "url", response_url_.possibly_invalid_spec()); + did_receive_response_ = true; // Dispatch BeforeWillProcessResponse(). if (!throttles_.empty()) { @@ -611,6 +693,19 @@ void ThrottlingURLLoader::OnReceiveRedirect( throttle->WillRedirectRequest( &redirect_info_copy, *response_head, &throttle_deferred, &removed_headers, &modified_headers, &modified_cors_exempt_headers); + + if (!weak_ptr) + return; + +#if DCHECK_IS_ON() + if (start_info_->cors_exempt_header_list) { + CheckThrottleWillNotCauseCorsPreflight( + std::set<std::string>(), std::set<std::string>(), modified_headers, + modified_cors_exempt_headers, + *start_info_->cors_exempt_header_list); + } +#endif + if (redirect_info_copy.new_url != redirect_info.new_url) { DCHECK(throttle_will_redirect_redirect_url_.is_empty()) << "ThrottlingURLLoader doesn't support multiple throttles " @@ -618,8 +713,6 @@ void ThrottlingURLLoader::OnReceiveRedirect( throttle_will_redirect_redirect_url_ = redirect_info_copy.new_url; } - if (!weak_ptr) - return; if (!HandleThrottleResult(throttle, throttle_deferred, &deferred)) return; @@ -865,8 +958,10 @@ void ThrottlingURLLoader::InterceptResponse( original_client_receiver) { response_intercepted_ = true; - if (original_loader) + if (original_loader) { + url_loader_->ResumeReadingBodyFromNet(); *original_loader = url_loader_.Unbind(); + } url_loader_.Bind(std::move(new_loader)); if (original_client_receiver) diff --git a/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc b/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc index 27cc2858487..c1fe940d655 100644 --- a/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc +++ b/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc @@ -2110,6 +2110,244 @@ TEST_F(ThrottlingURLLoaderTest, MultipleRestartWithURLResetAndFlags) { } } +// Verify RestartWithURLResetAndFlagsNow() behaves similar to +// RestartWithURLResetAndFlags() while called during BeforeWillProcessResponse() +// processing, and verify that it restarts with the original URL. +TEST_F(ThrottlingURLLoaderTest, RestartWithURLResetAndFlagsNow) { + 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), + {} /* modified_cors_exempt_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->RestartWithURLResetAndFlagsNow(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::BindLambdaForTesting([&run_loop3](int error) { + EXPECT_EQ(net::OK, error); + run_loop3.Quit(); + })); + + // Complete the response. + factory_.NotifyClientOnReceiveResponse(); + factory_.NotifyClientOnComplete(net::OK); + + run_loop3.Run(); + + EXPECT_EQ(2u, factory_.create_loader_and_start_called()); + EXPECT_EQ(1u, throttle_->will_start_request_called()); + EXPECT_EQ(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); +} + +// Verify RestartWithURLResetAndFlagsNow() behaves similar to +// RestartWithURLResetAndFlags() while called during BeforeWillProcessResponse() +// processing, and verify that it restarts with the original URL. +TEST_F(ThrottlingURLLoaderTest, + RestartWithURLResetAndFlagsNowBeforeProcessResponse) { + 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), + {} /* modified_cors_exempt_headers */); + })); + + CreateLoaderAndStart(); + + run_loop1.Run(); + + EXPECT_EQ(1u, factory_.create_loader_and_start_called()); + EXPECT_EQ(1u, throttle_->will_start_request_called()); + EXPECT_EQ(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); + + // Restarting the request should restart the request immediately. + throttle_->delegate()->RestartWithURLResetAndFlagsNow(1); + + // 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())); + + run_loop2.Run(); + + EXPECT_EQ(2u, factory_.create_loader_and_start_called()); + EXPECT_EQ(1u, throttle_->will_redirect_request_called()); + EXPECT_EQ(0u, throttle_->before_will_process_response_called()); + EXPECT_EQ(0u, throttle_->will_process_response_called()); + + client_.set_on_complete_callback( + base::BindLambdaForTesting([&run_loop3](int error) { + EXPECT_EQ(net::OK, error); + run_loop3.Quit(); + })); + + // Complete the response. + factory_.NotifyClientOnReceiveResponse(); + factory_.NotifyClientOnComplete(net::OK); + + run_loop3.Run(); + + EXPECT_EQ(2u, factory_.create_loader_and_start_called()); + EXPECT_EQ(1u, throttle_->will_start_request_called()); + EXPECT_EQ(1u, throttle_->will_redirect_request_called()); + EXPECT_EQ(1u, throttle_->before_will_process_response_called()); + EXPECT_EQ(1u, throttle_->will_process_response_called()); + EXPECT_EQ(throttle_->observed_response_url(), request_url); +} + +// Verify RestartWithURLResetAndFlagsNow() does not restart request if +// BeforeWillProcessResponse() has already been called. +TEST_F(ThrottlingURLLoaderTest, + RestartWithURLResetAndFlagsNowAfterProcessResponse) { + 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), + {} /* modified_cors_exempt_headers */); + })); + + CreateLoaderAndStart(); + run_loop1.Run(); + + throttle_->set_before_will_process_response_callback( + base::BindLambdaForTesting( + [&run_loop3](blink::URLLoaderThrottle::Delegate* delegate, + bool* defer) { run_loop3.Quit(); })); + + factory_.NotifyClientOnReceiveResponse(); + run_loop3.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(1u, throttle_->will_process_response_called()); + + // Restarting the request should not have any effect. + throttle_->delegate()->RestartWithURLResetAndFlagsNow(1); + + client_.set_on_complete_callback( + base::BindLambdaForTesting([&run_loop4](int error) { + EXPECT_EQ(net::OK, error); + run_loop4.Quit(); + })); + + // Complete the response. + factory_.NotifyClientOnComplete(net::OK); + run_loop4.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(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, diff --git a/chromium/third_party/blink/common/loader/url_loader_throttle.cc b/chromium/third_party/blink/common/loader/url_loader_throttle.cc index 16b98ba1664..b74c6e1e8d8 100644 --- a/chromium/third_party/blink/common/loader/url_loader_throttle.cc +++ b/chromium/third_party/blink/common/loader/url_loader_throttle.cc @@ -37,6 +37,11 @@ void URLLoaderThrottle::Delegate::RestartWithURLResetAndFlags( NOTIMPLEMENTED(); } +void URLLoaderThrottle::Delegate::RestartWithURLResetAndFlagsNow( + int additional_load_flags) { + NOTIMPLEMENTED(); +} + URLLoaderThrottle::Delegate::~Delegate() {} URLLoaderThrottle::~URLLoaderThrottle() {} |