blob: 1b2517a260af434f8975e2b4ae054e7e4ddf1df5 [file] [log] [blame]
Dmitry Gozmancd3529822019-01-11 21:12:161// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/loader/navigation_body_loader.h"
6
7#include "base/bind.h"
8#include "base/macros.h"
9#include "base/run_loop.h"
10#include "base/single_thread_task_runner.h"
Gabriel Charettec7108742019-08-23 03:31:4011#include "base/test/task_environment.h"
Lucas Furukawa Gadanief8290a2019-07-29 20:27:5112#include "content/common/navigation_params.mojom.h"
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:3013#include "mojo/public/cpp/bindings/remote.h"
Emily Stark1225b892019-07-03 05:51:3414#include "net/cert/x509_util.h"
15#include "net/ssl/ssl_connection_status_flags.h"
16#include "net/test/cert_test_util.h"
Dmitry Gozmancd3529822019-01-11 21:12:1617#include "services/network/public/cpp/url_loader_completion_status.h"
18#include "testing/gtest/include/gtest/gtest.h"
19#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
20#include "third_party/blink/public/platform/web_navigation_body_loader.h"
Dmitry Gozman00fd5bb2019-01-25 20:25:3321#include "third_party/blink/public/web/web_navigation_params.h"
Dmitry Gozmancd3529822019-01-11 21:12:1622
23namespace content {
24
25namespace {
26
27class NavigationBodyLoaderTest : public ::testing::Test,
28 public blink::WebNavigationBodyLoader::Client {
29 protected:
30 NavigationBodyLoaderTest() {}
31
32 ~NavigationBodyLoaderTest() override { base::RunLoop().RunUntilIdle(); }
33
34 MojoCreateDataPipeOptions CreateDataPipeOptions() {
35 MojoCreateDataPipeOptions options;
36 options.struct_size = sizeof(MojoCreateDataPipeOptions);
37 options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
38 options.element_num_bytes = 1;
39 options.capacity_num_bytes = 1024;
40 return options;
41 }
42
43 void CreateBodyLoader() {
Robert Sesek76af6692021-01-29 20:57:2344 mojo::ScopedDataPipeProducerHandle producer_handle;
45 mojo::ScopedDataPipeConsumerHandle consumer_handle;
46 MojoCreateDataPipeOptions options = CreateDataPipeOptions();
47 ASSERT_EQ(mojo::CreateDataPipe(&options, producer_handle, consumer_handle),
48 MOJO_RESULT_OK);
49
50 writer_ = std::move(producer_handle);
Dmitry Gozmancd3529822019-01-11 21:12:1651 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:3052 endpoints->url_loader_client = client_remote_.BindNewPipeAndPassReceiver();
Dmitry Gozman00fd5bb2019-01-25 20:25:3353 blink::WebNavigationParams navigation_params;
arthursonzognid5a8d0b2021-03-11 17:36:4354 navigation_params.sandbox_flags = network::mojom::WebSandboxFlags::kNone;
Lucas Furukawa Gadanieeddf2de2019-08-01 23:37:5755 auto common_params = CreateCommonNavigationParams();
Lucas Furukawa Gadania9c45682019-07-31 22:05:1456 auto commit_params = CreateCommitNavigationParams();
Dmitry Gozman00fd5bb2019-01-25 20:25:3357 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Minggang Wange0d5db32020-10-07 15:55:3158 std::move(common_params), std::move(commit_params), /*request_id=*/1,
Robert Sesek76af6692021-01-29 20:57:2359 network::mojom::URLResponseHead::New(), std::move(consumer_handle),
60 std::move(endpoints),
Dmitry Gozmancd3529822019-01-11 21:12:1661 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
Minggang Wange0d5db32020-10-07 15:55:3162 /*render_frame_impl=*/nullptr, /*is_main_frame=*/true,
63 &navigation_params);
Dmitry Gozman00fd5bb2019-01-25 20:25:3364 loader_ = std::move(navigation_params.body_loader);
Dmitry Gozmancd3529822019-01-11 21:12:1665 }
66
67 void StartLoading() {
68 loader_->StartLoadingBody(this, false /* use_isolated_code_cache */);
Dmitry Gozmancd3529822019-01-11 21:12:1669 base::RunLoop().RunUntilIdle();
70 }
71
72 void Write(const std::string& buffer) {
73 uint32_t size = buffer.size();
74 MojoResult result = writer_->WriteData(buffer.c_str(), &size, kNone);
75 ASSERT_EQ(MOJO_RESULT_OK, result);
76 ASSERT_EQ(buffer.size(), size);
77 }
78
79 void Complete(int net_error) {
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:3080 client_remote_->OnComplete(network::URLLoaderCompletionStatus(net_error));
Dmitry Gozmancd3529822019-01-11 21:12:1681 base::RunLoop().RunUntilIdle();
82 }
83
Bill Budge4405d8d52019-08-22 16:45:4584 void BodyCodeCacheReceived(mojo_base::BigBuffer data) override {}
Dmitry Gozmancd3529822019-01-11 21:12:1685
86 void BodyDataReceived(base::span<const char> data) override {
87 ASSERT_TRUE(expecting_data_received_);
88 did_receive_data_ = true;
89 data_received_ += std::string(data.data(), data.size());
90 TakeActions();
91 if (run_loop_.running())
92 run_loop_.Quit();
93 }
94
95 void BodyLoadingFinished(
96 base::TimeTicks completion_time,
97 int64_t total_encoded_data_length,
98 int64_t total_encoded_body_length,
99 int64_t total_decoded_body_length,
100 bool should_report_corb_blocking,
101 const base::Optional<blink::WebURLError>& error) override {
102 ASSERT_TRUE(expecting_finished_);
103 did_finish_ = true;
104 error_ = error;
105 TakeActions();
106 if (run_loop_.running())
107 run_loop_.Quit();
108 }
109
110 void TakeActions() {
111 if (!buffer_to_write_.empty()) {
112 std::string buffer = buffer_to_write_;
113 buffer_to_write_ = std::string();
114 ExpectDataReceived();
115 Write(buffer);
116 }
117 if (toggle_defers_loading_) {
118 toggle_defers_loading_ = false;
Yuzu Saijob71af9482020-11-24 08:38:38119 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
120 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
Dmitry Gozmancd3529822019-01-11 21:12:16121 }
122 if (destroy_loader_) {
123 destroy_loader_ = false;
124 loader_.reset();
125 }
126 }
127
128 void ExpectDataReceived() {
129 expecting_data_received_ = true;
130 did_receive_data_ = false;
131 }
132
133 void ExpectFinished() {
134 expecting_finished_ = true;
135 did_finish_ = false;
136 }
137
138 std::string TakeDataReceived() {
139 std::string data = data_received_;
140 data_received_ = std::string();
141 return data;
142 }
143
144 void Wait() {
145 if (expecting_data_received_) {
146 if (!did_receive_data_)
147 run_loop_.Run();
148 ASSERT_TRUE(did_receive_data_);
149 expecting_data_received_ = false;
150 }
151 if (expecting_finished_) {
152 if (!did_finish_)
153 run_loop_.Run();
154 ASSERT_TRUE(did_finish_);
155 expecting_finished_ = false;
156 }
157 }
158
Gabriel Charette694c3c332019-08-19 14:53:05159 base::test::TaskEnvironment task_environment_;
Dmitry Gozmancd3529822019-01-11 21:12:16160 static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:30161 mojo::Remote<network::mojom::URLLoaderClient> client_remote_;
Dmitry Gozmancd3529822019-01-11 21:12:16162 std::unique_ptr<blink::WebNavigationBodyLoader> loader_;
Dmitry Gozmancd3529822019-01-11 21:12:16163 mojo::ScopedDataPipeProducerHandle writer_;
164
165 base::RunLoop run_loop_;
166 bool expecting_data_received_ = false;
167 bool did_receive_data_ = false;
168 bool expecting_finished_ = false;
169 bool did_finish_ = false;
170 std::string buffer_to_write_;
171 bool toggle_defers_loading_ = false;
172 bool destroy_loader_ = false;
173 std::string data_received_;
174 base::Optional<blink::WebURLError> error_;
175};
176
Dmitry Gozman98e8b192019-01-17 13:15:24177TEST_F(NavigationBodyLoaderTest, SetDefersBeforeStart) {
178 CreateBodyLoader();
Yuzu Saijob71af9482020-11-24 08:38:38179 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
180 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
Dmitry Gozman98e8b192019-01-17 13:15:24181 // Should not crash.
182}
183
Dmitry Gozmancd3529822019-01-11 21:12:16184TEST_F(NavigationBodyLoaderTest, DataReceived) {
185 CreateBodyLoader();
186 StartLoading();
187 ExpectDataReceived();
188 Write("hello");
189 Wait();
190 EXPECT_EQ("hello", TakeDataReceived());
191}
192
193TEST_F(NavigationBodyLoaderTest, DataReceivedFromDataReceived) {
194 CreateBodyLoader();
195 StartLoading();
196 ExpectDataReceived();
197 buffer_to_write_ = "world";
198 Write("hello");
199 Wait();
200 EXPECT_EQ("helloworld", TakeDataReceived());
201}
202
203TEST_F(NavigationBodyLoaderTest, DestroyFromDataReceived) {
204 CreateBodyLoader();
205 StartLoading();
206 ExpectDataReceived();
207 destroy_loader_ = false;
208 Write("hello");
209 Wait();
210 EXPECT_EQ("hello", TakeDataReceived());
211}
212
213TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromDataReceived) {
214 CreateBodyLoader();
215 StartLoading();
216 ExpectDataReceived();
217 toggle_defers_loading_ = true;
218 Write("hello");
219 Wait();
220 EXPECT_EQ("hello", TakeDataReceived());
221}
222
223TEST_F(NavigationBodyLoaderTest, StartDeferred) {
224 CreateBodyLoader();
Yuzu Saijob71af9482020-11-24 08:38:38225 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
Dmitry Gozmancd3529822019-01-11 21:12:16226 StartLoading();
227 Write("hello");
228 ExpectDataReceived();
Yuzu Saijob71af9482020-11-24 08:38:38229 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
Dmitry Gozmancd3529822019-01-11 21:12:16230 Wait();
231 EXPECT_EQ("hello", TakeDataReceived());
232}
233
Yuzu Saijoa3610fab2020-11-24 10:05:57234TEST_F(NavigationBodyLoaderTest, StartDeferredWithBackForwardCache) {
235 CreateBodyLoader();
236 loader_->SetDefersLoading(
237 blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
238 StartLoading();
239 Write("hello");
240 ExpectDataReceived();
241 loader_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
242 Wait();
243 EXPECT_EQ("hello", TakeDataReceived());
244}
245
Dmitry Gozmancd3529822019-01-11 21:12:16246TEST_F(NavigationBodyLoaderTest, OnCompleteThenClose) {
247 CreateBodyLoader();
248 StartLoading();
249 Complete(net::ERR_FAILED);
250 ExpectFinished();
251 writer_.reset();
252 Wait();
253 EXPECT_TRUE(error_.has_value());
254}
255
256TEST_F(NavigationBodyLoaderTest, DestroyFromOnCompleteThenClose) {
257 CreateBodyLoader();
258 StartLoading();
259 Complete(net::ERR_FAILED);
260 ExpectFinished();
261 destroy_loader_ = true;
262 writer_.reset();
263 Wait();
264 EXPECT_TRUE(error_.has_value());
265}
266
267TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromOnCompleteThenClose) {
268 CreateBodyLoader();
269 StartLoading();
270 Complete(net::ERR_FAILED);
271 ExpectFinished();
272 toggle_defers_loading_ = true;
273 writer_.reset();
274 Wait();
275 EXPECT_TRUE(error_.has_value());
276}
277
278TEST_F(NavigationBodyLoaderTest, CloseThenOnComplete) {
279 CreateBodyLoader();
280 StartLoading();
281 writer_.reset();
282 ExpectFinished();
283 Complete(net::ERR_FAILED);
284 Wait();
285 EXPECT_TRUE(error_.has_value());
286}
287
288TEST_F(NavigationBodyLoaderTest, DestroyFromCloseThenOnComplete) {
289 CreateBodyLoader();
290 StartLoading();
291 writer_.reset();
292 ExpectFinished();
293 destroy_loader_ = true;
294 Complete(net::ERR_FAILED);
295 Wait();
296 EXPECT_TRUE(error_.has_value());
297}
298
299TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromCloseThenOnComplete) {
300 CreateBodyLoader();
301 StartLoading();
302 writer_.reset();
303 ExpectFinished();
304 toggle_defers_loading_ = true;
305 Complete(net::ERR_FAILED);
306 Wait();
307 EXPECT_TRUE(error_.has_value());
308}
309
Emily Stark1225b892019-07-03 05:51:34310// Tests that FillNavigationParamsResponseAndBodyLoader populates security
311// details on the response when they are present.
312TEST_F(NavigationBodyLoaderTest, FillResponseWithSecurityDetails) {
Lucas Gadanif7430a742019-10-11 17:42:14313 auto response = network::mojom::URLResponseHead::New();
314 response->ssl_info = net::SSLInfo();
Emily Stark1225b892019-07-03 05:51:34315 net::CertificateList certs;
316 ASSERT_TRUE(net::LoadCertificateFiles(
317 {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
318 ASSERT_EQ(2U, certs.size());
319
320 base::StringPiece cert0_der =
321 net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
322 base::StringPiece cert1_der =
323 net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
324
Lucas Gadanif7430a742019-10-11 17:42:14325 response->ssl_info->cert =
Emily Stark1225b892019-07-03 05:51:34326 net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
327 net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
Lucas Gadanif7430a742019-10-11 17:42:14328 &response->ssl_info->connection_status);
Emily Stark1225b892019-07-03 05:51:34329
Lucas Furukawa Gadanieeddf2de2019-08-01 23:37:57330 auto common_params = CreateCommonNavigationParams();
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51331 common_params->url = GURL("https://example.test");
Lucas Furukawa Gadania9c45682019-07-31 22:05:14332 auto commit_params = CreateCommitNavigationParams();
Emily Stark1225b892019-07-03 05:51:34333
334 blink::WebNavigationParams navigation_params;
arthursonzognid5a8d0b2021-03-11 17:36:43335 navigation_params.sandbox_flags = network::mojom::WebSandboxFlags::kNone;
Emily Stark1225b892019-07-03 05:51:34336 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
Minggang Wang83f7f3712019-11-16 11:28:16337 mojo::ScopedDataPipeProducerHandle producer_handle;
338 mojo::ScopedDataPipeConsumerHandle consumer_handle;
339 MojoResult rv =
Robert Sesek3bce5dd2021-02-19 19:27:58340 mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle);
Minggang Wang83f7f3712019-11-16 11:28:16341 ASSERT_EQ(MOJO_RESULT_OK, rv);
Emily Stark1225b892019-07-03 05:51:34342 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Minggang Wange0d5db32020-10-07 15:55:31343 std::move(common_params), std::move(commit_params), /*request_id=*/1,
Minggang Wang83f7f3712019-11-16 11:28:16344 std::move(response), std::move(consumer_handle), std::move(endpoints),
Emily Stark1225b892019-07-03 05:51:34345 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
Minggang Wange0d5db32020-10-07 15:55:31346 /*render_frame_impl=*/nullptr, /*is_main_frame=*/true,
347 &navigation_params);
Emily Stark1225b892019-07-03 05:51:34348 EXPECT_TRUE(
349 navigation_params.response.SecurityDetailsForTesting().has_value());
350}
351
Dmitry Gozmancd3529822019-01-11 21:12:16352} // namespace
353
354} // namespace content