blob: 27b7573064c466bef3b77370f80d80921b374744 [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"
Emily Stark1225b892019-07-03 05:51:3413#include "net/cert/x509_util.h"
14#include "net/ssl/ssl_connection_status_flags.h"
15#include "net/test/cert_test_util.h"
Dmitry Gozmancd3529822019-01-11 21:12:1616#include "services/network/public/cpp/url_loader_completion_status.h"
17#include "testing/gtest/include/gtest/gtest.h"
18#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
19#include "third_party/blink/public/platform/web_navigation_body_loader.h"
Dmitry Gozman00fd5bb2019-01-25 20:25:3320#include "third_party/blink/public/web/web_navigation_params.h"
Dmitry Gozmancd3529822019-01-11 21:12:1621
22namespace content {
23
24namespace {
25
26class NavigationBodyLoaderTest : public ::testing::Test,
27 public blink::WebNavigationBodyLoader::Client {
28 protected:
29 NavigationBodyLoaderTest() {}
30
31 ~NavigationBodyLoaderTest() override { base::RunLoop().RunUntilIdle(); }
32
33 MojoCreateDataPipeOptions CreateDataPipeOptions() {
34 MojoCreateDataPipeOptions options;
35 options.struct_size = sizeof(MojoCreateDataPipeOptions);
36 options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
37 options.element_num_bytes = 1;
38 options.capacity_num_bytes = 1024;
39 return options;
40 }
41
42 void CreateBodyLoader() {
43 data_pipe_ = std::make_unique<mojo::DataPipe>(CreateDataPipeOptions());
44 writer_ = std::move(data_pipe_->producer_handle);
45 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
46 endpoints->url_loader_client = mojo::MakeRequest(&client_ptr_);
Dmitry Gozman00fd5bb2019-01-25 20:25:3347 blink::WebNavigationParams navigation_params;
Lucas Furukawa Gadanieeddf2de2019-08-01 23:37:5748 auto common_params = CreateCommonNavigationParams();
Lucas Furukawa Gadania9c45682019-07-31 22:05:1449 auto commit_params = CreateCommitNavigationParams();
Dmitry Gozman00fd5bb2019-01-25 20:25:3350 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Lucas Furukawa Gadani33cfdf832019-10-04 17:19:1951 std::move(common_params), std::move(commit_params), 1 /* request_id */,
Lucas Gadanif7430a742019-10-11 17:42:1452 network::mojom::URLResponseHead::New(),
Minggang Wang83f7f3712019-11-16 11:28:1653 std::move(data_pipe_->consumer_handle), std::move(endpoints),
Dmitry Gozmancd3529822019-01-11 21:12:1654 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
Dmitry Gozman00fd5bb2019-01-25 20:25:3355 2 /* render_frame_id */, true /* is_main_frame */, &navigation_params);
56 loader_ = std::move(navigation_params.body_loader);
Dmitry Gozmancd3529822019-01-11 21:12:1657 }
58
59 void StartLoading() {
60 loader_->StartLoadingBody(this, false /* use_isolated_code_cache */);
Dmitry Gozmancd3529822019-01-11 21:12:1661 base::RunLoop().RunUntilIdle();
62 }
63
64 void Write(const std::string& buffer) {
65 uint32_t size = buffer.size();
66 MojoResult result = writer_->WriteData(buffer.c_str(), &size, kNone);
67 ASSERT_EQ(MOJO_RESULT_OK, result);
68 ASSERT_EQ(buffer.size(), size);
69 }
70
71 void Complete(int net_error) {
72 client_ptr_->OnComplete(network::URLLoaderCompletionStatus(net_error));
73 base::RunLoop().RunUntilIdle();
74 }
75
Bill Budge4405d8d52019-08-22 16:45:4576 void BodyCodeCacheReceived(mojo_base::BigBuffer data) override {}
Dmitry Gozmancd3529822019-01-11 21:12:1677
78 void BodyDataReceived(base::span<const char> data) override {
79 ASSERT_TRUE(expecting_data_received_);
80 did_receive_data_ = true;
81 data_received_ += std::string(data.data(), data.size());
82 TakeActions();
83 if (run_loop_.running())
84 run_loop_.Quit();
85 }
86
87 void BodyLoadingFinished(
88 base::TimeTicks completion_time,
89 int64_t total_encoded_data_length,
90 int64_t total_encoded_body_length,
91 int64_t total_decoded_body_length,
92 bool should_report_corb_blocking,
93 const base::Optional<blink::WebURLError>& error) override {
94 ASSERT_TRUE(expecting_finished_);
95 did_finish_ = true;
96 error_ = error;
97 TakeActions();
98 if (run_loop_.running())
99 run_loop_.Quit();
100 }
101
102 void TakeActions() {
103 if (!buffer_to_write_.empty()) {
104 std::string buffer = buffer_to_write_;
105 buffer_to_write_ = std::string();
106 ExpectDataReceived();
107 Write(buffer);
108 }
109 if (toggle_defers_loading_) {
110 toggle_defers_loading_ = false;
111 loader_->SetDefersLoading(false);
112 loader_->SetDefersLoading(true);
113 }
114 if (destroy_loader_) {
115 destroy_loader_ = false;
116 loader_.reset();
117 }
118 }
119
120 void ExpectDataReceived() {
121 expecting_data_received_ = true;
122 did_receive_data_ = false;
123 }
124
125 void ExpectFinished() {
126 expecting_finished_ = true;
127 did_finish_ = false;
128 }
129
130 std::string TakeDataReceived() {
131 std::string data = data_received_;
132 data_received_ = std::string();
133 return data;
134 }
135
136 void Wait() {
137 if (expecting_data_received_) {
138 if (!did_receive_data_)
139 run_loop_.Run();
140 ASSERT_TRUE(did_receive_data_);
141 expecting_data_received_ = false;
142 }
143 if (expecting_finished_) {
144 if (!did_finish_)
145 run_loop_.Run();
146 ASSERT_TRUE(did_finish_);
147 expecting_finished_ = false;
148 }
149 }
150
Gabriel Charette694c3c332019-08-19 14:53:05151 base::test::TaskEnvironment task_environment_;
Dmitry Gozmancd3529822019-01-11 21:12:16152 static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
153 network::mojom::URLLoaderClientPtr client_ptr_;
154 std::unique_ptr<blink::WebNavigationBodyLoader> loader_;
155 std::unique_ptr<mojo::DataPipe> data_pipe_;
156 mojo::ScopedDataPipeProducerHandle writer_;
157
158 base::RunLoop run_loop_;
159 bool expecting_data_received_ = false;
160 bool did_receive_data_ = false;
161 bool expecting_finished_ = false;
162 bool did_finish_ = false;
163 std::string buffer_to_write_;
164 bool toggle_defers_loading_ = false;
165 bool destroy_loader_ = false;
166 std::string data_received_;
167 base::Optional<blink::WebURLError> error_;
168};
169
Dmitry Gozman98e8b192019-01-17 13:15:24170TEST_F(NavigationBodyLoaderTest, SetDefersBeforeStart) {
171 CreateBodyLoader();
172 loader_->SetDefersLoading(true);
173 loader_->SetDefersLoading(false);
174 // Should not crash.
175}
176
Dmitry Gozmancd3529822019-01-11 21:12:16177TEST_F(NavigationBodyLoaderTest, DataReceived) {
178 CreateBodyLoader();
179 StartLoading();
180 ExpectDataReceived();
181 Write("hello");
182 Wait();
183 EXPECT_EQ("hello", TakeDataReceived());
184}
185
186TEST_F(NavigationBodyLoaderTest, DataReceivedFromDataReceived) {
187 CreateBodyLoader();
188 StartLoading();
189 ExpectDataReceived();
190 buffer_to_write_ = "world";
191 Write("hello");
192 Wait();
193 EXPECT_EQ("helloworld", TakeDataReceived());
194}
195
196TEST_F(NavigationBodyLoaderTest, DestroyFromDataReceived) {
197 CreateBodyLoader();
198 StartLoading();
199 ExpectDataReceived();
200 destroy_loader_ = false;
201 Write("hello");
202 Wait();
203 EXPECT_EQ("hello", TakeDataReceived());
204}
205
206TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromDataReceived) {
207 CreateBodyLoader();
208 StartLoading();
209 ExpectDataReceived();
210 toggle_defers_loading_ = true;
211 Write("hello");
212 Wait();
213 EXPECT_EQ("hello", TakeDataReceived());
214}
215
216TEST_F(NavigationBodyLoaderTest, StartDeferred) {
217 CreateBodyLoader();
218 loader_->SetDefersLoading(true);
219 StartLoading();
220 Write("hello");
221 ExpectDataReceived();
222 loader_->SetDefersLoading(false);
223 Wait();
224 EXPECT_EQ("hello", TakeDataReceived());
225}
226
227TEST_F(NavigationBodyLoaderTest, OnCompleteThenClose) {
228 CreateBodyLoader();
229 StartLoading();
230 Complete(net::ERR_FAILED);
231 ExpectFinished();
232 writer_.reset();
233 Wait();
234 EXPECT_TRUE(error_.has_value());
235}
236
237TEST_F(NavigationBodyLoaderTest, DestroyFromOnCompleteThenClose) {
238 CreateBodyLoader();
239 StartLoading();
240 Complete(net::ERR_FAILED);
241 ExpectFinished();
242 destroy_loader_ = true;
243 writer_.reset();
244 Wait();
245 EXPECT_TRUE(error_.has_value());
246}
247
248TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromOnCompleteThenClose) {
249 CreateBodyLoader();
250 StartLoading();
251 Complete(net::ERR_FAILED);
252 ExpectFinished();
253 toggle_defers_loading_ = true;
254 writer_.reset();
255 Wait();
256 EXPECT_TRUE(error_.has_value());
257}
258
259TEST_F(NavigationBodyLoaderTest, CloseThenOnComplete) {
260 CreateBodyLoader();
261 StartLoading();
262 writer_.reset();
263 ExpectFinished();
264 Complete(net::ERR_FAILED);
265 Wait();
266 EXPECT_TRUE(error_.has_value());
267}
268
269TEST_F(NavigationBodyLoaderTest, DestroyFromCloseThenOnComplete) {
270 CreateBodyLoader();
271 StartLoading();
272 writer_.reset();
273 ExpectFinished();
274 destroy_loader_ = true;
275 Complete(net::ERR_FAILED);
276 Wait();
277 EXPECT_TRUE(error_.has_value());
278}
279
280TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromCloseThenOnComplete) {
281 CreateBodyLoader();
282 StartLoading();
283 writer_.reset();
284 ExpectFinished();
285 toggle_defers_loading_ = true;
286 Complete(net::ERR_FAILED);
287 Wait();
288 EXPECT_TRUE(error_.has_value());
289}
290
Emily Stark1225b892019-07-03 05:51:34291// Tests that FillNavigationParamsResponseAndBodyLoader populates security
292// details on the response when they are present.
293TEST_F(NavigationBodyLoaderTest, FillResponseWithSecurityDetails) {
Lucas Gadanif7430a742019-10-11 17:42:14294 auto response = network::mojom::URLResponseHead::New();
295 response->ssl_info = net::SSLInfo();
Emily Stark1225b892019-07-03 05:51:34296 net::CertificateList certs;
297 ASSERT_TRUE(net::LoadCertificateFiles(
298 {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
299 ASSERT_EQ(2U, certs.size());
300
301 base::StringPiece cert0_der =
302 net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
303 base::StringPiece cert1_der =
304 net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
305
Lucas Gadanif7430a742019-10-11 17:42:14306 response->ssl_info->cert =
Emily Stark1225b892019-07-03 05:51:34307 net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
308 net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
Lucas Gadanif7430a742019-10-11 17:42:14309 &response->ssl_info->connection_status);
Emily Stark1225b892019-07-03 05:51:34310
Lucas Furukawa Gadanieeddf2de2019-08-01 23:37:57311 auto common_params = CreateCommonNavigationParams();
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51312 common_params->url = GURL("https://example.test");
Lucas Furukawa Gadania9c45682019-07-31 22:05:14313 auto commit_params = CreateCommitNavigationParams();
Emily Stark1225b892019-07-03 05:51:34314
315 blink::WebNavigationParams navigation_params;
316 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
Minggang Wang83f7f3712019-11-16 11:28:16317 mojo::ScopedDataPipeProducerHandle producer_handle;
318 mojo::ScopedDataPipeConsumerHandle consumer_handle;
319 MojoResult rv =
320 mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
321 ASSERT_EQ(MOJO_RESULT_OK, rv);
Emily Stark1225b892019-07-03 05:51:34322 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Lucas Furukawa Gadani33cfdf832019-10-04 17:19:19323 std::move(common_params), std::move(commit_params), 1 /* request_id */,
Minggang Wang83f7f3712019-11-16 11:28:16324 std::move(response), std::move(consumer_handle), std::move(endpoints),
Emily Stark1225b892019-07-03 05:51:34325 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
326 2 /* render_frame_id */, true /* is_main_frame */, &navigation_params);
327 EXPECT_TRUE(
328 navigation_params.response.SecurityDetailsForTesting().has_value());
329}
330
Dmitry Gozmancd3529822019-01-11 21:12:16331} // namespace
332
333} // namespace content