blob: 3e5c900689e3c5c2e865bee3379b959586c2cdfc [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2015 The Chromium Authors
clamy49678312015-10-22 21:59:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakjc492bf82020-09-09 20:02:445#include "content/browser/renderer_host/navigation_request.h"
Cammie Smith Barnesa0da2cf2021-01-11 22:09:376
Arthur Sonzognic686e8f2024-01-11 08:36:377#include <optional>
Cammie Smith Barnesa0da2cf2021-01-11 22:09:378#include <string>
9#include <vector>
10
Peter Birk Pakkenberg73e07b62022-09-21 11:20:3011#include "base/containers/flat_map.h"
Avi Drissmanadac21992023-01-11 23:46:3912#include "base/functional/bind.h"
arthursonzogni898dcda52021-01-21 08:50:1013#include "base/i18n/number_formatting.h"
Lei Zhang0a85e65a2025-05-23 19:22:0614#include "base/strings/string_number_conversions.h"
Yao Xiao6e1f7d32022-01-07 03:28:4015#include "base/test/scoped_feature_list.h"
Becky Zhou9898cb6e2019-06-05 00:35:3016#include "build/build_config.h"
Takashi Toyoshimacc4d947f2025-06-24 08:38:3417#include "content/browser/renderer_host/navigation_throttle_runner.h"
clamy49678312015-10-22 21:59:0018#include "content/public/browser/navigation_throttle.h"
Peter Birk Pakkenberg73e07b62022-09-21 11:20:3019#include "content/public/browser/origin_trials_controller_delegate.h"
jam6d47c3452016-09-09 18:51:0120#include "content/public/browser/ssl_status.h"
Hans Wennborg5ffd1392019-10-16 11:00:0221#include "content/public/common/content_client.h"
Peter Birk Pakkenberg73e07b62022-09-21 11:20:3022#include "content/public/common/content_features.h"
Robbie McElrath5641d572022-05-20 17:15:2923#include "content/public/common/content_switches.h"
Charles Harrison860f7ef2017-06-28 15:31:4124#include "content/public/common/url_constants.h"
Peter Birk Pakkenberg73e07b62022-09-21 11:20:3025#include "content/public/test/test_browser_context.h"
Lucas Garron79e1a972017-10-04 22:25:0626#include "content/public/test/test_navigation_throttle.h"
Yao Xiao1099e4c2022-03-24 22:40:3727#include "content/test/fenced_frame_test_utils.h"
Camille Lamy62b826012019-02-26 09:15:4728#include "content/test/navigation_simulator_impl.h"
Charles Harrison860f7ef2017-06-28 15:31:4129#include "content/test/test_content_browser_client.h"
clamy49678312015-10-22 21:59:0030#include "content/test/test_render_frame_host.h"
scottmg276753cf2016-10-27 18:25:2231#include "content/test/test_web_contents.h"
David Sandersc5c92922025-04-01 23:47:2132#include "net/base/features.h"
Lucas Garronc1edb5ab2017-11-08 03:31:1333#include "net/ssl/ssl_connection_status_flags.h"
arthursonzogni898dcda52021-01-21 08:50:1034#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
Sandor Majorf42e6bd62025-02-28 00:12:0435#include "services/network/public/cpp/features.h"
Cammie Smith Barnesa0da2cf2021-01-11 22:09:3736#include "testing/gmock/include/gmock/gmock.h"
Camillia Smith Barnes6d2966c82023-08-23 21:16:1837#include "third_party/blink/public/common/features.h"
Minggang Wanga13c796e2021-07-02 05:54:4338#include "third_party/blink/public/common/navigation/navigation_params.h"
Nasko Oskov32f95892025-06-02 20:45:0839#include "third_party/blink/public/common/navigation/navigation_params_mojom_traits.h"
Peter Birk Pakkenberg73e07b62022-09-21 11:20:3040#include "third_party/blink/public/common/origin_trials/scoped_test_origin_trial_policy.h"
sbingler4e4bd9b2023-02-27 19:56:5341#include "third_party/blink/public/common/runtime_feature_state/runtime_feature_state_context.h"
Richard Lie6899952018-11-30 08:42:0042#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
clamy49678312015-10-22 21:59:0043
44namespace content {
45
Mohamed Abdelhalim1e8c5822019-08-02 11:45:4346class NavigationRequestTest : public RenderViewHostImplTestHarness {
clamy49678312015-10-22 21:59:0047 public:
Fergal Dalya1d569972021-03-16 03:24:5348 NavigationRequestTest() : callback_result_(NavigationThrottle::DEFER) {}
clamy49678312015-10-22 21:59:0049
50 void SetUp() override {
51 RenderViewHostImplTestHarness::SetUp();
clamy1d4e78fd2017-07-11 12:59:1952 CreateNavigationHandle();
Dave Tapuska327c06c92022-06-13 20:31:5153 contents()->GetPrimaryMainFrame()->InitializeRenderFrameIfNeeded();
clamy49678312015-10-22 21:59:0054 }
55
Dmitrii Kuraginb7f90da2022-11-02 22:09:3056 void TearDown() override { RenderViewHostImplTestHarness::TearDown(); }
clamy49678312015-10-22 21:59:0057
Charles Harrison4f2bf1a2017-07-18 20:21:2158 void CancelDeferredNavigation(
59 NavigationThrottle::ThrottleCheckResult result) {
Hiroki Nakagawaadcffc502021-06-16 10:47:5160 GetNavigationRequest()->CancelDeferredNavigationInternal(result);
Charles Harrison4f2bf1a2017-07-18 20:21:2161 }
62
clamy49678312015-10-22 21:59:0063 // Helper function to call WillStartRequest on |handle|. If this function
64 // returns DEFER, |callback_result_| will be set to the actual result of
65 // the throttle checks when they are finished.
66 void SimulateWillStartRequest() {
67 was_callback_called_ = false;
68 callback_result_ = NavigationThrottle::DEFER;
69
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:4470 // It's safe to use base::Unretained since the NavigationRequest is owned by
Mohamed Abdelhalim1e8c5822019-08-02 11:45:4371 // the NavigationRequestTest.
Hiroki Nakagawaadcffc502021-06-16 10:47:5172 GetNavigationRequest()->set_complete_callback_for_testing(
Makoto Shimazud2aa2202019-10-09 13:57:1873 base::BindOnce(&NavigationRequestTest::UpdateThrottleCheckResult,
74 base::Unretained(this)));
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:4475
Hiroki Nakagawaadcffc502021-06-16 10:47:5176 GetNavigationRequest()->WillStartRequest();
clamy49678312015-10-22 21:59:0077 }
78
79 // Helper function to call WillRedirectRequest on |handle|. If this function
80 // returns DEFER, |callback_result_| will be set to the actual result of the
81 // throttle checks when they are finished.
clamye88533842015-11-18 12:48:5782 // TODO(clamy): this should also simulate that WillStartRequest was called if
83 // it has not been called before.
clamy49678312015-10-22 21:59:0084 void SimulateWillRedirectRequest() {
85 was_callback_called_ = false;
86 callback_result_ = NavigationThrottle::DEFER;
87
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:4488 // It's safe to use base::Unretained since the NavigationRequest is owned by
Mohamed Abdelhalim1e8c5822019-08-02 11:45:4389 // the NavigationRequestTest.
Hiroki Nakagawaadcffc502021-06-16 10:47:5190 GetNavigationRequest()->set_complete_callback_for_testing(
Makoto Shimazud2aa2202019-10-09 13:57:1891 base::BindOnce(&NavigationRequestTest::UpdateThrottleCheckResult,
92 base::Unretained(this)));
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:4493
Hiroki Nakagawaadcffc502021-06-16 10:47:5194 GetNavigationRequest()->WillRedirectRequest(
Arthur Hemery3a991c092021-12-22 12:04:2495 GURL(), nullptr /* post_redirect_process */);
clamy49678312015-10-22 21:59:0096 }
97
Lucas Garron0cedd962017-10-17 07:23:3398 // Helper function to call WillFailRequest on |handle|. If this function
99 // returns DEFER, |callback_result_| will be set to the actual result of the
100 // throttle checks when they are finished.
Lucas Garronc1edb5ab2017-11-08 03:31:13101 void SimulateWillFailRequest(
102 net::Error net_error_code,
Arthur Sonzognic686e8f2024-01-11 08:36:37103 const std::optional<net::SSLInfo> ssl_info = std::nullopt) {
Lucas Garron0cedd962017-10-17 07:23:33104 was_callback_called_ = false;
105 callback_result_ = NavigationThrottle::DEFER;
Hiroki Nakagawaadcffc502021-06-16 10:47:51106 GetNavigationRequest()->set_net_error(net_error_code);
Lucas Garron0cedd962017-10-17 07:23:33107
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:44108 // It's safe to use base::Unretained since the NavigationRequest is owned by
Mohamed Abdelhalim1e8c5822019-08-02 11:45:43109 // the NavigationRequestTest.
Hiroki Nakagawaadcffc502021-06-16 10:47:51110 GetNavigationRequest()->set_complete_callback_for_testing(
Makoto Shimazud2aa2202019-10-09 13:57:18111 base::BindOnce(&NavigationRequestTest::UpdateThrottleCheckResult,
112 base::Unretained(this)));
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:44113
Hiroki Nakagawaadcffc502021-06-16 10:47:51114 GetNavigationRequest()->WillFailRequest();
Lucas Garron0cedd962017-10-17 07:23:33115 }
116
Nate Chapin060cb952023-02-08 21:13:07117 // Helper function to call WillCommitWithoutUrlLoader on |handle|. If this
118 // function returns DEFER, |callback_result_| will be set to the actual result
119 // of the throttle checks when they are finished.
120 void SimulateWillCommitWithoutUrlLoader() {
121 was_callback_called_ = false;
122 callback_result_ = NavigationThrottle::DEFER;
123
124 // It's safe to use base::Unretained since the NavigationRequest is owned by
125 // the NavigationRequestTest.
126 GetNavigationRequest()->set_complete_callback_for_testing(
127 base::BindOnce(&NavigationRequestTest::UpdateThrottleCheckResult,
128 base::Unretained(this)));
129
130 GetNavigationRequest()->WillCommitWithoutUrlLoader();
131 }
132
clamy49678312015-10-22 21:59:00133 // Whether the callback was called.
134 bool was_callback_called() const { return was_callback_called_; }
135
136 // Returns the callback_result.
137 NavigationThrottle::ThrottleCheckResult callback_result() const {
138 return callback_result_;
139 }
140
Hiroki Nakagawaadcffc502021-06-16 10:47:51141 NavigationRequest::NavigationState state() {
142 return GetNavigationRequest()->state();
143 }
Mohamed Abdelhalimccd149af2019-10-31 14:48:53144
Lucas Garron0cedd962017-10-17 07:23:33145 bool call_counts_match(TestNavigationThrottle* throttle,
146 int start,
147 int redirect,
148 int failure,
Nate Chapin060cb952023-02-08 21:13:07149 int process,
150 int withoutUrlLoader) {
Lucas Garron0cedd962017-10-17 07:23:33151 return start == throttle->GetCallCount(
152 TestNavigationThrottle::WILL_START_REQUEST) &&
153 redirect == throttle->GetCallCount(
154 TestNavigationThrottle::WILL_REDIRECT_REQUEST) &&
155 failure == throttle->GetCallCount(
156 TestNavigationThrottle::WILL_FAIL_REQUEST) &&
157 process == throttle->GetCallCount(
Nate Chapin060cb952023-02-08 21:13:07158 TestNavigationThrottle::WILL_PROCESS_RESPONSE) &&
159 withoutUrlLoader ==
160 throttle->GetCallCount(
161 TestNavigationThrottle::WILL_COMMIT_WITHOUT_URL_LOADER);
Lucas Garron0cedd962017-10-17 07:23:33162 }
163
164 // Creates, register and returns a TestNavigationThrottle that will
165 // synchronously return |result| on checks by default.
clamy49678312015-10-22 21:59:00166 TestNavigationThrottle* CreateTestNavigationThrottle(
167 NavigationThrottle::ThrottleCheckResult result) {
Takashi Toyoshimadffe50e2025-05-21 04:24:21168 TestNavigationThrottle* test_throttle = new TestNavigationThrottle(
Takashi Toyoshima96a07bb2025-06-06 06:45:58169 *GetNavigationRequest()->GetNavigationThrottleRegistryForTesting());
Lucas Garron79e1a972017-10-04 22:25:06170 test_throttle->SetResponseForAllMethods(TestNavigationThrottle::SYNCHRONOUS,
171 result);
Hiroki Nakagawaadcffc502021-06-16 10:47:51172 GetNavigationRequest()->RegisterThrottleForTesting(
dcheng9bfa5162016-04-09 01:00:57173 std::unique_ptr<TestNavigationThrottle>(test_throttle));
clamy49678312015-10-22 21:59:00174 return test_throttle;
175 }
176
Lucas Garron0cedd962017-10-17 07:23:33177 // Creates, register and returns a TestNavigationThrottle that will
178 // synchronously return |result| on check for the given |method|, and
179 // NavigationThrottle::PROCEED otherwise.
180 TestNavigationThrottle* CreateTestNavigationThrottle(
181 TestNavigationThrottle::ThrottleMethod method,
182 NavigationThrottle::ThrottleCheckResult result) {
183 TestNavigationThrottle* test_throttle =
184 CreateTestNavigationThrottle(NavigationThrottle::PROCEED);
185 test_throttle->SetResponse(method, TestNavigationThrottle::SYNCHRONOUS,
186 result);
187 return test_throttle;
188 }
189
Mohamed Abdelhalim9ef43fc2019-04-05 13:09:43190 // TODO(zetamoo): Use NavigationSimulator instead of creating
191 // NavigationRequest and NavigationHandleImpl.
clamy1d4e78fd2017-07-11 12:59:19192 void CreateNavigationHandle() {
Minggang Wanga13c796e2021-07-02 05:54:43193 auto common_params = blink::CreateCommonNavigationParams();
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51194 common_params->initiator_origin =
Lukasz Anforowicz435bcb582019-07-12 20:50:06195 url::Origin::Create(GURL("https://initiator.example.com"));
Minggang Wanga13c796e2021-07-02 05:54:43196 auto commit_params = blink::CreateCommitNavigationParams();
arthursonzogni70ac7302020-05-28 08:49:05197 commit_params->frame_policy =
198 main_test_rfh()->frame_tree_node()->pending_frame_policy();
Hiroki Nakagawaadcffc502021-06-16 10:47:51199 auto request = NavigationRequest::CreateBrowserInitiated(
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51200 main_test_rfh()->frame_tree_node(), std::move(common_params),
Alex Moshchuk9321e6a2022-12-07 21:58:31201 std::move(commit_params), false /* was_opener_suppressed */,
John Delaney50425f82020-04-07 16:26:21202 std::string() /* extra_headers */, nullptr /* frame_entry */,
jongdeok.kim5de823b32022-06-14 04:37:50203 nullptr /* entry */, false /* is_form_submission */,
Arthur Sonzognic686e8f2024-01-11 08:36:37204 nullptr /* navigation_ui_data */, std::nullopt /* impression */,
Daniel Hosseinianf0fbfb42021-09-08 02:20:47205 false /* is_pdf */);
Charlie Reis09952ee2022-12-08 16:35:07206 main_test_rfh()->frame_tree_node()->TakeNavigationRequest(
Hiroki Nakagawaadcffc502021-06-16 10:47:51207 std::move(request));
208 GetNavigationRequest()->StartNavigation();
clamy1d4e78fd2017-07-11 12:59:19209 }
210
Yao Xiao6e1f7d32022-01-07 03:28:40211 FrameTreeNode* AddFrame(FrameTree& frame_tree,
212 RenderFrameHostImpl* parent,
213 int process_id,
214 int new_routing_id,
215 const blink::FramePolicy& frame_policy,
216 blink::FrameOwnerElementType owner_type) {
217 return frame_tree.AddFrame(
218 parent, process_id, new_routing_id,
219 TestRenderFrameHost::CreateStubFrameRemote(),
220 TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
221 TestRenderFrameHost::CreateStubPolicyContainerBindParams(),
Dominic Farolino12e06d72022-08-05 02:29:49222 TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
Yao Xiao6e1f7d32022-01-07 03:28:40223 blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
224 false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
Daniel Cheng284c38942022-09-22 23:30:34225 blink::DocumentToken(), frame_policy,
226 blink::mojom::FrameOwnerProperties(), false, owner_type,
Yao Xiao6e1f7d32022-01-07 03:28:40227 /*is_dummy_frame_for_inner_tree=*/false);
228 }
229
clamy49678312015-10-22 21:59:00230 private:
Mohamed Abdelhalimf03d4a22019-10-01 13:34:31231 // The callback provided to NavigationRequest::WillStartRequest,
232 // NavigationRequest::WillRedirectRequest, and
233 // NavigationRequest::WillFailRequest during the tests.
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:44234 bool UpdateThrottleCheckResult(
clamy49678312015-10-22 21:59:00235 NavigationThrottle::ThrottleCheckResult result) {
236 callback_result_ = result;
237 was_callback_called_ = true;
Mohamed Abdelhalim7e9e9c12019-11-26 13:48:44238 return true;
clamy49678312015-10-22 21:59:00239 }
240
Hiroki Nakagawaadcffc502021-06-16 10:47:51241 // This must be called after CreateNavigationHandle().
242 NavigationRequest* GetNavigationRequest() {
243 return main_test_rfh()->frame_tree_node()->navigation_request();
244 }
245
Fergal Dalya1d569972021-03-16 03:24:53246 bool was_callback_called_ = false;
clamy49678312015-10-22 21:59:00247 NavigationThrottle::ThrottleCheckResult callback_result_;
248};
249
carlosk489d9e22016-07-25 14:25:43250// Checks that the request_context_type is properly set.
251// Note: can be extended to cover more internal members.
Mohamed Abdelhalim1e8c5822019-08-02 11:45:43252TEST_F(NavigationRequestTest, SimpleDataChecksRedirectAndProcess) {
Camille Lamy62b826012019-02-26 09:15:47253 const GURL kUrl1 = GURL("http://chromium.org");
254 const GURL kUrl2 = GURL("http://google.com");
255 auto navigation =
256 NavigationSimulatorImpl::CreateRendererInitiated(kUrl1, main_rfh());
257 navigation->Start();
Harkiran Bolariaa2c9f79a2021-07-02 09:25:40258 EXPECT_EQ(blink::mojom::RequestContextType::LOCATION,
Mohamed Abdelhalim40c35d22019-09-19 15:59:05259 NavigationRequest::From(navigation->GetNavigationHandle())
260 ->request_context_type());
Tsuyoshi Horo3023b5d2023-11-28 21:40:31261 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Camille Lamy62b826012019-02-26 09:15:47262 navigation->GetNavigationHandle()->GetConnectionInfo());
carlosk489d9e22016-07-25 14:25:43263
Tsuyoshi Horo3023b5d2023-11-28 21:40:31264 navigation->set_http_connection_info(net::HttpConnectionInfo::kHTTP1_1);
Camille Lamy62b826012019-02-26 09:15:47265 navigation->Redirect(kUrl2);
Harkiran Bolariaa2c9f79a2021-07-02 09:25:40266 EXPECT_EQ(blink::mojom::RequestContextType::LOCATION,
Mohamed Abdelhalim40c35d22019-09-19 15:59:05267 NavigationRequest::From(navigation->GetNavigationHandle())
268 ->request_context_type());
Tsuyoshi Horo3023b5d2023-11-28 21:40:31269 EXPECT_EQ(net::HttpConnectionInfo::kHTTP1_1,
Camille Lamy62b826012019-02-26 09:15:47270 navigation->GetNavigationHandle()->GetConnectionInfo());
carlosk489d9e22016-07-25 14:25:43271
Tsuyoshi Horo3023b5d2023-11-28 21:40:31272 navigation->set_http_connection_info(net::HttpConnectionInfo::kQUIC_35);
Camille Lamy62b826012019-02-26 09:15:47273 navigation->ReadyToCommit();
Harkiran Bolariaa2c9f79a2021-07-02 09:25:40274 EXPECT_EQ(blink::mojom::RequestContextType::LOCATION,
Mohamed Abdelhalim40c35d22019-09-19 15:59:05275 NavigationRequest::From(navigation->GetNavigationHandle())
276 ->request_context_type());
Tsuyoshi Horo3023b5d2023-11-28 21:40:31277 EXPECT_EQ(net::HttpConnectionInfo::kQUIC_35,
Camille Lamy62b826012019-02-26 09:15:47278 navigation->GetNavigationHandle()->GetConnectionInfo());
jkarlinbb150112016-11-02 17:55:11279}
280
Mohamed Abdelhalim1e8c5822019-08-02 11:45:43281TEST_F(NavigationRequestTest, SimpleDataCheckNoRedirect) {
Camille Lamy62b826012019-02-26 09:15:47282 const GURL kUrl = GURL("http://chromium.org");
283 auto navigation =
284 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
285 navigation->Start();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31286 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Camille Lamy62b826012019-02-26 09:15:47287 navigation->GetNavigationHandle()->GetConnectionInfo());
jkarlinbb150112016-11-02 17:55:11288
Tsuyoshi Horo3023b5d2023-11-28 21:40:31289 navigation->set_http_connection_info(net::HttpConnectionInfo::kQUIC_35);
Camille Lamy62b826012019-02-26 09:15:47290 navigation->ReadyToCommit();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31291 EXPECT_EQ(net::HttpConnectionInfo::kQUIC_35,
Camille Lamy62b826012019-02-26 09:15:47292 navigation->GetNavigationHandle()->GetConnectionInfo());
carlosk489d9e22016-07-25 14:25:43293}
294
Mohamed Abdelhalim1e8c5822019-08-02 11:45:43295TEST_F(NavigationRequestTest, SimpleDataChecksFailure) {
Camille Lamy62b826012019-02-26 09:15:47296 const GURL kUrl = GURL("http://chromium.org");
297 auto navigation =
298 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
299 navigation->Start();
Harkiran Bolariaa2c9f79a2021-07-02 09:25:40300 EXPECT_EQ(blink::mojom::RequestContextType::LOCATION,
Mohamed Abdelhalim40c35d22019-09-19 15:59:05301 NavigationRequest::From(navigation->GetNavigationHandle())
302 ->request_context_type());
Tsuyoshi Horo3023b5d2023-11-28 21:40:31303 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Camille Lamy62b826012019-02-26 09:15:47304 navigation->GetNavigationHandle()->GetConnectionInfo());
Lucas Garron0cedd962017-10-17 07:23:33305
Camille Lamy62b826012019-02-26 09:15:47306 navigation->Fail(net::ERR_CERT_DATE_INVALID);
Harkiran Bolariaa2c9f79a2021-07-02 09:25:40307 EXPECT_EQ(blink::mojom::RequestContextType::LOCATION,
Mohamed Abdelhalim40c35d22019-09-19 15:59:05308 NavigationRequest::From(navigation->GetNavigationHandle())
309 ->request_context_type());
Camille Lamy62b826012019-02-26 09:15:47310 EXPECT_EQ(net::ERR_CERT_DATE_INVALID,
311 navigation->GetNavigationHandle()->GetNetErrorCode());
Lucas Garron0cedd962017-10-17 07:23:33312}
313
clamye88533842015-11-18 12:48:57314// Checks that a navigation deferred during WillStartRequest can be properly
315// cancelled.
Mohamed Abdelhalimba020672019-10-31 16:18:53316TEST_F(NavigationRequestTest, CancelDeferredWillStart) {
clamye88533842015-11-18 12:48:57317 TestNavigationThrottle* test_throttle =
318 CreateTestNavigationThrottle(NavigationThrottle::DEFER);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19319 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
Nate Chapin060cb952023-02-08 21:13:07320 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57321
322 // Simulate WillStartRequest. The request should be deferred. The callback
323 // should not have been called.
324 SimulateWillStartRequest();
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19325 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
clamye88533842015-11-18 12:48:57326 EXPECT_FALSE(was_callback_called());
Nate Chapin060cb952023-02-08 21:13:07327 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57328
329 // Cancel the request. The callback should have been called.
Charles Harrison4f2bf1a2017-07-18 20:21:21330 CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19331 EXPECT_EQ(NavigationRequest::CANCELING, state());
clamye88533842015-11-18 12:48:57332 EXPECT_TRUE(was_callback_called());
333 EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
Nate Chapin060cb952023-02-08 21:13:07334 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57335}
336
337// Checks that a navigation deferred during WillRedirectRequest can be properly
338// cancelled.
Mohamed Abdelhalimba020672019-10-31 16:18:53339TEST_F(NavigationRequestTest, CancelDeferredWillRedirect) {
clamye88533842015-11-18 12:48:57340 TestNavigationThrottle* test_throttle =
341 CreateTestNavigationThrottle(NavigationThrottle::DEFER);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19342 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
Nate Chapin060cb952023-02-08 21:13:07343 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57344
345 // Simulate WillRedirectRequest. The request should be deferred. The callback
346 // should not have been called.
347 SimulateWillRedirectRequest();
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19348 EXPECT_EQ(NavigationRequest::WILL_REDIRECT_REQUEST, state());
clamye88533842015-11-18 12:48:57349 EXPECT_FALSE(was_callback_called());
Nate Chapin060cb952023-02-08 21:13:07350 EXPECT_TRUE(call_counts_match(test_throttle, 0, 1, 0, 0, 0));
clamye88533842015-11-18 12:48:57351
352 // Cancel the request. The callback should have been called.
Charles Harrison4f2bf1a2017-07-18 20:21:21353 CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19354 EXPECT_EQ(NavigationRequest::CANCELING, state());
clamye88533842015-11-18 12:48:57355 EXPECT_TRUE(was_callback_called());
356 EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
Nate Chapin060cb952023-02-08 21:13:07357 EXPECT_TRUE(call_counts_match(test_throttle, 0, 1, 0, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33358}
359
360// Checks that a navigation deferred during WillFailRequest can be properly
361// cancelled.
Mohamed Abdelhalimba020672019-10-31 16:18:53362TEST_F(NavigationRequestTest, CancelDeferredWillFail) {
Lucas Garron0cedd962017-10-17 07:23:33363 TestNavigationThrottle* test_throttle = CreateTestNavigationThrottle(
364 TestNavigationThrottle::WILL_FAIL_REQUEST, NavigationThrottle::DEFER);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19365 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
Nate Chapin060cb952023-02-08 21:13:07366 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33367
368 // Simulate WillStartRequest.
369 SimulateWillStartRequest();
Nate Chapin060cb952023-02-08 21:13:07370 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33371
372 // Simulate WillFailRequest. The request should be deferred. The callback
373 // should not have been called.
374 SimulateWillFailRequest(net::ERR_CERT_DATE_INVALID);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19375 EXPECT_EQ(NavigationRequest::WILL_FAIL_REQUEST, state());
Lucas Garron0cedd962017-10-17 07:23:33376 EXPECT_FALSE(was_callback_called());
Nate Chapin060cb952023-02-08 21:13:07377 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33378
379 // Cancel the request. The callback should have been called.
380 CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19381 EXPECT_EQ(NavigationRequest::CANCELING, state());
Lucas Garron0cedd962017-10-17 07:23:33382 EXPECT_TRUE(was_callback_called());
383 EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
Nate Chapin060cb952023-02-08 21:13:07384 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
clamye88533842015-11-18 12:48:57385}
386
387// Checks that a navigation deferred can be canceled and not ignored.
Mohamed Abdelhalimba020672019-10-31 16:18:53388TEST_F(NavigationRequestTest, CancelDeferredWillRedirectNoIgnore) {
clamye88533842015-11-18 12:48:57389 TestNavigationThrottle* test_throttle =
390 CreateTestNavigationThrottle(NavigationThrottle::DEFER);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19391 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
Nate Chapin060cb952023-02-08 21:13:07392 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57393
Lucas Garron0cedd962017-10-17 07:23:33394 // Simulate WillStartRequest. The request should be deferred. The callback
clamye88533842015-11-18 12:48:57395 // should not have been called.
396 SimulateWillStartRequest();
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19397 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
Nate Chapin060cb952023-02-08 21:13:07398 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57399
400 // Cancel the request. The callback should have been called with CANCEL, and
401 // not CANCEL_AND_IGNORE.
Charles Harrison4f2bf1a2017-07-18 20:21:21402 CancelDeferredNavigation(NavigationThrottle::CANCEL);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19403 EXPECT_EQ(NavigationRequest::CANCELING, state());
clamye88533842015-11-18 12:48:57404 EXPECT_TRUE(was_callback_called());
405 EXPECT_EQ(NavigationThrottle::CANCEL, callback_result());
Nate Chapin060cb952023-02-08 21:13:07406 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
clamye88533842015-11-18 12:48:57407}
408
Lucas Garron0cedd962017-10-17 07:23:33409// Checks that a navigation deferred by WillFailRequest can be canceled and not
410// ignored.
Mohamed Abdelhalimba020672019-10-31 16:18:53411TEST_F(NavigationRequestTest, CancelDeferredWillFailNoIgnore) {
Lucas Garron0cedd962017-10-17 07:23:33412 TestNavigationThrottle* test_throttle = CreateTestNavigationThrottle(
413 TestNavigationThrottle::WILL_FAIL_REQUEST, NavigationThrottle::DEFER);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19414 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
Nate Chapin060cb952023-02-08 21:13:07415 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33416
417 // Simulate WillStartRequest.
418 SimulateWillStartRequest();
Nate Chapin060cb952023-02-08 21:13:07419 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33420
421 // Simulate WillFailRequest. The request should be deferred. The callback
422 // should not have been called.
423 SimulateWillFailRequest(net::ERR_CERT_DATE_INVALID);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19424 EXPECT_EQ(NavigationRequest::WILL_FAIL_REQUEST, state());
Lucas Garron0cedd962017-10-17 07:23:33425 EXPECT_FALSE(was_callback_called());
Nate Chapin060cb952023-02-08 21:13:07426 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
Lucas Garron0cedd962017-10-17 07:23:33427
428 // Cancel the request. The callback should have been called with CANCEL, and
429 // not CANCEL_AND_IGNORE.
430 CancelDeferredNavigation(NavigationThrottle::CANCEL);
Mohamed Abdelhalimb6f9f702019-11-06 17:23:19431 EXPECT_EQ(NavigationRequest::CANCELING, state());
Lucas Garron0cedd962017-10-17 07:23:33432 EXPECT_TRUE(was_callback_called());
433 EXPECT_EQ(NavigationThrottle::CANCEL, callback_result());
Nate Chapin060cb952023-02-08 21:13:07434 EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
435}
436
437// Checks that a navigation deferred during WillCommitWithoutUrlLoader can be
438// properly cancelled.
439TEST_F(NavigationRequestTest, CancelDeferredWillCommitWithoutUrlLoader) {
440 TestNavigationThrottle* test_throttle =
441 CreateTestNavigationThrottle(NavigationThrottle::DEFER);
442 EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
443 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
444
445 // Simulate WillCommitWithoutUrlLoader. The request should be deferred. The
446 // callback should not have been called.
447 SimulateWillCommitWithoutUrlLoader();
448 EXPECT_EQ(NavigationRequest::WILL_COMMIT_WITHOUT_URL_LOADER, state());
449 EXPECT_FALSE(was_callback_called());
450 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 1));
451
452 // Cancel the request. The callback should have been called.
453 CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
454 EXPECT_EQ(NavigationRequest::CANCELING, state());
455 EXPECT_TRUE(was_callback_called());
456 EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
457 EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 1));
Lucas Garron0cedd962017-10-17 07:23:33458}
459
Lucas Garronc1edb5ab2017-11-08 03:31:13460// Checks that data from the SSLInfo passed into SimulateWillStartRequest() is
John Abd-El-Malekf36e05f2017-11-30 16:17:52461// stored on the handle.
Mohamed Abdelhalim1e8c5822019-08-02 11:45:43462TEST_F(NavigationRequestTest, WillFailRequestSetsSSLInfo) {
Lucas Garronc1edb5ab2017-11-08 03:31:13463 uint16_t cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
464 int connection_status = 0;
465 net::SSLConnectionStatusSetCipherSuite(cipher_suite, &connection_status);
466
467 // Set some test values.
468 net::SSLInfo ssl_info;
469 ssl_info.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
470 ssl_info.connection_status = connection_status;
471
Camille Lamy62b826012019-02-26 09:15:47472 const GURL kUrl = GURL("https://chromium.org");
473 auto navigation =
474 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
Emily Starkfd6978ad12019-04-30 21:20:07475 navigation->SetSSLInfo(ssl_info);
Camille Lamy62b826012019-02-26 09:15:47476 navigation->Fail(net::ERR_CERT_DATE_INVALID);
Lucas Garronc1edb5ab2017-11-08 03:31:13477
478 EXPECT_EQ(net::CERT_STATUS_AUTHORITY_INVALID,
Camille Lamy62b826012019-02-26 09:15:47479 navigation->GetNavigationHandle()->GetSSLInfo()->cert_status);
480 EXPECT_EQ(connection_status,
481 navigation->GetNavigationHandle()->GetSSLInfo()->connection_status);
Lucas Garronc1edb5ab2017-11-08 03:31:13482}
483
Camillia Smith Barnes6d2966c82023-08-23 21:16:18484TEST_F(NavigationRequestTest, SharedStorageWritable) {
485 base::test::ScopedFeatureList feature_list;
486 feature_list.InitWithFeatures(
Sandor Majorf42e6bd62025-02-28 00:12:04487 /*enabled_features=*/{network::features::kSharedStorageAPI,
Camillia Smith Barnes6d2966c82023-08-23 21:16:18488 blink::features::kFencedFrames},
489 /*disabled_features=*/{});
490
491 // Create and start a simulated `NavigationRequest` for the main frame.
492 GURL main_url = GURL("https://main.com");
493 auto main_navigation =
494 NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
495 main_navigation->Start();
496 main_navigation->ReadyToCommit();
497
498 // Verify that the main frame's `NavigationRequest` will not be
499 // SharedStorageWritable.
500 ASSERT_TRUE(main_navigation->GetNavigationHandle());
Camillia Smith Barnes3cad1ba2023-10-30 20:10:16501 EXPECT_FALSE(main_navigation->GetNavigationHandle()
502 ->shared_storage_writable_eligible());
Camillia Smith Barnes6d2966c82023-08-23 21:16:18503
504 // Commit the navigation.
505 main_navigation->Commit();
506
507 // Append a child frame and set its `shared_storage_writable` attribute to
508 // true.
509 TestRenderFrameHost* child_frame = static_cast<TestRenderFrameHost*>(
510 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
511 blink::mojom::IframeAttributesPtr child_attributes =
512 blink::mojom::IframeAttributes::New();
Camillia Smith Barnesc267be62023-11-01 20:01:02513 child_attributes->shared_storage_writable_opted_in = true;
Camillia Smith Barnes6d2966c82023-08-23 21:16:18514 child_frame->frame_tree_node()->SetAttributes(std::move(child_attributes));
515
516 // Create and start a simulated `NavigationRequest` for the child frame.
517 GURL a_url = GURL("https://a.com");
518 auto child_navigation =
519 NavigationSimulatorImpl::CreateRendererInitiated(a_url, child_frame);
520 child_navigation->Start();
521
522 // Verify that the `NavigationRequest` will be SharedStorageWritable.
523 ASSERT_TRUE(child_navigation->GetNavigationHandle());
Camillia Smith Barnes3cad1ba2023-10-30 20:10:16524 EXPECT_TRUE(child_navigation->GetNavigationHandle()
525 ->shared_storage_writable_eligible());
Camillia Smith Barnes6d2966c82023-08-23 21:16:18526
527 // Commit the navigation.
528 child_navigation->Commit();
529
530 // Append a fenced frame and give it permission to access Shared Storage.
531 TestRenderFrameHost* fenced_frame_root = static_cast<TestRenderFrameHost*>(
532 content::RenderFrameHostTester::For(main_rfh())->AppendFencedFrame());
533 FrameTreeNode* fenced_frame_node =
534 static_cast<RenderFrameHostImpl*>(fenced_frame_root)->frame_tree_node();
Garrett Tanzer0698070f2023-12-12 19:48:20535 FencedFrameConfig new_config = FencedFrameConfig(GURL("about:blank"));
Garrett Tanzer3923f9d2023-12-15 16:54:34536 new_config.AddEffectiveEnabledPermissionForTesting(
Sandor «Alex» Majore9545a72025-01-31 20:40:46537 network::mojom::PermissionsPolicyFeature::kSharedStorage);
Garrett Tanzer0698070f2023-12-12 19:48:20538 FencedFrameProperties new_props = FencedFrameProperties(new_config);
Camillia Smith Barnes6d2966c82023-08-23 21:16:18539 fenced_frame_node->set_fenced_frame_properties(new_props);
Fergal Dalya6cfd112024-05-02 18:43:28540 fenced_frame_root->ResetPermissionsPolicy({});
Camillia Smith Barnes6d2966c82023-08-23 21:16:18541
542 // Append a child frame to the fenced frame root and set its
543 // `shared_storage_writable` attribute to true.
544 TestRenderFrameHost* child_of_fenced_frame =
545 static_cast<TestRenderFrameHost*>(
546 fenced_frame_root->AppendChild("child_of_fenced"));
547 blink::mojom::IframeAttributesPtr child_of_fenced_frame_attributes =
548 blink::mojom::IframeAttributes::New();
Camillia Smith Barnesc267be62023-11-01 20:01:02549 child_of_fenced_frame_attributes->shared_storage_writable_opted_in = true;
Camillia Smith Barnes6d2966c82023-08-23 21:16:18550 child_of_fenced_frame->frame_tree_node()->SetAttributes(
551 std::move(child_of_fenced_frame_attributes));
552
553 // Create and start a simulated `NavigationRequest` for the child frame.
554 GURL b_url = GURL("https://b.com");
555 auto child_of_fenced_frame_navigation =
556 NavigationSimulatorImpl::CreateRendererInitiated(b_url,
557 child_of_fenced_frame);
558 child_of_fenced_frame_navigation->Start();
559
560 // Verify that the `NavigationRequest` will be SharedStorageWritable.
561 ASSERT_TRUE(child_of_fenced_frame_navigation->GetNavigationHandle());
562 EXPECT_TRUE(child_of_fenced_frame_navigation->GetNavigationHandle()
Camillia Smith Barnes3cad1ba2023-10-30 20:10:16563 ->shared_storage_writable_eligible());
Camillia Smith Barnes6d2966c82023-08-23 21:16:18564
565 // Commit the navigation.
566 child_of_fenced_frame_navigation->Commit();
567}
568
Camille Lamy62b826012019-02-26 09:15:47569namespace {
570
Alex Moshchuk1a66b1d2018-05-15 21:18:26571// Helper throttle which checks that it can access NavigationHandle's
572// RenderFrameHost in WillFailRequest() and then defers the failure.
573class GetRenderFrameHostOnFailureNavigationThrottle
574 : public NavigationThrottle {
575 public:
Fergal Dalya1d569972021-03-16 03:24:53576 explicit GetRenderFrameHostOnFailureNavigationThrottle(
Takashi Toyoshima74e6ef302025-06-06 11:28:41577 NavigationThrottleRegistry& registry)
578 : NavigationThrottle(registry) {}
Peter Boström828b9022021-09-21 02:28:43579
580 GetRenderFrameHostOnFailureNavigationThrottle(
581 const GetRenderFrameHostOnFailureNavigationThrottle&) = delete;
582 GetRenderFrameHostOnFailureNavigationThrottle& operator=(
583 const GetRenderFrameHostOnFailureNavigationThrottle&) = delete;
584
Fergal Dalya1d569972021-03-16 03:24:53585 ~GetRenderFrameHostOnFailureNavigationThrottle() override = default;
Alex Moshchuk1a66b1d2018-05-15 21:18:26586
587 NavigationThrottle::ThrottleCheckResult WillFailRequest() override {
588 EXPECT_TRUE(navigation_handle()->GetRenderFrameHost());
589 return NavigationThrottle::DEFER;
590 }
591
592 const char* GetNameForLogging() override {
593 return "GetRenderFrameHostOnFailureNavigationThrottle";
594 }
Alex Moshchuk1a66b1d2018-05-15 21:18:26595};
596
Camille Lamy62b826012019-02-26 09:15:47597class ThrottleTestContentBrowserClient : public ContentBrowserClient {
Takashi Toyoshima2a7f8cc02025-05-07 07:58:46598 void CreateThrottlesForNavigation(
Takashi Toyoshimabe551532025-05-02 18:13:52599 NavigationThrottleRegistry& registry) override {
Takashi Toyoshimabe551532025-05-02 18:13:52600 registry.AddThrottle(
Camille Lamy62b826012019-02-26 09:15:47601 std::make_unique<GetRenderFrameHostOnFailureNavigationThrottle>(
Takashi Toyoshima74e6ef302025-06-06 11:28:41602 registry));
Camille Lamy62b826012019-02-26 09:15:47603 }
604};
605
606} // namespace
607
Alex Moshchuk1a66b1d2018-05-15 21:18:26608// Verify that the NavigationHandle::GetRenderFrameHost() can be retrieved by a
609// throttle in WillFailRequest(), as well as after deferring the failure. This
610// is allowed, since at that point the final RenderFrameHost will have already
611// been chosen. See https://crbug.com/817881.
Mohamed Abdelhalimba020672019-10-31 16:18:53612TEST_F(NavigationRequestTest, WillFailRequestCanAccessRenderFrameHost) {
Camille Lamy62b826012019-02-26 09:15:47613 std::unique_ptr<ContentBrowserClient> client(
614 new ThrottleTestContentBrowserClient);
615 ContentBrowserClient* old_browser_client =
616 SetBrowserClientForTesting(client.get());
617
618 const GURL kUrl = GURL("http://chromium.org");
619 auto navigation =
620 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
621 navigation->SetAutoAdvance(false);
622 navigation->Start();
623 navigation->Fail(net::ERR_CERT_DATE_INVALID);
Mohamed Abdelhalim3b235272019-11-05 15:06:07624 EXPECT_EQ(
625 NavigationRequest::WILL_FAIL_REQUEST,
626 NavigationRequest::From(navigation->GetNavigationHandle())->state());
Camille Lamy62b826012019-02-26 09:15:47627 EXPECT_TRUE(navigation->GetNavigationHandle()->GetRenderFrameHost());
Takashi Toyoshima71df91cb92025-07-08 09:48:00628 auto* registry = NavigationRequest::From(navigation->GetNavigationHandle())
629 ->GetNavigationThrottleRegistryForTesting();
630 ASSERT_EQ(1u, registry->GetDeferringThrottles().size());
631 registry->ResumeProcessingNavigationEvent(
632 *registry->GetDeferringThrottles().cbegin());
Camille Lamy62b826012019-02-26 09:15:47633 EXPECT_TRUE(navigation->GetNavigationHandle()->GetRenderFrameHost());
634
635 SetBrowserClientForTesting(old_browser_client);
Alex Moshchuk1a66b1d2018-05-15 21:18:26636}
637
Antonio Sartori3cfa3b62020-10-09 10:42:40638TEST_F(NavigationRequestTest, PolicyContainerInheritance) {
639 struct TestCase {
640 const char* url;
641 bool expect_inherit;
642 } cases[]{{"about:blank", true},
643 {"data:text/plain,hello", true},
644 {"file://local", false},
645 {"http://chromium.org", false}};
646
647 const GURL kUrl1 = GURL("http://chromium.org");
648 auto navigation =
649 NavigationSimulatorImpl::CreateRendererInitiated(kUrl1, main_rfh());
650 navigation->Commit();
651
652 for (auto test : cases) {
653 // We navigate child frames because the BlockedSchemeNavigationThrottle
654 // restricts navigations in the main frame.
655 auto* child_frame = static_cast<TestRenderFrameHost*>(
656 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
657
658 // We set the referrer policy of the frame to "always". We then create a new
659 // navigation, set as initiator the frame itself, start the navigation, and
660 // change the referrer policy of the frame to "never". After we commit the
661 // navigation:
662 // - If navigating to a local scheme, the target frame should have inherited
663 // the referrer policy of the initiator ("always").
664 // - If navigating to a non-local scheme, the target frame should have a new
665 // policy container (hence referrer policy set to "default").
666 const GURL kUrl = GURL(test.url);
Peter Kastingeb8c3ce2021-08-20 04:39:35667 navigation =
Antonio Sartori3cfa3b62020-10-09 10:42:40668 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, child_frame);
Antonio Sartori5b2f8042020-10-23 18:13:26669 static_cast<blink::mojom::PolicyContainerHost*>(
Antonio Sartori9290b6b2020-11-09 10:09:33670 child_frame->policy_container_host())
Antonio Sartori5b2f8042020-10-23 18:13:26671 ->SetReferrerPolicy(network::mojom::ReferrerPolicy::kAlways);
Antonio Sartori3cfa3b62020-10-09 10:42:40672 navigation->SetInitiatorFrame(child_frame);
673 navigation->Start();
Antonio Sartori5b2f8042020-10-23 18:13:26674 static_cast<blink::mojom::PolicyContainerHost*>(
Antonio Sartori9290b6b2020-11-09 10:09:33675 child_frame->policy_container_host())
Antonio Sartori5b2f8042020-10-23 18:13:26676 ->SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever);
Antonio Sartori3cfa3b62020-10-09 10:42:40677 navigation->Commit();
678 EXPECT_EQ(
679 test.expect_inherit ? network::mojom::ReferrerPolicy::kAlways
680 : network::mojom::ReferrerPolicy::kDefault,
681 static_cast<RenderFrameHostImpl*>(navigation->GetFinalRenderFrameHost())
Antonio Sartori9290b6b2020-11-09 10:09:33682 ->policy_container_host()
Antonio Sartori3cfa3b62020-10-09 10:42:40683 ->referrer_policy());
684 }
685}
686
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37687TEST_F(NavigationRequestTest, DnsAliasesCanBeAccessed) {
688 // Create simulated NavigationRequest for the URL, which has aliases.
689 const GURL kUrl = GURL("http://chromium.org");
690 auto navigation =
691 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
692 std::vector<std::string> dns_aliases({"alias1", "alias2"});
693 navigation->SetResponseDnsAliases(std::move(dns_aliases));
694
695 // Start the navigation.
696 navigation->Start();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31697 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37698 navigation->GetNavigationHandle()->GetConnectionInfo());
699
700 // Commit the navigation.
Tsuyoshi Horo3023b5d2023-11-28 21:40:31701 navigation->set_http_connection_info(net::HttpConnectionInfo::kQUIC_35);
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37702 navigation->ReadyToCommit();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31703 EXPECT_EQ(net::HttpConnectionInfo::kQUIC_35,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37704 navigation->GetNavigationHandle()->GetConnectionInfo());
705
706 // Verify that the aliases are accessible from the NavigationRequest.
707 EXPECT_THAT(navigation->GetNavigationHandle()->GetDnsAliases(),
708 testing::ElementsAre("alias1", "alias2"));
709}
710
711TEST_F(NavigationRequestTest, NoDnsAliases) {
712 // Create simulated NavigationRequest for the URL, which does not
713 // have aliases. (Note the empty alias list.)
714 const GURL kUrl = GURL("http://chromium.org");
715 auto navigation =
716 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
717 std::vector<std::string> dns_aliases;
718 navigation->SetResponseDnsAliases(std::move(dns_aliases));
719
720 // Start the navigation.
721 navigation->Start();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31722 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37723 navigation->GetNavigationHandle()->GetConnectionInfo());
724
725 // Commit the navigation.
Tsuyoshi Horo3023b5d2023-11-28 21:40:31726 navigation->set_http_connection_info(net::HttpConnectionInfo::kQUIC_35);
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37727 navigation->ReadyToCommit();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31728 EXPECT_EQ(net::HttpConnectionInfo::kQUIC_35,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37729 navigation->GetNavigationHandle()->GetConnectionInfo());
730
731 // Verify that there are no aliases in the NavigationRequest.
732 EXPECT_TRUE(navigation->GetNavigationHandle()->GetDnsAliases().empty());
733}
734
Antonio Sartori3e8de6d2021-07-26 10:28:41735TEST_F(NavigationRequestTest, StorageKeyToCommit) {
736 TestRenderFrameHost* child_document = static_cast<TestRenderFrameHost*>(
737 content::RenderFrameHostTester::For(main_rfh())->AppendChild(""));
Yuzu Saijo03dbf9b2022-07-22 04:29:45738 auto attributes = child_document->frame_tree_node()->attributes_->Clone();
Arthur Sonzogni64457592022-11-22 11:08:59739 attributes->credentialless = true;
Yuzu Saijo03dbf9b2022-07-22 04:29:45740 child_document->frame_tree_node()->SetAttributes(std::move(attributes));
Antonio Sartori3e8de6d2021-07-26 10:28:41741
742 const GURL kUrl = GURL("http://chromium.org");
743 auto navigation =
744 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, child_document);
745 navigation->ReadyToCommit();
746 NavigationRequest* request =
747 NavigationRequest::From(navigation->GetNavigationHandle());
748 EXPECT_TRUE(request->commit_params().storage_key.nonce().has_value());
Adithya Srinivasan4e0bb9642023-12-19 15:51:58749 EXPECT_EQ(child_document->GetPage().credentialless_iframes_nonce(),
Antonio Sartori3e8de6d2021-07-26 10:28:41750 request->commit_params().storage_key.nonce().value());
751
752 navigation->Commit();
753 child_document =
754 static_cast<TestRenderFrameHost*>(navigation->GetFinalRenderFrameHost());
Arthur Sonzogni64457592022-11-22 11:08:59755 EXPECT_TRUE(child_document->IsCredentialless());
Ari Chivukulad9e9c382023-02-15 23:30:09756 EXPECT_EQ(blink::StorageKey::CreateWithNonce(
Ali Hijazi78de14c2022-07-21 11:32:19757 url::Origin::Create(kUrl),
Adithya Srinivasan4e0bb9642023-12-19 15:51:58758 child_document->GetPage().credentialless_iframes_nonce()),
Mariam Ali8338d9fa2023-07-24 16:57:31759 child_document->GetStorageKey());
Antonio Sartori3e8de6d2021-07-26 10:28:41760}
761
sbingler4e4bd9b2023-02-27 19:56:53762// Test that the StorageKey's value is correctly affected by the
763// RuntimeFeatureStateContext.
764TEST_F(NavigationRequestTest, RuntimeFeatureStateStorageKey) {
765 base::test::ScopedFeatureList scoped_feature_list;
766 // Because the StorageKey's (and Storage Partitioning's) usage of
767 // RuntimeFeatureState is only meant to disable partitioning (i.e.:
768 // first-party only), we need the make sure the net::features is always
769 // enabled.
770 scoped_feature_list.InitAndEnableFeature(
771 net::features::kThirdPartyStoragePartitioning);
772
773 // This lambda performs the navigation and compares the commit_params'
774 // StorageKey against the passed in one. If `disable_sp` is true then it will
Ari Chivukula2b147362025-05-27 16:32:53775 // also enable the user bypass feature in the RFSC. It returns
sbingler4e4bd9b2023-02-27 19:56:53776 // the new TestRenderFrameHost* to the navigated frame.
777 auto NavigateAndCompareKeys =
778 [](NavigationSimulator* navigation, const blink::StorageKey& key,
779 bool disable_sp = false) -> TestRenderFrameHost* {
780 navigation->Start();
781
782 NavigationRequest* request =
783 NavigationRequest::From(navigation->GetNavigationHandle());
784
785 if (disable_sp) {
786 request->GetMutableRuntimeFeatureStateContext()
Ari Chivukula2b147362025-05-27 16:32:53787 .SetThirdPartyStoragePartitioningUserBypassEnabled(true);
sbingler4e4bd9b2023-02-27 19:56:53788 }
789
790 navigation->ReadyToCommit();
791
792 EXPECT_EQ(key, request->commit_params().storage_key);
793
794 navigation->Commit();
795 return static_cast<TestRenderFrameHost*>(
796 navigation->GetFinalRenderFrameHost());
797 };
798
799 // Throughout the test we'll be creating a frame tree with a main frame, a
800 // child frame, and a grandchild frame.
801 GURL main_url("https://main.com");
802 GURL b_url("https://b.com");
803 GURL c_url("https://c.com");
804
805 url::Origin main_origin = url::Origin::Create(main_url);
806 url::Origin b_origin = url::Origin::Create(b_url);
807 url::Origin c_origin = url::Origin::Create(c_url);
808
809 // Begin by testing with Storage Partitioning enabled.
810
811 auto main_navigation =
812 NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
813
814 // By definition the main frame's StorageKey will always be first party
815 blink::StorageKey main_frame_key =
816 blink::StorageKey::CreateFirstParty(main_origin);
817
818 NavigateAndCompareKeys(main_navigation.get(), main_frame_key);
819
820 TestRenderFrameHost* child_frame = static_cast<TestRenderFrameHost*>(
821 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
822
823 auto child_navigation =
824 NavigationSimulatorImpl::CreateRendererInitiated(b_url, child_frame);
825
826 // The child and grandchild should both be third-party keys.
827 blink::StorageKey child_frame_key =
828 blink::StorageKey::Create(b_origin, net::SchemefulSite(main_origin),
829 blink::mojom::AncestorChainBit::kCrossSite);
830
831 child_frame = NavigateAndCompareKeys(child_navigation.get(), child_frame_key);
832
833 TestRenderFrameHost* grandchild_frame =
834 child_frame->AppendChild("grandchild");
835
836 auto grandchild_navigation =
837 NavigationSimulatorImpl::CreateRendererInitiated(c_url, grandchild_frame);
838
839 blink::StorageKey grandchild_frame_key =
840 blink::StorageKey::Create(c_origin, net::SchemefulSite(main_origin),
841 blink::mojom::AncestorChainBit::kCrossSite);
842 grandchild_frame =
843 NavigateAndCompareKeys(grandchild_navigation.get(), grandchild_frame_key);
844
845 // Only the RuntimeFeatureStateContext in the main frame's matters. So
846 // disabling Storage Partitioning in the child_frame shouldn't affect the
847 // child's or the grandchild's StorageKey.
848 child_navigation =
849 NavigationSimulatorImpl::CreateRendererInitiated(b_url, child_frame);
850
851 child_frame = NavigateAndCompareKeys(child_navigation.get(), child_frame_key,
852 /*disable_sp=*/true);
853
854 grandchild_frame = child_frame->AppendChild("grandchild");
855
856 grandchild_navigation =
857 NavigationSimulatorImpl::CreateRendererInitiated(c_url, grandchild_frame);
858
859 grandchild_frame =
860 NavigateAndCompareKeys(grandchild_navigation.get(), grandchild_frame_key);
861
862 // Disabling Storage Partitioning on the main frame should cause the child's
863 // and grandchild's StorageKey to be first-party.
864 main_navigation =
865 NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
866
867 NavigateAndCompareKeys(main_navigation.get(), main_frame_key,
868 /*disable_sp=*/true);
869
870 child_frame = static_cast<TestRenderFrameHost*>(
871 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
872
873 child_navigation =
874 NavigationSimulatorImpl::CreateRendererInitiated(b_url, child_frame);
875
876 // The child and grandchild should both be first-party keys.
877 blink::StorageKey child_frame_key_1p =
878 blink::StorageKey::CreateFirstParty(b_origin);
879
880 child_frame =
881 NavigateAndCompareKeys(child_navigation.get(), child_frame_key_1p);
882
883 grandchild_frame = child_frame->AppendChild("grandchild");
884
885 blink::StorageKey grandchild_frame_key_1p =
886 blink::StorageKey::CreateFirstParty(c_origin);
887
888 grandchild_navigation =
889 NavigationSimulatorImpl::CreateRendererInitiated(c_url, grandchild_frame);
890
891 grandchild_frame = NavigateAndCompareKeys(grandchild_navigation.get(),
892 grandchild_frame_key_1p);
893}
894
Antonio Sartoribf27cc442021-08-25 13:08:23895TEST_F(NavigationRequestTest,
Arthur Sonzogni64457592022-11-22 11:08:59896 NavigationToCredentiallessDocumentNetworkIsolationInfo) {
Antonio Sartoribf27cc442021-08-25 13:08:23897 auto* child_frame = static_cast<TestRenderFrameHost*>(
898 content::RenderFrameHostTester::For(main_test_rfh())
899 ->AppendChild("child"));
Yuzu Saijo03dbf9b2022-07-22 04:29:45900 auto attributes = child_frame->frame_tree_node()->attributes_->Clone();
Arthur Sonzogni64457592022-11-22 11:08:59901 attributes->credentialless = true;
Yuzu Saijo03dbf9b2022-07-22 04:29:45902 child_frame->frame_tree_node()->SetAttributes(std::move(attributes));
Antonio Sartoribf27cc442021-08-25 13:08:23903
904 std::unique_ptr<NavigationSimulator> navigation =
905 NavigationSimulator::CreateRendererInitiated(
906 GURL("https://example.com/navigation.html"), child_frame);
907 navigation->ReadyToCommit();
908
Adithya Srinivasan4e0bb9642023-12-19 15:51:58909 EXPECT_EQ(main_test_rfh()->GetPage().credentialless_iframes_nonce(),
Antonio Sartoribf27cc442021-08-25 13:08:23910 static_cast<NavigationRequest*>(navigation->GetNavigationHandle())
911 ->isolation_info_for_subresources()
912 .network_isolation_key()
913 .GetNonce());
Adithya Srinivasan4e0bb9642023-12-19 15:51:58914 EXPECT_EQ(main_test_rfh()->GetPage().credentialless_iframes_nonce(),
Antonio Sartoribf27cc442021-08-25 13:08:23915 static_cast<NavigationRequest*>(navigation->GetNavigationHandle())
916 ->GetIsolationInfo()
917 .network_isolation_key()
918 .GetNonce());
919}
920
Yifan Luob5c352b2023-10-30 11:22:10921TEST_F(NavigationRequestTest, UpdatePrivateNetworkRequestPolicy) {
922 std::unique_ptr<NavigationSimulator> navigation =
923 NavigationSimulator::CreateRendererInitiated(GURL("https://example.com/"),
924 main_test_rfh());
925 navigation->SetSocketAddress(net::IPEndPoint());
926
927 navigation->ReadyToCommit();
928 NavigationRequest* request =
929 NavigationRequest::From(navigation->GetNavigationHandle());
930 EXPECT_FALSE(request->GetSocketAddress().address().IsValid());
931 navigation->Commit();
932}
933
Nasko Oskov32f95892025-06-02 20:45:08934// Test to ensure that the SanitizeRedirectsForCommit method correctly removes
935// the query parameters parts of the URL that can contain sensitive information.
936TEST_F(NavigationRequestTest, SanitizeRedirectsForCommit) {
937 const GURL start_url("https://a.com?param=1");
938 const GURL url_2("https://b.com?param=2#foo");
939 const GURL url_3("https://c.com?param=3");
940 const GURL final_url("https://d.com?param=4");
941 std::unique_ptr<NavigationSimulator> navigation =
942 NavigationSimulator::CreateRendererInitiated(start_url, main_test_rfh());
943 navigation->Start();
944 navigation->Redirect(url_2);
945 navigation->Redirect(url_3);
946 navigation->Redirect(final_url);
947
948 NavigationRequest* request =
949 NavigationRequest::From(navigation->GetNavigationHandle());
950 auto commit_params = request->commit_params().Clone();
951 request->SanitizeRedirectsForCommit(commit_params);
952
953 // redirect_infos contains entries for B, C, and D, but not the starting URL.
954 // Ensure that the full URL for D is preserved.
955 EXPECT_EQ(3, commit_params->redirect_infos.size());
956 EXPECT_EQ(GURL("https://b.com"), commit_params->redirect_infos[0].new_url);
957 EXPECT_EQ(GURL("https://c.com"), commit_params->redirect_infos[1].new_url);
958 EXPECT_EQ(final_url, commit_params->redirect_infos[2].new_url);
959
960 // In contrast, redirects contains A, B, and C (i.e., the starting URL but not
961 // the final URL).
962 EXPECT_EQ(3, commit_params->redirects.size());
963 EXPECT_EQ(GURL("https://a.com"), commit_params->redirects[0]);
964 EXPECT_EQ(GURL("https://b.com"), commit_params->redirects[1]);
965 EXPECT_EQ(GURL("https://c.com"), commit_params->redirects[2]);
966}
967
arthursonzogni898dcda52021-01-21 08:50:10968// Test that the required CSP of every frame is computed/inherited correctly and
969// that the Sec-Required-CSP header is set.
970class CSPEmbeddedEnforcementUnitTest : public NavigationRequestTest {
971 protected:
972 TestRenderFrameHost* main_rfh() {
973 return static_cast<TestRenderFrameHost*>(NavigationRequestTest::main_rfh());
974 }
975
976 // Simulate the |csp| attribute being set in |rfh|'s frame. Then navigate it.
977 // Returns the request's Sec-Required-CSP header.
978 std::string NavigateWithRequiredCSP(TestRenderFrameHost** rfh,
979 std::string required_csp) {
980 TestRenderFrameHost* document = *rfh;
981
982 if (!required_csp.empty()) {
983 auto headers =
984 base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
985 headers->SetHeader("Content-Security-Policy", required_csp);
986 std::vector<network::mojom::ContentSecurityPolicyPtr> policies;
987 network::AddContentSecurityPolicyFromHeaders(
988 *headers, GURL("https://example.com/"), &policies);
Yuzu Saijo03dbf9b2022-07-22 04:29:45989 auto attributes = document->frame_tree_node()->attributes_->Clone();
990 // Set csp value.
991 attributes->parsed_csp_attribute = std::move(policies[0]);
992 document->frame_tree_node()->SetAttributes(std::move(attributes));
arthursonzogni898dcda52021-01-21 08:50:10993 }
994
995 // Chrome blocks a document navigating to a URL if more than one of its
996 // ancestors have the same URL. Use a different URL every time, to
997 // avoid blocking navigation of the grandchild frame.
998 static int nonce = 0;
999 GURL url("https://www.example.com" + base::NumberToString(nonce++));
1000
1001 auto navigation =
1002 content::NavigationSimulator::CreateRendererInitiated(url, *rfh);
1003 navigation->Start();
1004 NavigationRequest* request =
1005 NavigationRequest::From(navigation->GetNavigationHandle());
Chris Fredricksonfb77b04d2024-08-02 18:54:581006 std::string sec_required_csp = request->GetRequestHeaders()
1007 .GetHeader("sec-required-csp")
1008 .value_or(std::string());
arthursonzogni898dcda52021-01-21 08:50:101009
1010 // Complete the navigation so that the required csp is stored in the
1011 // RenderFrameHost, so that when we will add children to this document they
1012 // will be able to get the parent's required csp (and hence also test that
1013 // the whole logic works).
1014 auto response_headers =
1015 base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
1016 response_headers->SetHeader("Allow-CSP-From", "*");
1017 navigation->SetResponseHeaders(response_headers);
1018 navigation->Commit();
1019
1020 *rfh = static_cast<TestRenderFrameHost*>(
1021 navigation->GetFinalRenderFrameHost());
1022
1023 return sec_required_csp;
1024 }
1025
1026 TestRenderFrameHost* AddChild(TestRenderFrameHost* parent) {
1027 return static_cast<TestRenderFrameHost*>(
1028 content::RenderFrameHostTester::For(parent)->AppendChild(""));
1029 }
1030};
1031
1032TEST_F(CSPEmbeddedEnforcementUnitTest, TopLevel) {
1033 TestRenderFrameHost* top_document = main_rfh();
1034 std::string sec_required_csp = NavigateWithRequiredCSP(&top_document, "");
1035 EXPECT_EQ("", sec_required_csp);
1036 EXPECT_FALSE(top_document->required_csp());
1037}
1038
1039TEST_F(CSPEmbeddedEnforcementUnitTest, ChildNoCSP) {
1040 TestRenderFrameHost* top_document = main_rfh();
1041 TestRenderFrameHost* child_document = AddChild(top_document);
1042 std::string sec_required_csp = NavigateWithRequiredCSP(&child_document, "");
1043 EXPECT_EQ("", sec_required_csp);
1044 EXPECT_FALSE(child_document->required_csp());
1045}
1046
1047TEST_F(CSPEmbeddedEnforcementUnitTest, ChildWithCSP) {
1048 TestRenderFrameHost* top_document = main_rfh();
1049 TestRenderFrameHost* child_document = AddChild(top_document);
1050 std::string sec_required_csp =
1051 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1052 EXPECT_EQ("script-src 'none'", sec_required_csp);
1053 EXPECT_TRUE(child_document->required_csp());
1054 EXPECT_EQ("script-src 'none'",
1055 child_document->required_csp()->header->header_value);
1056}
1057
1058TEST_F(CSPEmbeddedEnforcementUnitTest, ChildSiblingNoCSP) {
1059 TestRenderFrameHost* top_document = main_rfh();
1060 TestRenderFrameHost* child_document = AddChild(top_document);
1061 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1062 TestRenderFrameHost* sibling_document = AddChild(top_document);
1063 std::string sec_required_csp = NavigateWithRequiredCSP(&sibling_document, "");
1064 EXPECT_FALSE(sibling_document->required_csp());
1065}
1066
1067TEST_F(CSPEmbeddedEnforcementUnitTest, ChildSiblingCSP) {
1068 TestRenderFrameHost* top_document = main_rfh();
1069 TestRenderFrameHost* child_document = AddChild(top_document);
1070 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1071 TestRenderFrameHost* sibling_document = AddChild(top_document);
1072 std::string sec_required_csp =
1073 NavigateWithRequiredCSP(&sibling_document, "script-src 'none'");
1074 EXPECT_EQ("script-src 'none'", sec_required_csp);
1075 EXPECT_TRUE(sibling_document->required_csp());
1076 EXPECT_EQ("script-src 'none'",
1077 sibling_document->required_csp()->header->header_value);
1078}
1079
1080TEST_F(CSPEmbeddedEnforcementUnitTest, GrandChildNoCSP) {
1081 TestRenderFrameHost* top_document = main_rfh();
1082 TestRenderFrameHost* child_document = AddChild(top_document);
1083 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1084 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1085 std::string sec_required_csp =
1086 NavigateWithRequiredCSP(&grand_child_document, "");
1087 EXPECT_EQ("script-src 'none'", sec_required_csp);
1088 EXPECT_TRUE(grand_child_document->required_csp());
1089 EXPECT_EQ("script-src 'none'",
1090 grand_child_document->required_csp()->header->header_value);
1091}
1092
1093TEST_F(CSPEmbeddedEnforcementUnitTest, GrandChildSameCSP) {
1094 TestRenderFrameHost* top_document = main_rfh();
1095 TestRenderFrameHost* child_document = AddChild(top_document);
1096 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1097 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1098 std::string sec_required_csp =
1099 NavigateWithRequiredCSP(&grand_child_document, "script-src 'none'");
1100 EXPECT_EQ("script-src 'none'", sec_required_csp);
1101 EXPECT_TRUE(grand_child_document->required_csp());
1102 EXPECT_EQ("script-src 'none'",
1103 grand_child_document->required_csp()->header->header_value);
1104}
1105
1106TEST_F(CSPEmbeddedEnforcementUnitTest, GrandChildDifferentCSP) {
1107 TestRenderFrameHost* top_document = main_rfh();
1108 TestRenderFrameHost* child_document = AddChild(top_document);
1109 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1110 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1111 std::string sec_required_csp =
1112 NavigateWithRequiredCSP(&grand_child_document, "img-src 'none'");
1113
1114 // This seems weird, but it is the intended behaviour according to the spec.
1115 // The problem is that "script-src 'none'" does not subsume "img-src 'none'",
1116 // so "img-src 'none'" on the grandchild is an invalid csp attribute, and we
1117 // just discard it in favour of the parent's csp attribute.
1118 //
1119 // This should probably be fixed in the specification:
1120 // https://github.com/w3c/webappsec-cspee/pull/11
1121 EXPECT_EQ("script-src 'none'", sec_required_csp);
1122 EXPECT_TRUE(grand_child_document->required_csp());
1123 EXPECT_EQ("script-src 'none'",
1124 grand_child_document->required_csp()->header->header_value);
1125}
1126
1127TEST_F(CSPEmbeddedEnforcementUnitTest, InvalidCSP) {
1128 TestRenderFrameHost* top_document = main_rfh();
1129 TestRenderFrameHost* child_document = AddChild(top_document);
1130 std::string sec_required_csp =
1131 NavigateWithRequiredCSP(&child_document, "report-to group");
1132 EXPECT_EQ("", sec_required_csp);
1133 EXPECT_FALSE(child_document->required_csp());
1134}
1135
1136TEST_F(CSPEmbeddedEnforcementUnitTest, InvalidCspAndInheritFromParent) {
1137 TestRenderFrameHost* top_document = main_rfh();
1138 TestRenderFrameHost* child_document = AddChild(top_document);
1139 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1140 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1141 std::string sec_required_csp =
Antonio Sartori4231e932021-02-04 12:01:141142 NavigateWithRequiredCSP(&grand_child_document, "report-to group");
arthursonzogni898dcda52021-01-21 08:50:101143 EXPECT_EQ("script-src 'none'", sec_required_csp);
1144 EXPECT_TRUE(grand_child_document->required_csp());
1145 EXPECT_EQ("script-src 'none'",
1146 grand_child_document->required_csp()->header->header_value);
1147}
1148
1149TEST_F(CSPEmbeddedEnforcementUnitTest,
1150 SemiInvalidCspAndInheritSameCspFromParent) {
1151 TestRenderFrameHost* top_document = main_rfh();
1152 TestRenderFrameHost* child_document = AddChild(top_document);
1153 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1154 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1155 std::string sec_required_csp = NavigateWithRequiredCSP(
Antonio Sartori4231e932021-02-04 12:01:141156 &grand_child_document, "script-src 'none'; report-to group");
arthursonzogni898dcda52021-01-21 08:50:101157 EXPECT_EQ("script-src 'none'", sec_required_csp);
1158 EXPECT_TRUE(grand_child_document->required_csp());
1159 EXPECT_EQ("script-src 'none'",
1160 grand_child_document->required_csp()->header->header_value);
1161}
1162
1163TEST_F(CSPEmbeddedEnforcementUnitTest,
1164 SemiInvalidCspAndInheritDifferentCspFromParent) {
1165 TestRenderFrameHost* top_document = main_rfh();
1166 TestRenderFrameHost* child_document = AddChild(top_document);
1167 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1168 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1169 std::string sec_required_csp = NavigateWithRequiredCSP(
Antonio Sartori4231e932021-02-04 12:01:141170 &grand_child_document, "sandbox; report-to group");
arthursonzogni898dcda52021-01-21 08:50:101171 EXPECT_EQ("script-src 'none'", sec_required_csp);
1172 EXPECT_TRUE(grand_child_document->required_csp());
1173 EXPECT_EQ("script-src 'none'",
1174 grand_child_document->required_csp()->header->header_value);
1175}
1176
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301177namespace {
1178
1179// Mock that allows us to avoid depending on the origin_trials component.
1180class OriginTrialsControllerDelegateMock
1181 : public OriginTrialsControllerDelegate {
1182 public:
1183 ~OriginTrialsControllerDelegateMock() override = default;
1184
1185 void PersistTrialsFromTokens(
1186 const url::Origin& origin,
Peter Birk Pakkenbergf62286a2023-01-25 19:44:071187 const url::Origin& partition_origin,
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301188 const base::span<const std::string> header_tokens,
Svend Larsen113ac5b2024-06-05 20:56:201189 const base::Time current_time,
1190 std::optional<ukm::SourceId> source_id) override {
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301191 persisted_tokens_[origin] =
1192 std::vector<std::string>(header_tokens.begin(), header_tokens.end());
1193 }
Peter Birk Pakkenberg582edfc2023-02-27 11:22:121194 void PersistAdditionalTrialsFromTokens(
1195 const url::Origin& origin,
1196 const url::Origin& partition_origin,
1197 const base::span<const url::Origin> script_origins,
1198 const base::span<const std::string> header_tokens,
Svend Larsen113ac5b2024-06-05 20:56:201199 const base::Time current_time,
1200 std::optional<ukm::SourceId> source_id) override {
Peter Boströmfc7ddc182024-10-31 19:37:211201 NOTREACHED() << "not used by test";
Peter Birk Pakkenberg582edfc2023-02-27 11:22:121202 }
Peter Birk Pakkenberg36b79c912023-05-25 08:38:241203 bool IsFeaturePersistedForOrigin(const url::Origin& origin,
1204 const url::Origin& partition_origin,
Yao Xiao5c6e1fa2023-10-04 19:12:221205 blink::mojom::OriginTrialFeature feature,
Peter Birk Pakkenberg36b79c912023-05-25 08:38:241206 const base::Time current_time) override {
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301207 DCHECK(false) << "Method not implemented for test.";
1208 return false;
1209 }
1210
Peter Birk Pakkenberg4c1bb272022-09-27 10:51:291211 base::flat_set<std::string> GetPersistedTrialsForOrigin(
1212 const url::Origin& origin,
Peter Birk Pakkenbergf62286a2023-01-25 19:44:071213 const url::Origin& partition_origin,
Peter Birk Pakkenberg4c1bb272022-09-27 10:51:291214 base::Time current_time) override {
1215 DCHECK(false) << "Method not implemented for test.";
1216 return base::flat_set<std::string>();
1217 }
1218
Peter Birk Pakkenbergd74c6f82022-11-08 17:44:381219 void ClearPersistedTokens() override { persisted_tokens_.clear(); }
1220
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301221 base::flat_map<url::Origin, std::vector<std::string>> persisted_tokens_;
1222};
1223
1224} // namespace
1225
1226class PersistentOriginTrialNavigationRequestTest
1227 : public NavigationRequestTest {
1228 public:
1229 PersistentOriginTrialNavigationRequestTest()
1230 : delegate_mock_(std::make_unique<OriginTrialsControllerDelegateMock>()) {
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301231 }
1232 ~PersistentOriginTrialNavigationRequestTest() override = default;
1233
1234 std::vector<std::string> GetPersistedTokens(const url::Origin& origin) {
1235 return delegate_mock_->persisted_tokens_[origin];
1236 }
1237
1238 protected:
1239 std::unique_ptr<BrowserContext> CreateBrowserContext() override {
1240 std::unique_ptr<TestBrowserContext> context =
1241 std::make_unique<TestBrowserContext>();
1242 context->SetOriginTrialsControllerDelegate(delegate_mock_.get());
1243 return context;
1244 }
1245
1246 private:
1247 std::unique_ptr<OriginTrialsControllerDelegateMock> delegate_mock_;
1248};
1249
1250// Ensure that navigations with a valid Origin-Trial header with a persistent
1251// origin trial token results in the trial being marked as enabled.
1252// Then check that subsequent navigations without headers trigger an update
1253// that clears out stored trials.
1254TEST_F(PersistentOriginTrialNavigationRequestTest,
1255 NavigationCommitsPersistentOriginTrials) {
1256 // Generated with:
1257 // tools/origin_trials/generate_token.py https://example.com
1258 // FrobulatePersistent
1259 // --expire-timestamp=2000000000
1260 const char kPersistentOriginTrialToken[] =
1261 "AzZfd1vKZ0SSGRGk/"
1262 "8nIszQSlHYjbuYVE3jwaNZG3X4t11zRhzPWWJwTZ+JJDS3JJsyEZcpz+y20pAP6/"
1263 "6upOQ4AAABdeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZ"
1264 "SI"
1265 "6ICJGcm9idWxhdGVQZXJzaXN0ZW50IiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9";
1266
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301267 blink::ScopedTestOriginTrialPolicy origin_trial_policy_;
1268
1269 const GURL kUrl = GURL("https://example.com");
1270 auto navigation =
1271 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
1272
1273 auto response_headers =
1274 base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
1275 response_headers->SetHeader("Origin-Trial", kPersistentOriginTrialToken);
1276 navigation->SetResponseHeaders(response_headers);
1277
1278 navigation->Commit();
1279
1280 url::Origin origin = url::Origin::Create(kUrl);
1281 EXPECT_EQ(std::vector<std::string>{kPersistentOriginTrialToken},
1282 GetPersistedTokens(origin));
1283
1284 // Navigate again without response headers to assert the trial information is
1285 // still updated and cleared.
1286 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh())->Commit();
1287 EXPECT_EQ(std::vector<std::string>(), GetPersistedTokens(origin));
1288}
1289
Igor Ruvinovdcb81982023-06-21 22:22:171290namespace {
1291
1292// Test version of a NavigationThrottle that requests the response body.
1293class ResponseBodyNavigationThrottle : public NavigationThrottle {
1294 public:
1295 using ResponseBodyCallback = base::OnceCallback<void(const std::string&)>;
1296
Takashi Toyoshima74e6ef302025-06-06 11:28:411297 ResponseBodyNavigationThrottle(NavigationThrottleRegistry& registry,
Igor Ruvinovdcb81982023-06-21 22:22:171298 ResponseBodyCallback callback)
Takashi Toyoshima74e6ef302025-06-06 11:28:411299 : NavigationThrottle(registry), callback_(std::move(callback)) {}
Igor Ruvinovdcb81982023-06-21 22:22:171300 ResponseBodyNavigationThrottle(const ResponseBodyNavigationThrottle&) =
1301 delete;
1302 ResponseBodyNavigationThrottle& operator=(
1303 const ResponseBodyNavigationThrottle&) = delete;
1304 ~ResponseBodyNavigationThrottle() override = default;
1305
1306 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
1307 navigation_handle()->GetResponseBody(
1308 base::BindOnce(&ResponseBodyNavigationThrottle::OnResponseBodyReady,
1309 base::Unretained(this)));
1310 return NavigationThrottle::DEFER;
1311 }
1312
1313 const char* GetNameForLogging() override {
1314 return "ResponseBodyNavigationThrottle";
1315 }
1316
1317 private:
1318 void OnResponseBodyReady(const std::string& response_body) {
1319 std::move(callback_).Run(response_body);
1320 NavigationRequest::From(navigation_handle())
Takashi Toyoshimacc4d947f2025-06-24 08:38:341321 ->GetNavigationThrottleRegistryForTesting()
Takashi Toyoshima71df91cb92025-07-08 09:48:001322 ->ResumeProcessingNavigationEvent(this);
Igor Ruvinovdcb81982023-06-21 22:22:171323 }
1324
1325 ResponseBodyCallback callback_;
1326};
1327
1328} // namespace
1329
1330// Tests response body.
1331class NavigationRequestResponseBodyTest : public NavigationRequestTest {
1332 public:
1333 std::unique_ptr<NavigationSimulator> CreateNavigationSimulator() {
1334 auto navigation = NavigationSimulatorImpl::CreateRendererInitiated(
1335 GURL("http://example.test"), main_rfh());
1336 navigation->SetAutoAdvance(false);
1337 navigation->Start();
1338 // It is safe to use base::Unretained as the NavigationThrottle will not be
1339 // destroyed before the callback is called.
Takashi Toyoshima74e6ef302025-06-06 11:28:411340 auto& registry = navigation->GetNavigationThrottleRegistry();
Igor Ruvinovdcb81982023-06-21 22:22:171341 auto throttle = std::make_unique<ResponseBodyNavigationThrottle>(
Takashi Toyoshima74e6ef302025-06-06 11:28:411342 registry,
Igor Ruvinovdcb81982023-06-21 22:22:171343 base::BindOnce(&NavigationRequestResponseBodyTest::UpdateResponseBody,
1344 base::Unretained(this)));
Takashi Toyoshima74e6ef302025-06-06 11:28:411345 registry.AddThrottle(std::move(throttle));
Igor Ruvinovdcb81982023-06-21 22:22:171346 return navigation;
1347 }
1348
1349 void UpdateResponseBody(const std::string& response_body) {
1350 response_body_ = response_body;
1351 was_callback_called_ = true;
1352 }
1353
1354 bool was_callback_called() const { return was_callback_called_; }
1355
1356 const std::string& response_body() const { return response_body_; }
1357
1358 protected:
1359 mojo::ScopedDataPipeProducerHandle producer_handle_;
1360 mojo::ScopedDataPipeConsumerHandle consumer_handle_;
1361
1362 private:
1363 bool was_callback_called_ = false;
1364 std::string response_body_;
1365};
1366
1367TEST_F(NavigationRequestResponseBodyTest, Received) {
1368 auto navigation = CreateNavigationSimulator();
1369 std::string response = "response-body-content";
Lukasz Anforowicz2a672e32024-06-14 17:27:491370 ASSERT_EQ(MOJO_RESULT_OK,
1371 mojo::CreateDataPipe(response.size(), producer_handle_,
1372 consumer_handle_));
Igor Ruvinovdcb81982023-06-21 22:22:171373 navigation->SetResponseBody(std::move(consumer_handle_));
1374
1375 navigation->ReadyToCommit();
1376 EXPECT_EQ(
1377 NavigationRequest::WILL_PROCESS_RESPONSE,
1378 NavigationRequest::From(navigation->GetNavigationHandle())->state());
1379 EXPECT_FALSE(was_callback_called());
1380 EXPECT_EQ(std::string(), response_body());
1381
Lukasz Anforowicz2a672e32024-06-14 17:27:491382 size_t actually_written_bytes = 0;
Igor Ruvinovdcb81982023-06-21 22:22:171383 ASSERT_EQ(MOJO_RESULT_OK,
Lukasz Anforowicz2a672e32024-06-14 17:27:491384 producer_handle_->WriteData(base::as_byte_span(response),
1385 MOJO_WRITE_DATA_FLAG_NONE,
1386 actually_written_bytes));
1387 EXPECT_EQ(actually_written_bytes, response.size());
Igor Ruvinovdcb81982023-06-21 22:22:171388
1389 navigation->Wait();
1390 EXPECT_EQ(
1391 NavigationRequest::READY_TO_COMMIT,
1392 NavigationRequest::From(navigation->GetNavigationHandle())->state());
1393 EXPECT_TRUE(was_callback_called());
1394 EXPECT_EQ(response, response_body());
1395}
1396
1397TEST_F(NavigationRequestResponseBodyTest, PartiallyReceived) {
1398 auto navigation = CreateNavigationSimulator();
1399
1400 // The data pipe size is smaller than the response body size.
1401 uint32_t pipe_size = 8u;
1402 ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(pipe_size, producer_handle_,
1403 consumer_handle_));
1404 navigation->SetResponseBody(std::move(consumer_handle_));
1405
1406 navigation->ReadyToCommit();
1407 EXPECT_EQ(
1408 NavigationRequest::WILL_PROCESS_RESPONSE,
1409 NavigationRequest::From(navigation->GetNavigationHandle())->state());
1410 EXPECT_FALSE(was_callback_called());
1411 EXPECT_EQ(std::string(), response_body());
1412
1413 std::string response = "response-body-content";
Lukasz Anforowicz2a672e32024-06-14 17:27:491414 size_t actually_written_bytes = 0;
Igor Ruvinovdcb81982023-06-21 22:22:171415 ASSERT_EQ(MOJO_RESULT_OK,
Lukasz Anforowicz2a672e32024-06-14 17:27:491416 producer_handle_->WriteData(base::as_byte_span(response),
1417 MOJO_WRITE_DATA_FLAG_NONE,
1418 actually_written_bytes));
1419 EXPECT_EQ(actually_written_bytes, pipe_size);
Igor Ruvinovdcb81982023-06-21 22:22:171420
1421 navigation->Wait();
1422 EXPECT_EQ(
1423 NavigationRequest::READY_TO_COMMIT,
1424 NavigationRequest::From(navigation->GetNavigationHandle())->state());
1425 EXPECT_TRUE(was_callback_called());
1426 // Only the first part of the response body that fits in the pipe is received.
1427 EXPECT_EQ("response", response_body());
1428}
1429
1430TEST_F(NavigationRequestResponseBodyTest, PipeClosed) {
1431 auto navigation = CreateNavigationSimulator();
1432 ASSERT_EQ(MOJO_RESULT_OK,
1433 mojo::CreateDataPipe(10u, producer_handle_, consumer_handle_));
1434 navigation->SetResponseBody(std::move(consumer_handle_));
1435 navigation->ReadyToCommit();
1436 EXPECT_EQ(
1437 NavigationRequest::WILL_PROCESS_RESPONSE,
1438 NavigationRequest::From(navigation->GetNavigationHandle())->state());
1439 EXPECT_FALSE(was_callback_called());
1440 EXPECT_EQ(std::string(), response_body());
1441
1442 // Close the pipe before any data is sent.
1443 producer_handle_.reset();
1444 navigation->Wait();
1445 EXPECT_EQ(
1446 NavigationRequest::READY_TO_COMMIT,
1447 NavigationRequest::From(navigation->GetNavigationHandle())->state());
1448 EXPECT_TRUE(was_callback_called());
1449 EXPECT_EQ(std::string(), response_body());
1450}
1451
clamy49678312015-10-22 21:59:001452} // namespace content