1 // Copyright 2023 The Chromium Authors
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 "net/http/http_transaction_test_util.h"
6
7 #include <string>
8 #include <string_view>
9
10 #include "base/test/bind.h"
11 #include "base/test/task_environment.h"
12 #include "net/base/test_completion_callback.h"
13 #include "net/test/gtest_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace net {
17
18 namespace {
19
20 // Default transaction.
21 const MockTransaction kBasicTransaction = {
22 .url = "http://www.example.com/",
23 .method = "GET",
24 .request_time = base::Time(),
25 .request_headers = "",
26 .load_flags = LOAD_NORMAL,
27 .transport_info = TransportInfo(TransportType::kDirect,
28 IPEndPoint(IPAddress::IPv4Localhost(), 80),
29 /*accept_ch_frame_arg=*/"",
30 /*cert_is_issued_by_known_root=*/false,
31 kProtoUnknown),
32 .status = "HTTP/1.1 200 OK",
33 .response_headers = "Cache-Control: max-age=10000\n",
34 .response_time = base::Time(),
35 .data = "<html><body>Hello world!</body></html>",
36 .dns_aliases = {},
37 .fps_cache_filter = std::nullopt,
38 .browser_run_id = std::nullopt,
39 .test_mode = TEST_MODE_NORMAL,
40 .handler = MockTransactionHandler(),
41 .read_handler = MockTransactionReadHandler(),
42 .cert = nullptr,
43 .cert_status = 0,
44 .ssl_connection_status = 0,
45 .start_return_code = OK,
46 .read_return_code = OK,
47 };
48 const size_t kDefaultBufferSize = 1024;
49
50 } // namespace
51
52 class MockNetworkTransactionTest : public ::testing::Test {
53 public:
MockNetworkTransactionTest()54 MockNetworkTransactionTest()
55 : network_layer_(std::make_unique<MockNetworkLayer>()) {}
56 ~MockNetworkTransactionTest() override = default;
57
58 MockNetworkTransactionTest(const MockNetworkTransactionTest&) = delete;
59 MockNetworkTransactionTest& operator=(const MockNetworkTransactionTest&) =
60 delete;
61
62 protected:
CreateNetworkTransaction()63 std::unique_ptr<HttpTransaction> CreateNetworkTransaction() {
64 std::unique_ptr<HttpTransaction> network_transaction;
65 network_layer_->CreateTransaction(DEFAULT_PRIORITY, &network_transaction);
66 return network_transaction;
67 }
68
RunUntilIdle()69 void RunUntilIdle() { task_environment_.RunUntilIdle(); }
70
network_layer()71 MockNetworkLayer& network_layer() { return *network_layer_.get(); }
72
73 private:
74 std::unique_ptr<MockNetworkLayer> network_layer_;
75 base::test::TaskEnvironment task_environment_{
76 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
77 };
78
TEST_F(MockNetworkTransactionTest,Basic)79 TEST_F(MockNetworkTransactionTest, Basic) {
80 ScopedMockTransaction mock_transaction(kBasicTransaction);
81 HttpRequestInfo request = MockHttpRequest(mock_transaction);
82
83 auto transaction = CreateNetworkTransaction();
84 TestCompletionCallback start_callback;
85 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
86 NetLogWithSource()),
87 test::IsError(ERR_IO_PENDING));
88 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
89
90 EXPECT_FALSE(transaction->GetResponseInfo()->was_cached);
91 EXPECT_TRUE(transaction->GetResponseInfo()->network_accessed);
92 EXPECT_EQ(mock_transaction.transport_info.endpoint,
93 transaction->GetResponseInfo()->remote_endpoint);
94 EXPECT_FALSE(transaction->GetResponseInfo()->was_fetched_via_proxy);
95
96 scoped_refptr<IOBufferWithSize> buf =
97 base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
98 TestCompletionCallback read_callback;
99 ASSERT_THAT(
100 transaction->Read(buf.get(), buf->size(), read_callback.callback()),
101 test::IsError(ERR_IO_PENDING));
102 int read_result = read_callback.WaitForResult();
103 ASSERT_THAT(read_result, std::string_view(mock_transaction.data).size());
104 EXPECT_EQ(std::string_view(mock_transaction.data),
105 std::string_view(buf->data(), read_result));
106 }
107
TEST_F(MockNetworkTransactionTest,SyncNetStart)108 TEST_F(MockNetworkTransactionTest, SyncNetStart) {
109 ScopedMockTransaction mock_transaction(kBasicTransaction);
110 mock_transaction.test_mode = TEST_MODE_SYNC_NET_START;
111 HttpRequestInfo request = MockHttpRequest(mock_transaction);
112
113 auto transaction = CreateNetworkTransaction();
114 TestCompletionCallback start_callback;
115 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
116 NetLogWithSource()),
117 test::IsError(OK));
118
119 scoped_refptr<IOBufferWithSize> buf =
120 base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
121 TestCompletionCallback read_callback;
122 ASSERT_THAT(
123 transaction->Read(buf.get(), buf->size(), read_callback.callback()),
124 test::IsError(ERR_IO_PENDING));
125 int read_result = read_callback.WaitForResult();
126 ASSERT_THAT(read_result, std::string_view(mock_transaction.data).size());
127 EXPECT_EQ(std::string_view(mock_transaction.data),
128 std::string_view(buf->data(), read_result));
129 }
130
TEST_F(MockNetworkTransactionTest,AsyncNetStartFailure)131 TEST_F(MockNetworkTransactionTest, AsyncNetStartFailure) {
132 ScopedMockTransaction mock_transaction(kBasicTransaction);
133 mock_transaction.start_return_code = ERR_NETWORK_ACCESS_DENIED;
134 HttpRequestInfo request = MockHttpRequest(mock_transaction);
135
136 auto transaction = CreateNetworkTransaction();
137 TestCompletionCallback start_callback;
138 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
139 NetLogWithSource()),
140 test::IsError(ERR_IO_PENDING));
141 EXPECT_THAT(start_callback.WaitForResult(),
142 test::IsError(ERR_NETWORK_ACCESS_DENIED));
143 }
144
TEST_F(MockNetworkTransactionTest,SyncNetStartFailure)145 TEST_F(MockNetworkTransactionTest, SyncNetStartFailure) {
146 ScopedMockTransaction mock_transaction(kBasicTransaction);
147 mock_transaction.test_mode = TEST_MODE_SYNC_NET_START;
148 mock_transaction.start_return_code = ERR_NETWORK_ACCESS_DENIED;
149 HttpRequestInfo request = MockHttpRequest(mock_transaction);
150
151 auto transaction = CreateNetworkTransaction();
152 TestCompletionCallback start_callback;
153 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
154 NetLogWithSource()),
155 test::IsError(ERR_NETWORK_ACCESS_DENIED));
156 }
157
TEST_F(MockNetworkTransactionTest,BeforeNetworkStartCallback)158 TEST_F(MockNetworkTransactionTest, BeforeNetworkStartCallback) {
159 ScopedMockTransaction mock_transaction(kBasicTransaction);
160 HttpRequestInfo request = MockHttpRequest(mock_transaction);
161
162 auto transaction = CreateNetworkTransaction();
163 bool before_network_start_callback_called = false;
164 transaction->SetBeforeNetworkStartCallback(base::BindLambdaForTesting(
165 [&](bool* defer) { before_network_start_callback_called = true; }));
166
167 TestCompletionCallback start_callback;
168 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
169 NetLogWithSource()),
170 test::IsError(ERR_IO_PENDING));
171 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
172 EXPECT_TRUE(before_network_start_callback_called);
173 }
174
TEST_F(MockNetworkTransactionTest,BeforeNetworkStartCallbackDeferAndResume)175 TEST_F(MockNetworkTransactionTest, BeforeNetworkStartCallbackDeferAndResume) {
176 ScopedMockTransaction mock_transaction(kBasicTransaction);
177 HttpRequestInfo request = MockHttpRequest(mock_transaction);
178
179 auto transaction = CreateNetworkTransaction();
180 bool before_network_start_callback_called = false;
181 transaction->SetBeforeNetworkStartCallback(
182 base::BindLambdaForTesting([&](bool* defer) {
183 before_network_start_callback_called = true;
184 *defer = true;
185 }));
186
187 TestCompletionCallback start_callback;
188 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
189 NetLogWithSource()),
190 test::IsError(ERR_IO_PENDING));
191 EXPECT_TRUE(before_network_start_callback_called);
192 RunUntilIdle();
193 EXPECT_FALSE(start_callback.have_result());
194 transaction->ResumeNetworkStart();
195 EXPECT_FALSE(start_callback.have_result());
196 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
197 }
198
TEST_F(MockNetworkTransactionTest,AsyncConnectedCallback)199 TEST_F(MockNetworkTransactionTest, AsyncConnectedCallback) {
200 ScopedMockTransaction mock_transaction(kBasicTransaction);
201 HttpRequestInfo request = MockHttpRequest(mock_transaction);
202
203 auto transaction = CreateNetworkTransaction();
204 bool connected_callback_called = false;
205 CompletionOnceCallback callback_for_connected_callback;
206 transaction->SetConnectedCallback(base::BindLambdaForTesting(
207 [&](const TransportInfo& info, CompletionOnceCallback callback) -> int {
208 EXPECT_EQ(mock_transaction.transport_info, info);
209 connected_callback_called = true;
210 callback_for_connected_callback = std::move(callback);
211 return ERR_IO_PENDING;
212 }));
213
214 TestCompletionCallback start_callback;
215 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
216 NetLogWithSource()),
217 test::IsError(ERR_IO_PENDING));
218 RunUntilIdle();
219 EXPECT_TRUE(connected_callback_called);
220 EXPECT_FALSE(start_callback.have_result());
221 std::move(callback_for_connected_callback).Run(OK);
222 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
223 }
224
TEST_F(MockNetworkTransactionTest,AsyncConnectedCallbackFailure)225 TEST_F(MockNetworkTransactionTest, AsyncConnectedCallbackFailure) {
226 ScopedMockTransaction mock_transaction(kBasicTransaction);
227 HttpRequestInfo request = MockHttpRequest(mock_transaction);
228
229 auto transaction = CreateNetworkTransaction();
230 bool connected_callback_called = false;
231 CompletionOnceCallback callback_for_connected_callback;
232 transaction->SetConnectedCallback(base::BindLambdaForTesting(
233 [&](const TransportInfo& info, CompletionOnceCallback callback) -> int {
234 EXPECT_EQ(mock_transaction.transport_info, info);
235 connected_callback_called = true;
236 callback_for_connected_callback = std::move(callback);
237 return ERR_IO_PENDING;
238 }));
239
240 TestCompletionCallback start_callback;
241 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
242 NetLogWithSource()),
243 test::IsError(ERR_IO_PENDING));
244 RunUntilIdle();
245 EXPECT_TRUE(connected_callback_called);
246 EXPECT_FALSE(start_callback.have_result());
247 std::move(callback_for_connected_callback).Run(ERR_INSUFFICIENT_RESOURCES);
248 EXPECT_THAT(start_callback.WaitForResult(),
249 test::IsError(ERR_INSUFFICIENT_RESOURCES));
250 }
251
TEST_F(MockNetworkTransactionTest,SyncConnectedCallback)252 TEST_F(MockNetworkTransactionTest, SyncConnectedCallback) {
253 ScopedMockTransaction mock_transaction(kBasicTransaction);
254 HttpRequestInfo request = MockHttpRequest(mock_transaction);
255
256 auto transaction = CreateNetworkTransaction();
257 bool connected_callback_called = false;
258 transaction->SetConnectedCallback(base::BindLambdaForTesting(
259 [&](const TransportInfo& info, CompletionOnceCallback callback) -> int {
260 EXPECT_EQ(mock_transaction.transport_info, info);
261 connected_callback_called = true;
262 return OK;
263 }));
264
265 TestCompletionCallback start_callback;
266 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
267 NetLogWithSource()),
268 test::IsError(ERR_IO_PENDING));
269 RunUntilIdle();
270 EXPECT_TRUE(connected_callback_called);
271 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
272 }
273
TEST_F(MockNetworkTransactionTest,SyncConnectedCallbackFailure)274 TEST_F(MockNetworkTransactionTest, SyncConnectedCallbackFailure) {
275 ScopedMockTransaction mock_transaction(kBasicTransaction);
276 HttpRequestInfo request = MockHttpRequest(mock_transaction);
277
278 auto transaction = CreateNetworkTransaction();
279 bool connected_callback_called = false;
280 transaction->SetConnectedCallback(base::BindLambdaForTesting(
281 [&](const TransportInfo& info, CompletionOnceCallback callback) -> int {
282 EXPECT_EQ(mock_transaction.transport_info, info);
283 connected_callback_called = true;
284 return ERR_INSUFFICIENT_RESOURCES;
285 }));
286
287 TestCompletionCallback start_callback;
288 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
289 NetLogWithSource()),
290 test::IsError(ERR_IO_PENDING));
291 RunUntilIdle();
292 EXPECT_TRUE(connected_callback_called);
293 EXPECT_THAT(start_callback.WaitForResult(),
294 test::IsError(ERR_INSUFFICIENT_RESOURCES));
295 }
296
TEST_F(MockNetworkTransactionTest,ModifyRequestHeadersCallback)297 TEST_F(MockNetworkTransactionTest, ModifyRequestHeadersCallback) {
298 const std::string kTestResponseData = "hello";
299 ScopedMockTransaction mock_transaction(kBasicTransaction);
300 mock_transaction.request_headers = "Foo: Bar\r\n";
301
302 bool transaction_handler_called = false;
303 mock_transaction.handler = base::BindLambdaForTesting(
304 [&](const HttpRequestInfo* request, std::string* response_status,
305 std::string* response_headers, std::string* response_data) {
306 EXPECT_EQ("Foo: Bar\r\nHoge: Piyo\r\n\r\n",
307 request->extra_headers.ToString());
308 *response_data = kTestResponseData;
309 transaction_handler_called = true;
310 });
311 HttpRequestInfo request = MockHttpRequest(mock_transaction);
312
313 auto transaction = CreateNetworkTransaction();
314 bool modify_request_headers_callback_called_ = false;
315 transaction->SetModifyRequestHeadersCallback(
316 base::BindLambdaForTesting([&](HttpRequestHeaders* request_headers) {
317 modify_request_headers_callback_called_ = true;
318 request_headers->SetHeader("Hoge", "Piyo");
319 }));
320
321 TestCompletionCallback start_callback;
322 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
323 NetLogWithSource()),
324 test::IsError(ERR_IO_PENDING));
325 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
326 EXPECT_TRUE(modify_request_headers_callback_called_);
327 EXPECT_TRUE(transaction_handler_called);
328
329 scoped_refptr<IOBufferWithSize> buf =
330 base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
331 TestCompletionCallback read_callback;
332 ASSERT_THAT(
333 transaction->Read(buf.get(), buf->size(), read_callback.callback()),
334 test::IsError(ERR_IO_PENDING));
335 int read_result = read_callback.WaitForResult();
336 ASSERT_THAT(read_result, kTestResponseData.size());
337 EXPECT_EQ(kTestResponseData, std::string_view(buf->data(), read_result));
338 }
339
TEST_F(MockNetworkTransactionTest,CallbackOrder)340 TEST_F(MockNetworkTransactionTest, CallbackOrder) {
341 const std::string kTestResponseData = "hello";
342 ScopedMockTransaction mock_transaction(kBasicTransaction);
343 mock_transaction.request_headers = "Foo: Bar\r\n";
344
345 bool before_network_start_callback_called = false;
346 bool connected_callback_called = false;
347 bool modify_request_headers_callback_called_ = false;
348 bool transaction_handler_called = false;
349
350 mock_transaction.handler = base::BindLambdaForTesting(
351 [&](const HttpRequestInfo* request, std::string* response_status,
352 std::string* response_headers, std::string* response_data) {
353 EXPECT_TRUE(before_network_start_callback_called);
354 EXPECT_TRUE(connected_callback_called);
355 EXPECT_TRUE(modify_request_headers_callback_called_);
356 EXPECT_FALSE(transaction_handler_called);
357
358 *response_data = kTestResponseData;
359 transaction_handler_called = true;
360 });
361
362 HttpRequestInfo request = MockHttpRequest(mock_transaction);
363
364 auto transaction = CreateNetworkTransaction();
365 transaction->SetBeforeNetworkStartCallback(
366 base::BindLambdaForTesting([&](bool* defer) {
367 EXPECT_FALSE(before_network_start_callback_called);
368 EXPECT_FALSE(connected_callback_called);
369 EXPECT_FALSE(modify_request_headers_callback_called_);
370 EXPECT_FALSE(transaction_handler_called);
371
372 before_network_start_callback_called = true;
373 *defer = true;
374 }));
375
376 CompletionOnceCallback callback_for_connected_callback;
377 transaction->SetConnectedCallback(base::BindLambdaForTesting(
378 [&](const TransportInfo& info, CompletionOnceCallback callback) -> int {
379 EXPECT_TRUE(before_network_start_callback_called);
380 EXPECT_FALSE(connected_callback_called);
381 EXPECT_FALSE(modify_request_headers_callback_called_);
382 EXPECT_FALSE(transaction_handler_called);
383
384 connected_callback_called = true;
385 callback_for_connected_callback = std::move(callback);
386 return ERR_IO_PENDING;
387 }));
388
389 transaction->SetModifyRequestHeadersCallback(
390 base::BindLambdaForTesting([&](HttpRequestHeaders* request_headers) {
391 EXPECT_TRUE(before_network_start_callback_called);
392 EXPECT_TRUE(connected_callback_called);
393 EXPECT_FALSE(modify_request_headers_callback_called_);
394 EXPECT_FALSE(transaction_handler_called);
395
396 modify_request_headers_callback_called_ = true;
397 }));
398
399 EXPECT_FALSE(before_network_start_callback_called);
400 TestCompletionCallback start_callback;
401 ASSERT_THAT(transaction->Start(&request, start_callback.callback(),
402 NetLogWithSource()),
403 test::IsError(ERR_IO_PENDING));
404
405 EXPECT_TRUE(before_network_start_callback_called);
406
407 EXPECT_FALSE(connected_callback_called);
408 transaction->ResumeNetworkStart();
409 RunUntilIdle();
410 EXPECT_TRUE(connected_callback_called);
411
412 EXPECT_FALSE(modify_request_headers_callback_called_);
413 std::move(callback_for_connected_callback).Run(OK);
414 EXPECT_TRUE(modify_request_headers_callback_called_);
415 EXPECT_TRUE(transaction_handler_called);
416
417 EXPECT_TRUE(start_callback.have_result());
418 EXPECT_THAT(start_callback.WaitForResult(), test::IsError(OK));
419 }
420
421 } // namespace net
422