blob: 6f364a3350416fa82125e8f1f16bf2ea12f13d7d [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"
11#include "base/test/scoped_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 Gadanief8290a2019-07-29 20:27:5148 auto common_params = mojom::CommonNavigationParams::New();
49 common_params->referrer = blink::mojom::Referrer::New();
50 common_params->navigation_start = base::TimeTicks::Now();
Dmitry Gozman00fd5bb2019-01-25 20:25:3351 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Owen Min45db3a5d2019-07-31 20:13:2952 *common_params, CommitNavigationParams(), 1 /* request_id */,
Minggang Wang47a78222019-06-28 17:05:4653 network::ResourceResponseHead(),
54 mojo::ScopedDataPipeConsumerHandle() /* response_body */,
55 std::move(endpoints),
Dmitry Gozmancd3529822019-01-11 21:12:1656 blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
Dmitry Gozman00fd5bb2019-01-25 20:25:3357 2 /* render_frame_id */, true /* is_main_frame */, &navigation_params);
58 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 */);
63 client_ptr_->OnStartLoadingResponseBody(
64 std::move(data_pipe_->consumer_handle));
65 base::RunLoop().RunUntilIdle();
66 }
67
68 void Write(const std::string& buffer) {
69 uint32_t size = buffer.size();
70 MojoResult result = writer_->WriteData(buffer.c_str(), &size, kNone);
71 ASSERT_EQ(MOJO_RESULT_OK, result);
72 ASSERT_EQ(buffer.size(), size);
73 }
74
75 void Complete(int net_error) {
76 client_ptr_->OnComplete(network::URLLoaderCompletionStatus(net_error));
77 base::RunLoop().RunUntilIdle();
78 }
79
80 void BodyCodeCacheReceived(base::span<const uint8_t>) override {}
81
82 void BodyDataReceived(base::span<const char> data) override {
83 ASSERT_TRUE(expecting_data_received_);
84 did_receive_data_ = true;
85 data_received_ += std::string(data.data(), data.size());
86 TakeActions();
87 if (run_loop_.running())
88 run_loop_.Quit();
89 }
90
91 void BodyLoadingFinished(
92 base::TimeTicks completion_time,
93 int64_t total_encoded_data_length,
94 int64_t total_encoded_body_length,
95 int64_t total_decoded_body_length,
96 bool should_report_corb_blocking,
97 const base::Optional<blink::WebURLError>& error) override {
98 ASSERT_TRUE(expecting_finished_);
99 did_finish_ = true;
100 error_ = error;
101 TakeActions();
102 if (run_loop_.running())
103 run_loop_.Quit();
104 }
105
106 void TakeActions() {
107 if (!buffer_to_write_.empty()) {
108 std::string buffer = buffer_to_write_;
109 buffer_to_write_ = std::string();
110 ExpectDataReceived();
111 Write(buffer);
112 }
113 if (toggle_defers_loading_) {
114 toggle_defers_loading_ = false;
115 loader_->SetDefersLoading(false);
116 loader_->SetDefersLoading(true);
117 }
118 if (destroy_loader_) {
119 destroy_loader_ = false;
120 loader_.reset();
121 }
122 }
123
124 void ExpectDataReceived() {
125 expecting_data_received_ = true;
126 did_receive_data_ = false;
127 }
128
129 void ExpectFinished() {
130 expecting_finished_ = true;
131 did_finish_ = false;
132 }
133
134 std::string TakeDataReceived() {
135 std::string data = data_received_;
136 data_received_ = std::string();
137 return data;
138 }
139
140 void Wait() {
141 if (expecting_data_received_) {
142 if (!did_receive_data_)
143 run_loop_.Run();
144 ASSERT_TRUE(did_receive_data_);
145 expecting_data_received_ = false;
146 }
147 if (expecting_finished_) {
148 if (!did_finish_)
149 run_loop_.Run();
150 ASSERT_TRUE(did_finish_);
151 expecting_finished_ = false;
152 }
153 }
154
155 base::test::ScopedTaskEnvironment task_environment_;
156 static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
157 network::mojom::URLLoaderClientPtr client_ptr_;
158 std::unique_ptr<blink::WebNavigationBodyLoader> loader_;
159 std::unique_ptr<mojo::DataPipe> data_pipe_;
160 mojo::ScopedDataPipeProducerHandle writer_;
161
162 base::RunLoop run_loop_;
163 bool expecting_data_received_ = false;
164 bool did_receive_data_ = false;
165 bool expecting_finished_ = false;
166 bool did_finish_ = false;
167 std::string buffer_to_write_;
168 bool toggle_defers_loading_ = false;
169 bool destroy_loader_ = false;
170 std::string data_received_;
171 base::Optional<blink::WebURLError> error_;
172};
173
Dmitry Gozman98e8b192019-01-17 13:15:24174TEST_F(NavigationBodyLoaderTest, SetDefersBeforeStart) {
175 CreateBodyLoader();
176 loader_->SetDefersLoading(true);
177 loader_->SetDefersLoading(false);
178 // Should not crash.
179}
180
Dmitry Gozmancd3529822019-01-11 21:12:16181TEST_F(NavigationBodyLoaderTest, DataReceived) {
182 CreateBodyLoader();
183 StartLoading();
184 ExpectDataReceived();
185 Write("hello");
186 Wait();
187 EXPECT_EQ("hello", TakeDataReceived());
188}
189
190TEST_F(NavigationBodyLoaderTest, DataReceivedFromDataReceived) {
191 CreateBodyLoader();
192 StartLoading();
193 ExpectDataReceived();
194 buffer_to_write_ = "world";
195 Write("hello");
196 Wait();
197 EXPECT_EQ("helloworld", TakeDataReceived());
198}
199
200TEST_F(NavigationBodyLoaderTest, DestroyFromDataReceived) {
201 CreateBodyLoader();
202 StartLoading();
203 ExpectDataReceived();
204 destroy_loader_ = false;
205 Write("hello");
206 Wait();
207 EXPECT_EQ("hello", TakeDataReceived());
208}
209
210TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromDataReceived) {
211 CreateBodyLoader();
212 StartLoading();
213 ExpectDataReceived();
214 toggle_defers_loading_ = true;
215 Write("hello");
216 Wait();
217 EXPECT_EQ("hello", TakeDataReceived());
218}
219
220TEST_F(NavigationBodyLoaderTest, StartDeferred) {
221 CreateBodyLoader();
222 loader_->SetDefersLoading(true);
223 StartLoading();
224 Write("hello");
225 ExpectDataReceived();
226 loader_->SetDefersLoading(false);
227 Wait();
228 EXPECT_EQ("hello", TakeDataReceived());
229}
230
231TEST_F(NavigationBodyLoaderTest, OnCompleteThenClose) {
232 CreateBodyLoader();
233 StartLoading();
234 Complete(net::ERR_FAILED);
235 ExpectFinished();
236 writer_.reset();
237 Wait();
238 EXPECT_TRUE(error_.has_value());
239}
240
241TEST_F(NavigationBodyLoaderTest, DestroyFromOnCompleteThenClose) {
242 CreateBodyLoader();
243 StartLoading();
244 Complete(net::ERR_FAILED);
245 ExpectFinished();
246 destroy_loader_ = true;
247 writer_.reset();
248 Wait();
249 EXPECT_TRUE(error_.has_value());
250}
251
252TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromOnCompleteThenClose) {
253 CreateBodyLoader();
254 StartLoading();
255 Complete(net::ERR_FAILED);
256 ExpectFinished();
257 toggle_defers_loading_ = true;
258 writer_.reset();
259 Wait();
260 EXPECT_TRUE(error_.has_value());
261}
262
263TEST_F(NavigationBodyLoaderTest, CloseThenOnComplete) {
264 CreateBodyLoader();
265 StartLoading();
266 writer_.reset();
267 ExpectFinished();
268 Complete(net::ERR_FAILED);
269 Wait();
270 EXPECT_TRUE(error_.has_value());
271}
272
273TEST_F(NavigationBodyLoaderTest, DestroyFromCloseThenOnComplete) {
274 CreateBodyLoader();
275 StartLoading();
276 writer_.reset();
277 ExpectFinished();
278 destroy_loader_ = true;
279 Complete(net::ERR_FAILED);
280 Wait();
281 EXPECT_TRUE(error_.has_value());
282}
283
284TEST_F(NavigationBodyLoaderTest, SetDefersLoadingFromCloseThenOnComplete) {
285 CreateBodyLoader();
286 StartLoading();
287 writer_.reset();
288 ExpectFinished();
289 toggle_defers_loading_ = true;
290 Complete(net::ERR_FAILED);
291 Wait();
292 EXPECT_TRUE(error_.has_value());
293}
294
Emily Stark1225b892019-07-03 05:51:34295// Tests that FillNavigationParamsResponseAndBodyLoader populates security
296// details on the response when they are present.
297TEST_F(NavigationBodyLoaderTest, FillResponseWithSecurityDetails) {
298 network::ResourceResponseHead response;
299 response.ssl_info = net::SSLInfo();
300 net::CertificateList certs;
301 ASSERT_TRUE(net::LoadCertificateFiles(
302 {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
303 ASSERT_EQ(2U, certs.size());
304
305 base::StringPiece cert0_der =
306 net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
307 base::StringPiece cert1_der =
308 net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
309
310 response.ssl_info->cert =
311 net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
312 net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
313 &response.ssl_info->connection_status);
314
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51315 auto common_params = mojom::CommonNavigationParams::New();
316 common_params->referrer = blink::mojom::Referrer::New();
317 common_params->navigation_start = base::TimeTicks::Now();
318 common_params->url = GURL("https://example.test");
Emily Stark1225b892019-07-03 05:51:34319
320 blink::WebNavigationParams navigation_params;
321 auto endpoints = network::mojom::URLLoaderClientEndpoints::New();
322 NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
Owen Min45db3a5d2019-07-31 20:13:29323 *common_params, CommitNavigationParams(), 1 /* request_id */, response,
Emily Stark1225b892019-07-03 05:51:34324 mojo::ScopedDataPipeConsumerHandle() /* response_body */,
325 std::move(endpoints),
326 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