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