blob: 882d2a7a3e905283f39b75e34a1b1030a416bd73 [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 Tanzer06980702023-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 Tanzer06980702023-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());
Mohamed Abdelhalim40c35d22019-09-19 15:59:05628 NavigationRequest::From(navigation->GetNavigationHandle())
Takashi Toyoshimacc4d947f2025-06-24 08:38:34629 ->GetNavigationThrottleRegistryForTesting()
danakjf26536bf2020-09-10 00:46:13630 ->GetNavigationThrottleRunnerForTesting()
Takashi Toyoshimacc4d947f2025-06-24 08:38:34631 .CallResumeForTesting();
Camille Lamy62b826012019-02-26 09:15:47632 EXPECT_TRUE(navigation->GetNavigationHandle()->GetRenderFrameHost());
633
634 SetBrowserClientForTesting(old_browser_client);
Alex Moshchuk1a66b1d2018-05-15 21:18:26635}
636
Antonio Sartori3cfa3b62020-10-09 10:42:40637TEST_F(NavigationRequestTest, PolicyContainerInheritance) {
638 struct TestCase {
639 const char* url;
640 bool expect_inherit;
641 } cases[]{{"about:blank", true},
642 {"data:text/plain,hello", true},
643 {"file://local", false},
644 {"http://chromium.org", false}};
645
646 const GURL kUrl1 = GURL("http://chromium.org");
647 auto navigation =
648 NavigationSimulatorImpl::CreateRendererInitiated(kUrl1, main_rfh());
649 navigation->Commit();
650
651 for (auto test : cases) {
652 // We navigate child frames because the BlockedSchemeNavigationThrottle
653 // restricts navigations in the main frame.
654 auto* child_frame = static_cast<TestRenderFrameHost*>(
655 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
656
657 // We set the referrer policy of the frame to "always". We then create a new
658 // navigation, set as initiator the frame itself, start the navigation, and
659 // change the referrer policy of the frame to "never". After we commit the
660 // navigation:
661 // - If navigating to a local scheme, the target frame should have inherited
662 // the referrer policy of the initiator ("always").
663 // - If navigating to a non-local scheme, the target frame should have a new
664 // policy container (hence referrer policy set to "default").
665 const GURL kUrl = GURL(test.url);
Peter Kastingeb8c3ce2021-08-20 04:39:35666 navigation =
Antonio Sartori3cfa3b62020-10-09 10:42:40667 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, child_frame);
Antonio Sartori5b2f8042020-10-23 18:13:26668 static_cast<blink::mojom::PolicyContainerHost*>(
Antonio Sartori9290b6b2020-11-09 10:09:33669 child_frame->policy_container_host())
Antonio Sartori5b2f8042020-10-23 18:13:26670 ->SetReferrerPolicy(network::mojom::ReferrerPolicy::kAlways);
Antonio Sartori3cfa3b62020-10-09 10:42:40671 navigation->SetInitiatorFrame(child_frame);
672 navigation->Start();
Antonio Sartori5b2f8042020-10-23 18:13:26673 static_cast<blink::mojom::PolicyContainerHost*>(
Antonio Sartori9290b6b2020-11-09 10:09:33674 child_frame->policy_container_host())
Antonio Sartori5b2f8042020-10-23 18:13:26675 ->SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever);
Antonio Sartori3cfa3b62020-10-09 10:42:40676 navigation->Commit();
677 EXPECT_EQ(
678 test.expect_inherit ? network::mojom::ReferrerPolicy::kAlways
679 : network::mojom::ReferrerPolicy::kDefault,
680 static_cast<RenderFrameHostImpl*>(navigation->GetFinalRenderFrameHost())
Antonio Sartori9290b6b2020-11-09 10:09:33681 ->policy_container_host()
Antonio Sartori3cfa3b62020-10-09 10:42:40682 ->referrer_policy());
683 }
684}
685
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37686TEST_F(NavigationRequestTest, DnsAliasesCanBeAccessed) {
687 // Create simulated NavigationRequest for the URL, which has aliases.
688 const GURL kUrl = GURL("http://chromium.org");
689 auto navigation =
690 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
691 std::vector<std::string> dns_aliases({"alias1", "alias2"});
692 navigation->SetResponseDnsAliases(std::move(dns_aliases));
693
694 // Start the navigation.
695 navigation->Start();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31696 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37697 navigation->GetNavigationHandle()->GetConnectionInfo());
698
699 // Commit the navigation.
Tsuyoshi Horo3023b5d2023-11-28 21:40:31700 navigation->set_http_connection_info(net::HttpConnectionInfo::kQUIC_35);
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37701 navigation->ReadyToCommit();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31702 EXPECT_EQ(net::HttpConnectionInfo::kQUIC_35,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37703 navigation->GetNavigationHandle()->GetConnectionInfo());
704
705 // Verify that the aliases are accessible from the NavigationRequest.
706 EXPECT_THAT(navigation->GetNavigationHandle()->GetDnsAliases(),
707 testing::ElementsAre("alias1", "alias2"));
708}
709
710TEST_F(NavigationRequestTest, NoDnsAliases) {
711 // Create simulated NavigationRequest for the URL, which does not
712 // have aliases. (Note the empty alias list.)
713 const GURL kUrl = GURL("http://chromium.org");
714 auto navigation =
715 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
716 std::vector<std::string> dns_aliases;
717 navigation->SetResponseDnsAliases(std::move(dns_aliases));
718
719 // Start the navigation.
720 navigation->Start();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31721 EXPECT_EQ(net::HttpConnectionInfo::kUNKNOWN,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37722 navigation->GetNavigationHandle()->GetConnectionInfo());
723
724 // Commit the navigation.
Tsuyoshi Horo3023b5d2023-11-28 21:40:31725 navigation->set_http_connection_info(net::HttpConnectionInfo::kQUIC_35);
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37726 navigation->ReadyToCommit();
Tsuyoshi Horo3023b5d2023-11-28 21:40:31727 EXPECT_EQ(net::HttpConnectionInfo::kQUIC_35,
Cammie Smith Barnesa0da2cf2021-01-11 22:09:37728 navigation->GetNavigationHandle()->GetConnectionInfo());
729
730 // Verify that there are no aliases in the NavigationRequest.
731 EXPECT_TRUE(navigation->GetNavigationHandle()->GetDnsAliases().empty());
732}
733
Antonio Sartori3e8de6d2021-07-26 10:28:41734TEST_F(NavigationRequestTest, StorageKeyToCommit) {
735 TestRenderFrameHost* child_document = static_cast<TestRenderFrameHost*>(
736 content::RenderFrameHostTester::For(main_rfh())->AppendChild(""));
Yuzu Saijo03dbf9b2022-07-22 04:29:45737 auto attributes = child_document->frame_tree_node()->attributes_->Clone();
Arthur Sonzogni64457592022-11-22 11:08:59738 attributes->credentialless = true;
Yuzu Saijo03dbf9b2022-07-22 04:29:45739 child_document->frame_tree_node()->SetAttributes(std::move(attributes));
Antonio Sartori3e8de6d2021-07-26 10:28:41740
741 const GURL kUrl = GURL("http://chromium.org");
742 auto navigation =
743 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, child_document);
744 navigation->ReadyToCommit();
745 NavigationRequest* request =
746 NavigationRequest::From(navigation->GetNavigationHandle());
747 EXPECT_TRUE(request->commit_params().storage_key.nonce().has_value());
Adithya Srinivasan4e0bb9642023-12-19 15:51:58748 EXPECT_EQ(child_document->GetPage().credentialless_iframes_nonce(),
Antonio Sartori3e8de6d2021-07-26 10:28:41749 request->commit_params().storage_key.nonce().value());
750
751 navigation->Commit();
752 child_document =
753 static_cast<TestRenderFrameHost*>(navigation->GetFinalRenderFrameHost());
Arthur Sonzogni64457592022-11-22 11:08:59754 EXPECT_TRUE(child_document->IsCredentialless());
Ari Chivukulad9e9c382023-02-15 23:30:09755 EXPECT_EQ(blink::StorageKey::CreateWithNonce(
Ali Hijazi78de14c2022-07-21 11:32:19756 url::Origin::Create(kUrl),
Adithya Srinivasan4e0bb9642023-12-19 15:51:58757 child_document->GetPage().credentialless_iframes_nonce()),
Mariam Ali8338d9fa2023-07-24 16:57:31758 child_document->GetStorageKey());
Antonio Sartori3e8de6d2021-07-26 10:28:41759}
760
sbingler4e4bd9b2023-02-27 19:56:53761// Test that the StorageKey's value is correctly affected by the
762// RuntimeFeatureStateContext.
763TEST_F(NavigationRequestTest, RuntimeFeatureStateStorageKey) {
764 base::test::ScopedFeatureList scoped_feature_list;
765 // Because the StorageKey's (and Storage Partitioning's) usage of
766 // RuntimeFeatureState is only meant to disable partitioning (i.e.:
767 // first-party only), we need the make sure the net::features is always
768 // enabled.
769 scoped_feature_list.InitAndEnableFeature(
770 net::features::kThirdPartyStoragePartitioning);
771
772 // This lambda performs the navigation and compares the commit_params'
773 // StorageKey against the passed in one. If `disable_sp` is true then it will
Ari Chivukula2b147362025-05-27 16:32:53774 // also enable the user bypass feature in the RFSC. It returns
sbingler4e4bd9b2023-02-27 19:56:53775 // the new TestRenderFrameHost* to the navigated frame.
776 auto NavigateAndCompareKeys =
777 [](NavigationSimulator* navigation, const blink::StorageKey& key,
778 bool disable_sp = false) -> TestRenderFrameHost* {
779 navigation->Start();
780
781 NavigationRequest* request =
782 NavigationRequest::From(navigation->GetNavigationHandle());
783
784 if (disable_sp) {
785 request->GetMutableRuntimeFeatureStateContext()
Ari Chivukula2b147362025-05-27 16:32:53786 .SetThirdPartyStoragePartitioningUserBypassEnabled(true);
sbingler4e4bd9b2023-02-27 19:56:53787 }
788
789 navigation->ReadyToCommit();
790
791 EXPECT_EQ(key, request->commit_params().storage_key);
792
793 navigation->Commit();
794 return static_cast<TestRenderFrameHost*>(
795 navigation->GetFinalRenderFrameHost());
796 };
797
798 // Throughout the test we'll be creating a frame tree with a main frame, a
799 // child frame, and a grandchild frame.
800 GURL main_url("https://main.com");
801 GURL b_url("https://b.com");
802 GURL c_url("https://c.com");
803
804 url::Origin main_origin = url::Origin::Create(main_url);
805 url::Origin b_origin = url::Origin::Create(b_url);
806 url::Origin c_origin = url::Origin::Create(c_url);
807
808 // Begin by testing with Storage Partitioning enabled.
809
810 auto main_navigation =
811 NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
812
813 // By definition the main frame's StorageKey will always be first party
814 blink::StorageKey main_frame_key =
815 blink::StorageKey::CreateFirstParty(main_origin);
816
817 NavigateAndCompareKeys(main_navigation.get(), main_frame_key);
818
819 TestRenderFrameHost* child_frame = static_cast<TestRenderFrameHost*>(
820 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
821
822 auto child_navigation =
823 NavigationSimulatorImpl::CreateRendererInitiated(b_url, child_frame);
824
825 // The child and grandchild should both be third-party keys.
826 blink::StorageKey child_frame_key =
827 blink::StorageKey::Create(b_origin, net::SchemefulSite(main_origin),
828 blink::mojom::AncestorChainBit::kCrossSite);
829
830 child_frame = NavigateAndCompareKeys(child_navigation.get(), child_frame_key);
831
832 TestRenderFrameHost* grandchild_frame =
833 child_frame->AppendChild("grandchild");
834
835 auto grandchild_navigation =
836 NavigationSimulatorImpl::CreateRendererInitiated(c_url, grandchild_frame);
837
838 blink::StorageKey grandchild_frame_key =
839 blink::StorageKey::Create(c_origin, net::SchemefulSite(main_origin),
840 blink::mojom::AncestorChainBit::kCrossSite);
841 grandchild_frame =
842 NavigateAndCompareKeys(grandchild_navigation.get(), grandchild_frame_key);
843
844 // Only the RuntimeFeatureStateContext in the main frame's matters. So
845 // disabling Storage Partitioning in the child_frame shouldn't affect the
846 // child's or the grandchild's StorageKey.
847 child_navigation =
848 NavigationSimulatorImpl::CreateRendererInitiated(b_url, child_frame);
849
850 child_frame = NavigateAndCompareKeys(child_navigation.get(), child_frame_key,
851 /*disable_sp=*/true);
852
853 grandchild_frame = child_frame->AppendChild("grandchild");
854
855 grandchild_navigation =
856 NavigationSimulatorImpl::CreateRendererInitiated(c_url, grandchild_frame);
857
858 grandchild_frame =
859 NavigateAndCompareKeys(grandchild_navigation.get(), grandchild_frame_key);
860
861 // Disabling Storage Partitioning on the main frame should cause the child's
862 // and grandchild's StorageKey to be first-party.
863 main_navigation =
864 NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
865
866 NavigateAndCompareKeys(main_navigation.get(), main_frame_key,
867 /*disable_sp=*/true);
868
869 child_frame = static_cast<TestRenderFrameHost*>(
870 content::RenderFrameHostTester::For(main_rfh())->AppendChild("child"));
871
872 child_navigation =
873 NavigationSimulatorImpl::CreateRendererInitiated(b_url, child_frame);
874
875 // The child and grandchild should both be first-party keys.
876 blink::StorageKey child_frame_key_1p =
877 blink::StorageKey::CreateFirstParty(b_origin);
878
879 child_frame =
880 NavigateAndCompareKeys(child_navigation.get(), child_frame_key_1p);
881
882 grandchild_frame = child_frame->AppendChild("grandchild");
883
884 blink::StorageKey grandchild_frame_key_1p =
885 blink::StorageKey::CreateFirstParty(c_origin);
886
887 grandchild_navigation =
888 NavigationSimulatorImpl::CreateRendererInitiated(c_url, grandchild_frame);
889
890 grandchild_frame = NavigateAndCompareKeys(grandchild_navigation.get(),
891 grandchild_frame_key_1p);
892}
893
Antonio Sartoribf27cc442021-08-25 13:08:23894TEST_F(NavigationRequestTest,
Arthur Sonzogni64457592022-11-22 11:08:59895 NavigationToCredentiallessDocumentNetworkIsolationInfo) {
Antonio Sartoribf27cc442021-08-25 13:08:23896 auto* child_frame = static_cast<TestRenderFrameHost*>(
897 content::RenderFrameHostTester::For(main_test_rfh())
898 ->AppendChild("child"));
Yuzu Saijo03dbf9b2022-07-22 04:29:45899 auto attributes = child_frame->frame_tree_node()->attributes_->Clone();
Arthur Sonzogni64457592022-11-22 11:08:59900 attributes->credentialless = true;
Yuzu Saijo03dbf9b2022-07-22 04:29:45901 child_frame->frame_tree_node()->SetAttributes(std::move(attributes));
Antonio Sartoribf27cc442021-08-25 13:08:23902
903 std::unique_ptr<NavigationSimulator> navigation =
904 NavigationSimulator::CreateRendererInitiated(
905 GURL("https://example.com/navigation.html"), child_frame);
906 navigation->ReadyToCommit();
907
Adithya Srinivasan4e0bb9642023-12-19 15:51:58908 EXPECT_EQ(main_test_rfh()->GetPage().credentialless_iframes_nonce(),
Antonio Sartoribf27cc442021-08-25 13:08:23909 static_cast<NavigationRequest*>(navigation->GetNavigationHandle())
910 ->isolation_info_for_subresources()
911 .network_isolation_key()
912 .GetNonce());
Adithya Srinivasan4e0bb9642023-12-19 15:51:58913 EXPECT_EQ(main_test_rfh()->GetPage().credentialless_iframes_nonce(),
Antonio Sartoribf27cc442021-08-25 13:08:23914 static_cast<NavigationRequest*>(navigation->GetNavigationHandle())
915 ->GetIsolationInfo()
916 .network_isolation_key()
917 .GetNonce());
918}
919
Yifan Luob5c352b2023-10-30 11:22:10920TEST_F(NavigationRequestTest, UpdatePrivateNetworkRequestPolicy) {
921 std::unique_ptr<NavigationSimulator> navigation =
922 NavigationSimulator::CreateRendererInitiated(GURL("https://example.com/"),
923 main_test_rfh());
924 navigation->SetSocketAddress(net::IPEndPoint());
925
926 navigation->ReadyToCommit();
927 NavigationRequest* request =
928 NavigationRequest::From(navigation->GetNavigationHandle());
929 EXPECT_FALSE(request->GetSocketAddress().address().IsValid());
930 navigation->Commit();
931}
932
Nasko Oskov32f95892025-06-02 20:45:08933// Test to ensure that the SanitizeRedirectsForCommit method correctly removes
934// the query parameters parts of the URL that can contain sensitive information.
935TEST_F(NavigationRequestTest, SanitizeRedirectsForCommit) {
936 const GURL start_url("https://a.com?param=1");
937 const GURL url_2("https://b.com?param=2#foo");
938 const GURL url_3("https://c.com?param=3");
939 const GURL final_url("https://d.com?param=4");
940 std::unique_ptr<NavigationSimulator> navigation =
941 NavigationSimulator::CreateRendererInitiated(start_url, main_test_rfh());
942 navigation->Start();
943 navigation->Redirect(url_2);
944 navigation->Redirect(url_3);
945 navigation->Redirect(final_url);
946
947 NavigationRequest* request =
948 NavigationRequest::From(navigation->GetNavigationHandle());
949 auto commit_params = request->commit_params().Clone();
950 request->SanitizeRedirectsForCommit(commit_params);
951
952 // redirect_infos contains entries for B, C, and D, but not the starting URL.
953 // Ensure that the full URL for D is preserved.
954 EXPECT_EQ(3, commit_params->redirect_infos.size());
955 EXPECT_EQ(GURL("https://b.com"), commit_params->redirect_infos[0].new_url);
956 EXPECT_EQ(GURL("https://c.com"), commit_params->redirect_infos[1].new_url);
957 EXPECT_EQ(final_url, commit_params->redirect_infos[2].new_url);
958
959 // In contrast, redirects contains A, B, and C (i.e., the starting URL but not
960 // the final URL).
961 EXPECT_EQ(3, commit_params->redirects.size());
962 EXPECT_EQ(GURL("https://a.com"), commit_params->redirects[0]);
963 EXPECT_EQ(GURL("https://b.com"), commit_params->redirects[1]);
964 EXPECT_EQ(GURL("https://c.com"), commit_params->redirects[2]);
965}
966
arthursonzogni898dcda52021-01-21 08:50:10967// Test that the required CSP of every frame is computed/inherited correctly and
968// that the Sec-Required-CSP header is set.
969class CSPEmbeddedEnforcementUnitTest : public NavigationRequestTest {
970 protected:
971 TestRenderFrameHost* main_rfh() {
972 return static_cast<TestRenderFrameHost*>(NavigationRequestTest::main_rfh());
973 }
974
975 // Simulate the |csp| attribute being set in |rfh|'s frame. Then navigate it.
976 // Returns the request's Sec-Required-CSP header.
977 std::string NavigateWithRequiredCSP(TestRenderFrameHost** rfh,
978 std::string required_csp) {
979 TestRenderFrameHost* document = *rfh;
980
981 if (!required_csp.empty()) {
982 auto headers =
983 base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
984 headers->SetHeader("Content-Security-Policy", required_csp);
985 std::vector<network::mojom::ContentSecurityPolicyPtr> policies;
986 network::AddContentSecurityPolicyFromHeaders(
987 *headers, GURL("https://example.com/"), &policies);
Yuzu Saijo03dbf9b2022-07-22 04:29:45988 auto attributes = document->frame_tree_node()->attributes_->Clone();
989 // Set csp value.
990 attributes->parsed_csp_attribute = std::move(policies[0]);
991 document->frame_tree_node()->SetAttributes(std::move(attributes));
arthursonzogni898dcda52021-01-21 08:50:10992 }
993
994 // Chrome blocks a document navigating to a URL if more than one of its
995 // ancestors have the same URL. Use a different URL every time, to
996 // avoid blocking navigation of the grandchild frame.
997 static int nonce = 0;
998 GURL url("https://www.example.com" + base::NumberToString(nonce++));
999
1000 auto navigation =
1001 content::NavigationSimulator::CreateRendererInitiated(url, *rfh);
1002 navigation->Start();
1003 NavigationRequest* request =
1004 NavigationRequest::From(navigation->GetNavigationHandle());
Chris Fredricksonfb77b04d2024-08-02 18:54:581005 std::string sec_required_csp = request->GetRequestHeaders()
1006 .GetHeader("sec-required-csp")
1007 .value_or(std::string());
arthursonzogni898dcda52021-01-21 08:50:101008
1009 // Complete the navigation so that the required csp is stored in the
1010 // RenderFrameHost, so that when we will add children to this document they
1011 // will be able to get the parent's required csp (and hence also test that
1012 // the whole logic works).
1013 auto response_headers =
1014 base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
1015 response_headers->SetHeader("Allow-CSP-From", "*");
1016 navigation->SetResponseHeaders(response_headers);
1017 navigation->Commit();
1018
1019 *rfh = static_cast<TestRenderFrameHost*>(
1020 navigation->GetFinalRenderFrameHost());
1021
1022 return sec_required_csp;
1023 }
1024
1025 TestRenderFrameHost* AddChild(TestRenderFrameHost* parent) {
1026 return static_cast<TestRenderFrameHost*>(
1027 content::RenderFrameHostTester::For(parent)->AppendChild(""));
1028 }
1029};
1030
1031TEST_F(CSPEmbeddedEnforcementUnitTest, TopLevel) {
1032 TestRenderFrameHost* top_document = main_rfh();
1033 std::string sec_required_csp = NavigateWithRequiredCSP(&top_document, "");
1034 EXPECT_EQ("", sec_required_csp);
1035 EXPECT_FALSE(top_document->required_csp());
1036}
1037
1038TEST_F(CSPEmbeddedEnforcementUnitTest, ChildNoCSP) {
1039 TestRenderFrameHost* top_document = main_rfh();
1040 TestRenderFrameHost* child_document = AddChild(top_document);
1041 std::string sec_required_csp = NavigateWithRequiredCSP(&child_document, "");
1042 EXPECT_EQ("", sec_required_csp);
1043 EXPECT_FALSE(child_document->required_csp());
1044}
1045
1046TEST_F(CSPEmbeddedEnforcementUnitTest, ChildWithCSP) {
1047 TestRenderFrameHost* top_document = main_rfh();
1048 TestRenderFrameHost* child_document = AddChild(top_document);
1049 std::string sec_required_csp =
1050 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1051 EXPECT_EQ("script-src 'none'", sec_required_csp);
1052 EXPECT_TRUE(child_document->required_csp());
1053 EXPECT_EQ("script-src 'none'",
1054 child_document->required_csp()->header->header_value);
1055}
1056
1057TEST_F(CSPEmbeddedEnforcementUnitTest, ChildSiblingNoCSP) {
1058 TestRenderFrameHost* top_document = main_rfh();
1059 TestRenderFrameHost* child_document = AddChild(top_document);
1060 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1061 TestRenderFrameHost* sibling_document = AddChild(top_document);
1062 std::string sec_required_csp = NavigateWithRequiredCSP(&sibling_document, "");
1063 EXPECT_FALSE(sibling_document->required_csp());
1064}
1065
1066TEST_F(CSPEmbeddedEnforcementUnitTest, ChildSiblingCSP) {
1067 TestRenderFrameHost* top_document = main_rfh();
1068 TestRenderFrameHost* child_document = AddChild(top_document);
1069 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1070 TestRenderFrameHost* sibling_document = AddChild(top_document);
1071 std::string sec_required_csp =
1072 NavigateWithRequiredCSP(&sibling_document, "script-src 'none'");
1073 EXPECT_EQ("script-src 'none'", sec_required_csp);
1074 EXPECT_TRUE(sibling_document->required_csp());
1075 EXPECT_EQ("script-src 'none'",
1076 sibling_document->required_csp()->header->header_value);
1077}
1078
1079TEST_F(CSPEmbeddedEnforcementUnitTest, GrandChildNoCSP) {
1080 TestRenderFrameHost* top_document = main_rfh();
1081 TestRenderFrameHost* child_document = AddChild(top_document);
1082 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1083 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1084 std::string sec_required_csp =
1085 NavigateWithRequiredCSP(&grand_child_document, "");
1086 EXPECT_EQ("script-src 'none'", sec_required_csp);
1087 EXPECT_TRUE(grand_child_document->required_csp());
1088 EXPECT_EQ("script-src 'none'",
1089 grand_child_document->required_csp()->header->header_value);
1090}
1091
1092TEST_F(CSPEmbeddedEnforcementUnitTest, GrandChildSameCSP) {
1093 TestRenderFrameHost* top_document = main_rfh();
1094 TestRenderFrameHost* child_document = AddChild(top_document);
1095 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1096 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1097 std::string sec_required_csp =
1098 NavigateWithRequiredCSP(&grand_child_document, "script-src 'none'");
1099 EXPECT_EQ("script-src 'none'", sec_required_csp);
1100 EXPECT_TRUE(grand_child_document->required_csp());
1101 EXPECT_EQ("script-src 'none'",
1102 grand_child_document->required_csp()->header->header_value);
1103}
1104
1105TEST_F(CSPEmbeddedEnforcementUnitTest, GrandChildDifferentCSP) {
1106 TestRenderFrameHost* top_document = main_rfh();
1107 TestRenderFrameHost* child_document = AddChild(top_document);
1108 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1109 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1110 std::string sec_required_csp =
1111 NavigateWithRequiredCSP(&grand_child_document, "img-src 'none'");
1112
1113 // This seems weird, but it is the intended behaviour according to the spec.
1114 // The problem is that "script-src 'none'" does not subsume "img-src 'none'",
1115 // so "img-src 'none'" on the grandchild is an invalid csp attribute, and we
1116 // just discard it in favour of the parent's csp attribute.
1117 //
1118 // This should probably be fixed in the specification:
1119 // https://github.com/w3c/webappsec-cspee/pull/11
1120 EXPECT_EQ("script-src 'none'", sec_required_csp);
1121 EXPECT_TRUE(grand_child_document->required_csp());
1122 EXPECT_EQ("script-src 'none'",
1123 grand_child_document->required_csp()->header->header_value);
1124}
1125
1126TEST_F(CSPEmbeddedEnforcementUnitTest, InvalidCSP) {
1127 TestRenderFrameHost* top_document = main_rfh();
1128 TestRenderFrameHost* child_document = AddChild(top_document);
1129 std::string sec_required_csp =
1130 NavigateWithRequiredCSP(&child_document, "report-to group");
1131 EXPECT_EQ("", sec_required_csp);
1132 EXPECT_FALSE(child_document->required_csp());
1133}
1134
1135TEST_F(CSPEmbeddedEnforcementUnitTest, InvalidCspAndInheritFromParent) {
1136 TestRenderFrameHost* top_document = main_rfh();
1137 TestRenderFrameHost* child_document = AddChild(top_document);
1138 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1139 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1140 std::string sec_required_csp =
Antonio Sartori4231e932021-02-04 12:01:141141 NavigateWithRequiredCSP(&grand_child_document, "report-to group");
arthursonzogni898dcda52021-01-21 08:50:101142 EXPECT_EQ("script-src 'none'", sec_required_csp);
1143 EXPECT_TRUE(grand_child_document->required_csp());
1144 EXPECT_EQ("script-src 'none'",
1145 grand_child_document->required_csp()->header->header_value);
1146}
1147
1148TEST_F(CSPEmbeddedEnforcementUnitTest,
1149 SemiInvalidCspAndInheritSameCspFromParent) {
1150 TestRenderFrameHost* top_document = main_rfh();
1151 TestRenderFrameHost* child_document = AddChild(top_document);
1152 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1153 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1154 std::string sec_required_csp = NavigateWithRequiredCSP(
Antonio Sartori4231e932021-02-04 12:01:141155 &grand_child_document, "script-src 'none'; report-to group");
arthursonzogni898dcda52021-01-21 08:50:101156 EXPECT_EQ("script-src 'none'", sec_required_csp);
1157 EXPECT_TRUE(grand_child_document->required_csp());
1158 EXPECT_EQ("script-src 'none'",
1159 grand_child_document->required_csp()->header->header_value);
1160}
1161
1162TEST_F(CSPEmbeddedEnforcementUnitTest,
1163 SemiInvalidCspAndInheritDifferentCspFromParent) {
1164 TestRenderFrameHost* top_document = main_rfh();
1165 TestRenderFrameHost* child_document = AddChild(top_document);
1166 NavigateWithRequiredCSP(&child_document, "script-src 'none'");
1167 TestRenderFrameHost* grand_child_document = AddChild(child_document);
1168 std::string sec_required_csp = NavigateWithRequiredCSP(
Antonio Sartori4231e932021-02-04 12:01:141169 &grand_child_document, "sandbox; report-to group");
arthursonzogni898dcda52021-01-21 08:50:101170 EXPECT_EQ("script-src 'none'", sec_required_csp);
1171 EXPECT_TRUE(grand_child_document->required_csp());
1172 EXPECT_EQ("script-src 'none'",
1173 grand_child_document->required_csp()->header->header_value);
1174}
1175
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301176namespace {
1177
1178// Mock that allows us to avoid depending on the origin_trials component.
1179class OriginTrialsControllerDelegateMock
1180 : public OriginTrialsControllerDelegate {
1181 public:
1182 ~OriginTrialsControllerDelegateMock() override = default;
1183
1184 void PersistTrialsFromTokens(
1185 const url::Origin& origin,
Peter Birk Pakkenbergf62286a2023-01-25 19:44:071186 const url::Origin& partition_origin,
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301187 const base::span<const std::string> header_tokens,
Svend Larsen113ac5b2024-06-05 20:56:201188 const base::Time current_time,
1189 std::optional<ukm::SourceId> source_id) override {
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301190 persisted_tokens_[origin] =
1191 std::vector<std::string>(header_tokens.begin(), header_tokens.end());
1192 }
Peter Birk Pakkenberg582edfc2023-02-27 11:22:121193 void PersistAdditionalTrialsFromTokens(
1194 const url::Origin& origin,
1195 const url::Origin& partition_origin,
1196 const base::span<const url::Origin> script_origins,
1197 const base::span<const std::string> header_tokens,
Svend Larsen113ac5b2024-06-05 20:56:201198 const base::Time current_time,
1199 std::optional<ukm::SourceId> source_id) override {
Peter Boströmfc7ddc182024-10-31 19:37:211200 NOTREACHED() << "not used by test";
Peter Birk Pakkenberg582edfc2023-02-27 11:22:121201 }
Peter Birk Pakkenberg36b79c912023-05-25 08:38:241202 bool IsFeaturePersistedForOrigin(const url::Origin& origin,
1203 const url::Origin& partition_origin,
Yao Xiao5c6e1fa2023-10-04 19:12:221204 blink::mojom::OriginTrialFeature feature,
Peter Birk Pakkenberg36b79c912023-05-25 08:38:241205 const base::Time current_time) override {
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301206 DCHECK(false) << "Method not implemented for test.";
1207 return false;
1208 }
1209
Peter Birk Pakkenberg4c1bb272022-09-27 10:51:291210 base::flat_set<std::string> GetPersistedTrialsForOrigin(
1211 const url::Origin& origin,
Peter Birk Pakkenbergf62286a2023-01-25 19:44:071212 const url::Origin& partition_origin,
Peter Birk Pakkenberg4c1bb272022-09-27 10:51:291213 base::Time current_time) override {
1214 DCHECK(false) << "Method not implemented for test.";
1215 return base::flat_set<std::string>();
1216 }
1217
Peter Birk Pakkenbergd74c6f82022-11-08 17:44:381218 void ClearPersistedTokens() override { persisted_tokens_.clear(); }
1219
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301220 base::flat_map<url::Origin, std::vector<std::string>> persisted_tokens_;
1221};
1222
1223} // namespace
1224
1225class PersistentOriginTrialNavigationRequestTest
1226 : public NavigationRequestTest {
1227 public:
1228 PersistentOriginTrialNavigationRequestTest()
1229 : delegate_mock_(std::make_unique<OriginTrialsControllerDelegateMock>()) {
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301230 }
1231 ~PersistentOriginTrialNavigationRequestTest() override = default;
1232
1233 std::vector<std::string> GetPersistedTokens(const url::Origin& origin) {
1234 return delegate_mock_->persisted_tokens_[origin];
1235 }
1236
1237 protected:
1238 std::unique_ptr<BrowserContext> CreateBrowserContext() override {
1239 std::unique_ptr<TestBrowserContext> context =
1240 std::make_unique<TestBrowserContext>();
1241 context->SetOriginTrialsControllerDelegate(delegate_mock_.get());
1242 return context;
1243 }
1244
1245 private:
1246 std::unique_ptr<OriginTrialsControllerDelegateMock> delegate_mock_;
1247};
1248
1249// Ensure that navigations with a valid Origin-Trial header with a persistent
1250// origin trial token results in the trial being marked as enabled.
1251// Then check that subsequent navigations without headers trigger an update
1252// that clears out stored trials.
1253TEST_F(PersistentOriginTrialNavigationRequestTest,
1254 NavigationCommitsPersistentOriginTrials) {
1255 // Generated with:
1256 // tools/origin_trials/generate_token.py https://example.com
1257 // FrobulatePersistent
1258 // --expire-timestamp=2000000000
1259 const char kPersistentOriginTrialToken[] =
1260 "AzZfd1vKZ0SSGRGk/"
1261 "8nIszQSlHYjbuYVE3jwaNZG3X4t11zRhzPWWJwTZ+JJDS3JJsyEZcpz+y20pAP6/"
1262 "6upOQ4AAABdeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZ"
1263 "SI"
1264 "6ICJGcm9idWxhdGVQZXJzaXN0ZW50IiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9";
1265
Peter Birk Pakkenberg73e07b62022-09-21 11:20:301266 blink::ScopedTestOriginTrialPolicy origin_trial_policy_;
1267
1268 const GURL kUrl = GURL("https://example.com");
1269 auto navigation =
1270 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
1271
1272 auto response_headers =
1273 base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
1274 response_headers->SetHeader("Origin-Trial", kPersistentOriginTrialToken);
1275 navigation->SetResponseHeaders(response_headers);
1276
1277 navigation->Commit();
1278
1279 url::Origin origin = url::Origin::Create(kUrl);
1280 EXPECT_EQ(std::vector<std::string>{kPersistentOriginTrialToken},
1281 GetPersistedTokens(origin));
1282
1283 // Navigate again without response headers to assert the trial information is
1284 // still updated and cleared.
1285 NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh())->Commit();
1286 EXPECT_EQ(std::vector<std::string>(), GetPersistedTokens(origin));
1287}
1288
Igor Ruvinovdcb81982023-06-21 22:22:171289namespace {
1290
1291// Test version of a NavigationThrottle that requests the response body.
1292class ResponseBodyNavigationThrottle : public NavigationThrottle {
1293 public:
1294 using ResponseBodyCallback = base::OnceCallback<void(const std::string&)>;
1295
Takashi Toyoshima74e6ef302025-06-06 11:28:411296 ResponseBodyNavigationThrottle(NavigationThrottleRegistry& registry,
Igor Ruvinovdcb81982023-06-21 22:22:171297 ResponseBodyCallback callback)
Takashi Toyoshima74e6ef302025-06-06 11:28:411298 : NavigationThrottle(registry), callback_(std::move(callback)) {}
Igor Ruvinovdcb81982023-06-21 22:22:171299 ResponseBodyNavigationThrottle(const ResponseBodyNavigationThrottle&) =
1300 delete;
1301 ResponseBodyNavigationThrottle& operator=(
1302 const ResponseBodyNavigationThrottle&) = delete;
1303 ~ResponseBodyNavigationThrottle() override = default;
1304
1305 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
1306 navigation_handle()->GetResponseBody(
1307 base::BindOnce(&ResponseBodyNavigationThrottle::OnResponseBodyReady,
1308 base::Unretained(this)));
1309 return NavigationThrottle::DEFER;
1310 }
1311
1312 const char* GetNameForLogging() override {
1313 return "ResponseBodyNavigationThrottle";
1314 }
1315
1316 private:
1317 void OnResponseBodyReady(const std::string& response_body) {
1318 std::move(callback_).Run(response_body);
1319 NavigationRequest::From(navigation_handle())
Takashi Toyoshimacc4d947f2025-06-24 08:38:341320 ->GetNavigationThrottleRegistryForTesting()
Igor Ruvinovdcb81982023-06-21 22:22:171321 ->GetNavigationThrottleRunnerForTesting()
Takashi Toyoshimacc4d947f2025-06-24 08:38:341322 .CallResumeForTesting();
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