summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/common/loader
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/common/loader')
-rw-r--r--chromium/third_party/blink/common/loader/throttling_url_loader.cc119
-rw-r--r--chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc238
-rw-r--r--chromium/third_party/blink/common/loader/url_loader_throttle.cc5
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() {}