blob: 7624d3f54c23489848d68d42eb1327acefdde1de [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() {
44 data_pipe_ = std::make_unique<mojo::DataPipe>(CreateDataPipeOptions());
45 writer_ = std::move(data_pipe_->producer_handle);
46 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:3047 endpoints->url_loader_client = client_remote_.BindNewPipeAndPassReceiver();
Dmitry Gozman00fd5bb2019-01-25 20:25:3348 blink::WebNavigationParams navigation_params;
Lucas Furukawa Gadanieeddf2de2019-08-01 23:37:5749 auto common_params = CreateCommonNavigationParams();
Lucas Furukawa Gadania9c45682019-07-31 22:05:1450 auto commit_params = CreateCommitNavigationParams();
Dmitry Gozman00fd5bb2019-01-25 20:25:3351 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Minggang Wange0d5db32020-10-07 15:55:3152 std::move(common_params), std::move(commit_params), /*request_id=*/1,
Lucas Gadanif7430a742019-10-11 17:42:1453 network::mojom::URLResponseHead::New(),
Minggang Wang83f7f3712019-11-16 11:28:1654 std::move(data_pipe_->consumer_handle), std::move(endpoints),
Dmitry Gozmancd3529822019-01-11 21:12:1655 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
Minggang Wange0d5db32020-10-07 15:55:3156 /*render_frame_impl=*/nullptr, /*is_main_frame=*/true,
57 &navigation_params);
Dmitry Gozman00fd5bb2019-01-25 20:25:3358 loader_ = std::move(navigation_params.body_loader);
Dmitry Gozmancd3529822019-01-11 21:12:1659 }
60
61 void StartLoading() {
62 loader_->StartLoadingBody(this, false /* use_isolated_code_cache */);
Dmitry Gozmancd3529822019-01-11 21:12:1663 base::RunLoop().RunUntilIdle();
64 }
65
66 void Write(const std::string& buffer) {
67 uint32_t size = buffer.size();
68 MojoResult result = writer_->WriteData(buffer.c_str(), &size, kNone);
69 ASSERT_EQ(MOJO_RESULT_OK, result);
70 ASSERT_EQ(buffer.size(), size);
71 }
72
73 void Complete(int net_error) {
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:3074 client_remote_->OnComplete(network::URLLoaderCompletionStatus(net_error));
Dmitry Gozmancd3529822019-01-11 21:12:1675 base::RunLoop().RunUntilIdle();
76 }
77
Bill Budge4405d8d52019-08-22 16:45:4578 void BodyCodeCacheReceived(mojo_base::BigBuffer data) override {}
Dmitry Gozmancd3529822019-01-11 21:12:1679
80 void BodyDataReceived(base::span<const char> data) override {
81 ASSERT_TRUE(expecting_data_received_);
82 did_receive_data_ = true;
83 data_received_ += std::string(data.data(), data.size());
84 TakeActions();
85 if (run_loop_.running())
86 run_loop_.Quit();
87 }
88
89 void BodyLoadingFinished(
90 base::TimeTicks completion_time,
91 int64_t total_encoded_data_length,
92 int64_t total_encoded_body_length,
93 int64_t total_decoded_body_length,
94 bool should_report_corb_blocking,
95 const base::Optional<blink::WebURLError>& error) override {
96 ASSERT_TRUE(expecting_finished_);
97 did_finish_ = true;
98 error_ = error;
99 TakeActions();
100 if (run_loop_.running())
101 run_loop_.Quit();
102 }
103
104 void TakeActions() {
105 if (!buffer_to_write_.empty()) {
106 std::string buffer = buffer_to_write_;
107 buffer_to_write_ = std::string();
108 ExpectDataReceived();
109 Write(buffer);
110 }
111 if (toggle_defers_loading_) {
112 toggle_defers_loading_ = false;
113 loader_->SetDefersLoading(false);
114 loader_->SetDefersLoading(true);
115 }
116 if (destroy_loader_) {
117 destroy_loader_ = false;
118 loader_.reset();
119 }
120 }
121
122 void ExpectDataReceived() {
123 expecting_data_received_ = true;
124 did_receive_data_ = false;
125 }
126
127 void ExpectFinished() {
128 expecting_finished_ = true;
129 did_finish_ = false;
130 }
131
132 std::string TakeDataReceived() {
133 std::string data = data_received_;
134 data_received_ = std::string();
135 return data;
136 }
137
138 void Wait() {
139 if (expecting_data_received_) {
140 if (!did_receive_data_)
141 run_loop_.Run();
142 ASSERT_TRUE(did_receive_data_);
143 expecting_data_received_ = false;
144 }
145 if (expecting_finished_) {
146 if (!did_finish_)
147 run_loop_.Run();
148 ASSERT_TRUE(did_finish_);
149 expecting_finished_ = false;
150 }
151 }
152
Gabriel Charette694c3c332019-08-19 14:53:05153 base::test::TaskEnvironment task_environment_;
Dmitry Gozmancd3529822019-01-11 21:12:16154 static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
Julie Jeongeun Kim6dd4c7b2019-11-18 05:56:30155 mojo::Remote<network::mojom::URLLoaderClient> client_remote_;
Dmitry Gozmancd3529822019-01-11 21:12:16156 std::unique_ptr<blink::WebNavigationBodyLoader> loader_;
157 std::unique_ptr<mojo::DataPipe> data_pipe_;
158 mojo::ScopedDataPipeProducerHandle writer_;
159
160 base::RunLoop run_loop_;
161 bool expecting_data_received_ = false;
162 bool did_receive_data_ = false;
163 bool expecting_finished_ = false;
164 bool did_finish_ = false;
165 std::string buffer_to_write_;
166 bool toggle_defers_loading_ = false;
167 bool destroy_loader_ = false;
168 std::string data_received_;
169 base::Optional<blink::WebURLError> error_;
170};
171
Dmitry Gozman98e8b192019-01-17 13:15:24172TEST_F(NavigationBodyLoaderTest, SetDefersBeforeStart) {
173 CreateBodyLoader();
174 loader_->SetDefersLoading(true);
175 loader_->SetDefersLoading(false);
176 // Should not crash.
177}
178
Dmitry Gozmancd3529822019-01-11 21:12:16179TEST_F(NavigationBodyLoaderTest, DataReceived) {
180 CreateBodyLoader();
181 StartLoading();
182 ExpectDataReceived();
183 Write("hello");
184 Wait();
185 EXPECT_EQ("hello", TakeDataReceived());
186}
187
188TEST_F(NavigationBodyLoaderTest, DataReceivedFromDataReceived) {
189 CreateBodyLoader();
190 StartLoading();
191 ExpectDataReceived();
192 buffer_to_write_ = "world";
193 Write("hello");
194 Wait();
195 EXPECT_EQ("helloworld", TakeDataReceived());
196}
197
198TEST_F(NavigationBodyLoaderTest, DestroyFromDataReceived) {
199 CreateBodyLoader();
200 StartLoading();
201 ExpectDataReceived();
202 destroy_loader_ = false;
203 Write("hello");
204 Wait();
205 EXPECT_EQ("hello", TakeDataReceived());
206}
207
208TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromDataReceived) {
209 CreateBodyLoader();
210 StartLoading();
211 ExpectDataReceived();
212 toggle_defers_loading_ = true;
213 Write("hello");
214 Wait();
215 EXPECT_EQ("hello", TakeDataReceived());
216}
217
218TEST_F(NavigationBodyLoaderTest, StartDeferred) {
219 CreateBodyLoader();
220 loader_->SetDefersLoading(true);
221 StartLoading();
222 Write("hello");
223 ExpectDataReceived();
224 loader_->SetDefersLoading(false);
225 Wait();
226 EXPECT_EQ("hello", TakeDataReceived());
227}
228
229TEST_F(NavigationBodyLoaderTest, OnCompleteThenClose) {
230 CreateBodyLoader();
231 StartLoading();
232 Complete(net::ERR_FAILED);
233 ExpectFinished();
234 writer_.reset();
235 Wait();
236 EXPECT_TRUE(error_.has_value());
237}
238
239TEST_F(NavigationBodyLoaderTest, DestroyFromOnCompleteThenClose) {
240 CreateBodyLoader();
241 StartLoading();
242 Complete(net::ERR_FAILED);
243 ExpectFinished();
244 destroy_loader_ = true;
245 writer_.reset();
246 Wait();
247 EXPECT_TRUE(error_.has_value());
248}
249
250TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromOnCompleteThenClose) {
251 CreateBodyLoader();
252 StartLoading();
253 Complete(net::ERR_FAILED);
254 ExpectFinished();
255 toggle_defers_loading_ = true;
256 writer_.reset();
257 Wait();
258 EXPECT_TRUE(error_.has_value());
259}
260
261TEST_F(NavigationBodyLoaderTest, CloseThenOnComplete) {
262 CreateBodyLoader();
263 StartLoading();
264 writer_.reset();
265 ExpectFinished();
266 Complete(net::ERR_FAILED);
267 Wait();
268 EXPECT_TRUE(error_.has_value());
269}
270
271TEST_F(NavigationBodyLoaderTest, DestroyFromCloseThenOnComplete) {
272 CreateBodyLoader();
273 StartLoading();
274 writer_.reset();
275 ExpectFinished();
276 destroy_loader_ = true;
277 Complete(net::ERR_FAILED);
278 Wait();
279 EXPECT_TRUE(error_.has_value());
280}
281
282TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromCloseThenOnComplete) {
283 CreateBodyLoader();
284 StartLoading();
285 writer_.reset();
286 ExpectFinished();
287 toggle_defers_loading_ = true;
288 Complete(net::ERR_FAILED);
289 Wait();
290 EXPECT_TRUE(error_.has_value());
291}
292
Emily Stark1225b892019-07-03 05:51:34293// Tests that FillNavigationParamsResponseAndBodyLoader populates security
294// details on the response when they are present.
295TEST_F(NavigationBodyLoaderTest, FillResponseWithSecurityDetails) {
Lucas Gadanif7430a742019-10-11 17:42:14296 auto response = network::mojom::URLResponseHead::New();
297 response->ssl_info = net::SSLInfo();
Emily Stark1225b892019-07-03 05:51:34298 net::CertificateList certs;
299 ASSERT_TRUE(net::LoadCertificateFiles(
300 {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
301 ASSERT_EQ(2U, certs.size());
302
303 base::StringPiece cert0_der =
304 net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
305 base::StringPiece cert1_der =
306 net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
307
Lucas Gadanif7430a742019-10-11 17:42:14308 response->ssl_info->cert =
Emily Stark1225b892019-07-03 05:51:34309 net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
310 net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
Lucas Gadanif7430a742019-10-11 17:42:14311 &response->ssl_info->connection_status);
Emily Stark1225b892019-07-03 05:51:34312
Lucas Furukawa Gadanieeddf2de2019-08-01 23:37:57313 auto common_params = CreateCommonNavigationParams();
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51314 common_params->url = GURL("https://example.test");
Lucas Furukawa Gadania9c45682019-07-31 22:05:14315 auto commit_params = CreateCommitNavigationParams();
Emily Stark1225b892019-07-03 05:51:34316
317 blink::WebNavigationParams navigation_params;
318 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
Minggang Wang83f7f3712019-11-16 11:28:16319 mojo::ScopedDataPipeProducerHandle producer_handle;
320 mojo::ScopedDataPipeConsumerHandle consumer_handle;
321 MojoResult rv =
322 mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
323 ASSERT_EQ(MOJO_RESULT_OK, rv);
Emily Stark1225b892019-07-03 05:51:34324 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Minggang Wange0d5db32020-10-07 15:55:31325 std::move(common_params), std::move(commit_params), /*request_id=*/1,
Minggang Wang83f7f3712019-11-16 11:28:16326 std::move(response), std::move(consumer_handle), std::move(endpoints),
Emily Stark1225b892019-07-03 05:51:34327 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
Minggang Wange0d5db32020-10-07 15:55:31328 /*render_frame_impl=*/nullptr, /*is_main_frame=*/true,
329 &navigation_params);
Emily Stark1225b892019-07-03 05:51:34330 EXPECT_TRUE(
331 navigation_params.response.SecurityDetailsForTesting().has_value());
332}
333
Dmitry Gozmancd3529822019-01-11 21:12:16334} // namespace
335
336} // namespace content