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