1 // Copyright 2024 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_stream_pool_group.h"
6
7 #include <memory>
8
9 #include "base/functional/callback_helpers.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "base/test/task_environment.h"
12 #include "net/base/address_list.h"
13 #include "net/base/completion_once_callback.h"
14 #include "net/base/ip_address.h"
15 #include "net/base/network_anonymization_key.h"
16 #include "net/base/network_change_notifier.h"
17 #include "net/base/privacy_mode.h"
18 #include "net/http/http_network_session.h"
19 #include "net/http/http_stream.h"
20 #include "net/http/http_stream_pool.h"
21 #include "net/http/http_stream_pool_test_util.h"
22 #include "net/log/net_log.h"
23 #include "net/socket/socket_test_util.h"
24 #include "net/socket/stream_socket.h"
25 #include "net/spdy/spdy_test_util_common.h"
26 #include "net/test/gtest_util.h"
27 #include "net/test/test_with_task_environment.h"
28 #include "url/scheme_host_port.h"
29
30 namespace net {
31
32 using test::IsOk;
33
34 using Group = HttpStreamPool::Group;
35
36 class HttpStreamPoolGroupTest : public TestWithTaskEnvironment {
37 public:
HttpStreamPoolGroupTest()38 HttpStreamPoolGroupTest()
39 : TestWithTaskEnvironment(
40 base::test::TaskEnvironment::TimeSource::MOCK_TIME),
41 default_test_key_(url::SchemeHostPort("http", "a.test", 80),
42 PRIVACY_MODE_DISABLED,
43 SocketTag(),
44 NetworkAnonymizationKey(),
45 SecureDnsPolicy::kAllow,
46 /*disable_cert_network_fetches=*/false) {
47 feature_list_.InitAndEnableFeature(features::kHappyEyeballsV3);
48 session_deps_.ignore_ip_address_changes = false;
49 session_deps_.disable_idle_sockets_close_on_memory_pressure = false;
50 InitializePool();
51 }
52
53 protected:
set_ignore_ip_address_changes(bool ignore_ip_address_changes)54 void set_ignore_ip_address_changes(bool ignore_ip_address_changes) {
55 session_deps_.ignore_ip_address_changes = ignore_ip_address_changes;
56 }
57
set_disable_idle_sockets_close_on_memory_pressure(bool disable_idle_sockets_close_on_memory_pressure)58 void set_disable_idle_sockets_close_on_memory_pressure(
59 bool disable_idle_sockets_close_on_memory_pressure) {
60 session_deps_.disable_idle_sockets_close_on_memory_pressure =
61 disable_idle_sockets_close_on_memory_pressure;
62 }
63
set_enable_quic(bool enable_quic)64 void set_enable_quic(bool enable_quic) {
65 session_deps_.enable_quic = enable_quic;
66 }
67
InitializePool()68 void InitializePool() {
69 http_network_session_ =
70 SpdySessionDependencies::SpdyCreateSession(&session_deps_);
71 }
72
GetOrCreateTestGroup()73 Group& GetOrCreateTestGroup() {
74 return pool().GetOrCreateGroupForTesting(default_test_key_);
75 }
76
GetTestGroup()77 Group* GetTestGroup() { return pool().GetGroupForTesting(default_test_key_); }
78
pool()79 HttpStreamPool& pool() { return *http_network_session_->http_stream_pool(); }
80
DestroyHttpNetworkSession()81 void DestroyHttpNetworkSession() { http_network_session_.reset(); }
82
83 private:
84 base::test::ScopedFeatureList feature_list_;
85 const HttpStreamKey default_test_key_;
86 // For creating HttpNetworkSession.
87 SpdySessionDependencies session_deps_;
88 std::unique_ptr<HttpNetworkSession> http_network_session_;
89 };
90
TEST_F(HttpStreamPoolGroupTest,CreateTextBasedStream)91 TEST_F(HttpStreamPoolGroupTest, CreateTextBasedStream) {
92 auto stream_socket = std::make_unique<FakeStreamSocket>();
93
94 Group& group = GetOrCreateTestGroup();
95 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
96 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
97 LoadTimingInfo::ConnectTiming());
98 CHECK(stream);
99 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
100 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
101 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
102 }
103
TEST_F(HttpStreamPoolGroupTest,ReleaseStreamSocketUnused)104 TEST_F(HttpStreamPoolGroupTest, ReleaseStreamSocketUnused) {
105 auto stream_socket = std::make_unique<FakeStreamSocket>();
106
107 Group& group = GetOrCreateTestGroup();
108 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
109 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
110 LoadTimingInfo::ConnectTiming());
111 CHECK(stream);
112
113 stream.reset();
114 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
115 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
116 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
117
118 FastForwardBy(Group::kUnusedIdleStreamSocketTimeout);
119 group.CleanupTimedoutIdleStreamSocketsForTesting();
120 ASSERT_EQ(group.ActiveStreamSocketCount(), 0u);
121 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
122 ASSERT_EQ(pool().TotalActiveStreamCount(), 0u);
123 }
124
TEST_F(HttpStreamPoolGroupTest,ReleaseStreamSocketUsed)125 TEST_F(HttpStreamPoolGroupTest, ReleaseStreamSocketUsed) {
126 auto stream_socket = std::make_unique<FakeStreamSocket>();
127 stream_socket->set_was_ever_used(true);
128
129 Group& group = GetOrCreateTestGroup();
130 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
131 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
132 LoadTimingInfo::ConnectTiming());
133 CHECK(stream);
134
135 stream.reset();
136 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
137 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
138 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
139
140 static_assert(Group::kUnusedIdleStreamSocketTimeout <=
141 Group::kUsedIdleStreamSocketTimeout);
142
143 FastForwardBy(Group::kUnusedIdleStreamSocketTimeout);
144 group.CleanupTimedoutIdleStreamSocketsForTesting();
145 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
146 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
147 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
148
149 FastForwardBy(Group::kUsedIdleStreamSocketTimeout);
150 group.CleanupTimedoutIdleStreamSocketsForTesting();
151 ASSERT_EQ(group.ActiveStreamSocketCount(), 0u);
152 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
153 ASSERT_EQ(pool().TotalActiveStreamCount(), 0u);
154 }
155
TEST_F(HttpStreamPoolGroupTest,ReleaseStreamSocketNotIdle)156 TEST_F(HttpStreamPoolGroupTest, ReleaseStreamSocketNotIdle) {
157 auto stream_socket = std::make_unique<FakeStreamSocket>();
158 stream_socket->set_is_idle(false);
159
160 Group& group = GetOrCreateTestGroup();
161 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
162 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
163 LoadTimingInfo::ConnectTiming());
164 CHECK(stream);
165
166 stream.reset();
167
168 ASSERT_FALSE(GetTestGroup());
169 }
170
TEST_F(HttpStreamPoolGroupTest,IdleSocketDisconnected)171 TEST_F(HttpStreamPoolGroupTest, IdleSocketDisconnected) {
172 auto stream_socket = std::make_unique<FakeStreamSocket>();
173 FakeStreamSocket* raw_stream_socket = stream_socket.get();
174
175 Group& group = GetOrCreateTestGroup();
176 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
177 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
178 LoadTimingInfo::ConnectTiming());
179 CHECK(stream);
180
181 stream.reset();
182 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
183 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
184 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
185
186 raw_stream_socket->set_is_connected(false);
187 group.CleanupTimedoutIdleStreamSocketsForTesting();
188 ASSERT_EQ(group.ActiveStreamSocketCount(), 0u);
189 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
190 }
191
TEST_F(HttpStreamPoolGroupTest,IdleSocketReceivedDataUnexpectedly)192 TEST_F(HttpStreamPoolGroupTest, IdleSocketReceivedDataUnexpectedly) {
193 auto stream_socket = std::make_unique<FakeStreamSocket>();
194 FakeStreamSocket* raw_stream_socket = stream_socket.get();
195
196 Group& group = GetOrCreateTestGroup();
197 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
198 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
199 LoadTimingInfo::ConnectTiming());
200 CHECK(stream);
201
202 stream.reset();
203 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
204 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
205 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
206
207 // Simulate the socket was used and not idle (received data).
208 raw_stream_socket->set_was_ever_used(true);
209 raw_stream_socket->set_is_idle(false);
210
211 group.CleanupTimedoutIdleStreamSocketsForTesting();
212 ASSERT_EQ(group.ActiveStreamSocketCount(), 0u);
213 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
214 }
215
TEST_F(HttpStreamPoolGroupTest,GetIdleStreamSocket)216 TEST_F(HttpStreamPoolGroupTest, GetIdleStreamSocket) {
217 Group& group = GetOrCreateTestGroup();
218 ASSERT_FALSE(group.GetIdleStreamSocket());
219
220 auto stream_socket = std::make_unique<FakeStreamSocket>();
221 group.AddIdleStreamSocket(std::move(stream_socket));
222 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
223
224 std::unique_ptr<StreamSocket> socket = group.GetIdleStreamSocket();
225 ASSERT_TRUE(socket);
226 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
227 }
228
TEST_F(HttpStreamPoolGroupTest,GetIdleStreamSocketPreferUsed)229 TEST_F(HttpStreamPoolGroupTest, GetIdleStreamSocketPreferUsed) {
230 Group& group = GetOrCreateTestGroup();
231
232 // Add 3 idle streams. the first and the third ones are marked as used.
233 auto stream_socket1 = std::make_unique<FakeStreamSocket>();
234 auto stream_socket2 = std::make_unique<FakeStreamSocket>();
235 auto stream_socket3 = std::make_unique<FakeStreamSocket>();
236
237 stream_socket1->set_was_ever_used(true);
238 stream_socket3->set_was_ever_used(true);
239
240 stream_socket1->set_peer_addr(IPEndPoint(IPAddress(192, 0, 2, 1), 80));
241 stream_socket2->set_peer_addr(IPEndPoint(IPAddress(192, 0, 2, 2), 80));
242 stream_socket3->set_peer_addr(IPEndPoint(IPAddress(192, 0, 2, 3), 80));
243
244 group.AddIdleStreamSocket(std::move(stream_socket1));
245 group.AddIdleStreamSocket(std::move(stream_socket2));
246 group.AddIdleStreamSocket(std::move(stream_socket3));
247 ASSERT_EQ(group.IdleStreamSocketCount(), 3u);
248
249 std::unique_ptr<StreamSocket> socket = group.GetIdleStreamSocket();
250 ASSERT_TRUE(socket);
251 ASSERT_EQ(group.IdleStreamSocketCount(), 2u);
252
253 IPEndPoint peer;
254 int rv = socket->GetPeerAddress(&peer);
255 EXPECT_THAT(rv, IsOk());
256 EXPECT_THAT(peer, IPEndPoint(IPAddress(192, 0, 2, 3), 80));
257 }
258
TEST_F(HttpStreamPoolGroupTest,GetIdleStreamSocketDisconnectedDuringIdle)259 TEST_F(HttpStreamPoolGroupTest, GetIdleStreamSocketDisconnectedDuringIdle) {
260 Group& group = GetOrCreateTestGroup();
261 ASSERT_FALSE(group.GetIdleStreamSocket());
262
263 auto stream_socket = std::make_unique<FakeStreamSocket>();
264 FakeStreamSocket* raw_stream_socket = stream_socket.get();
265 group.AddIdleStreamSocket(std::move(stream_socket));
266 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
267
268 raw_stream_socket->set_is_connected(false);
269 ASSERT_FALSE(group.GetIdleStreamSocket());
270 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
271 }
272
TEST_F(HttpStreamPoolGroupTest,GetIdleStreamSocketUsedSocketDisconnected)273 TEST_F(HttpStreamPoolGroupTest, GetIdleStreamSocketUsedSocketDisconnected) {
274 Group& group = GetOrCreateTestGroup();
275 ASSERT_FALSE(group.GetIdleStreamSocket());
276
277 auto stream_socket = std::make_unique<FakeStreamSocket>();
278 FakeStreamSocket* raw_stream_socket = stream_socket.get();
279 group.AddIdleStreamSocket(std::move(stream_socket));
280 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
281
282 raw_stream_socket->set_was_ever_used(true);
283 raw_stream_socket->set_is_connected(false);
284 ASSERT_FALSE(group.GetIdleStreamSocket());
285 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
286 }
287
TEST_F(HttpStreamPoolGroupTest,GetIdleStreamSocketTimedout)288 TEST_F(HttpStreamPoolGroupTest, GetIdleStreamSocketTimedout) {
289 Group& group = GetOrCreateTestGroup();
290
291 auto stream_socket = std::make_unique<FakeStreamSocket>();
292 group.AddIdleStreamSocket(std::move(stream_socket));
293 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
294
295 FastForwardBy(HttpStreamPool::Group::kUnusedIdleStreamSocketTimeout);
296
297 ASSERT_FALSE(group.GetIdleStreamSocket());
298 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
299 }
300
301 // Test that a group is destroyed when closing an idle stream that is the last
302 // stream in the group.
TEST_F(HttpStreamPoolGroupTest,DestroyGroupAfterCloseOneIdleStream)303 TEST_F(HttpStreamPoolGroupTest, DestroyGroupAfterCloseOneIdleStream) {
304 Group& group = GetOrCreateTestGroup();
305
306 auto stream_socket = std::make_unique<FakeStreamSocket>();
307 group.AddIdleStreamSocket(std::move(stream_socket));
308 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
309
310 ASSERT_TRUE(group.CloseOneIdleStreamSocket());
311 FastForwardUntilNoTasksRemain();
312 ASSERT_FALSE(GetTestGroup());
313 }
314
TEST_F(HttpStreamPoolGroupTest,IPAddressChangeCleanupIdleSocket)315 TEST_F(HttpStreamPoolGroupTest, IPAddressChangeCleanupIdleSocket) {
316 auto stream_socket = std::make_unique<FakeStreamSocket>();
317
318 Group& group = GetOrCreateTestGroup();
319 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
320 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
321 LoadTimingInfo::ConnectTiming());
322 CHECK(stream);
323
324 stream.reset();
325 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
326 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
327 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
328
329 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
330 RunUntilIdle();
331
332 group.CleanupTimedoutIdleStreamSocketsForTesting();
333 ASSERT_EQ(group.ActiveStreamSocketCount(), 0u);
334 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
335 }
336
TEST_F(HttpStreamPoolGroupTest,IPAddressChangeReleaseStreamSocket)337 TEST_F(HttpStreamPoolGroupTest, IPAddressChangeReleaseStreamSocket) {
338 auto stream_socket = std::make_unique<FakeStreamSocket>();
339
340 Group& group = GetOrCreateTestGroup();
341 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
342 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
343 LoadTimingInfo::ConnectTiming());
344 CHECK(stream);
345
346 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
347 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
348 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
349
350 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
351 RunUntilIdle();
352
353 stream.reset();
354
355 ASSERT_FALSE(GetTestGroup());
356 }
357
TEST_F(HttpStreamPoolGroupTest,IPAddressChangeIgnored)358 TEST_F(HttpStreamPoolGroupTest, IPAddressChangeIgnored) {
359 set_ignore_ip_address_changes(true);
360 InitializePool();
361
362 auto stream_socket = std::make_unique<FakeStreamSocket>();
363 Group& group = GetOrCreateTestGroup();
364 std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
365 std::move(stream_socket), StreamSocketHandle::SocketReuseType::kUnused,
366 LoadTimingInfo::ConnectTiming());
367 CHECK(stream);
368
369 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
370 ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
371 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
372
373 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
374 RunUntilIdle();
375
376 stream.reset();
377
378 group.CleanupTimedoutIdleStreamSocketsForTesting();
379 ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
380 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
381 ASSERT_EQ(pool().TotalActiveStreamCount(), 1u);
382 }
383
TEST_F(HttpStreamPoolGroupTest,FlushIdleStreamsOnMemoryPressure)384 TEST_F(HttpStreamPoolGroupTest, FlushIdleStreamsOnMemoryPressure) {
385 set_disable_idle_sockets_close_on_memory_pressure(false);
386 InitializePool();
387
388 {
389 Group& group = GetOrCreateTestGroup();
390 ASSERT_FALSE(group.GetIdleStreamSocket());
391
392 group.AddIdleStreamSocket(std::make_unique<FakeStreamSocket>());
393 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
394
395 // Idle sockets should be flushed on moderate memory pressure and `group`
396 // should be destroyed.
397 base::MemoryPressureListener::NotifyMemoryPressure(
398 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
399 FastForwardUntilNoTasksRemain();
400 ASSERT_FALSE(GetTestGroup());
401 }
402
403 {
404 Group& group = GetOrCreateTestGroup();
405 group.AddIdleStreamSocket(std::make_unique<FakeStreamSocket>());
406 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
407
408 // Idle sockets should be flushed on critical memory pressure and `group`
409 // should be destroyed.
410 base::MemoryPressureListener::NotifyMemoryPressure(
411 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
412 FastForwardUntilNoTasksRemain();
413 ASSERT_FALSE(GetTestGroup());
414 }
415 }
416
TEST_F(HttpStreamPoolGroupTest,MemoryPressureDisabled)417 TEST_F(HttpStreamPoolGroupTest, MemoryPressureDisabled) {
418 set_disable_idle_sockets_close_on_memory_pressure(true);
419 InitializePool();
420
421 Group& group = GetOrCreateTestGroup();
422 ASSERT_FALSE(group.GetIdleStreamSocket());
423
424 group.AddIdleStreamSocket(std::make_unique<FakeStreamSocket>());
425 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
426
427 // Idle sockets should be not flushed on moderate memory pressure.
428 base::MemoryPressureListener::NotifyMemoryPressure(
429 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
430 base::RunLoop().RunUntilIdle();
431 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
432
433 // Idle sockets should be not flushed on critical memory pressure.
434 base::MemoryPressureListener::NotifyMemoryPressure(
435 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
436 base::RunLoop().RunUntilIdle();
437 ASSERT_EQ(group.IdleStreamSocketCount(), 1u);
438 }
439
TEST_F(HttpStreamPoolGroupTest,DestroySessionWhileStreamAlive)440 TEST_F(HttpStreamPoolGroupTest, DestroySessionWhileStreamAlive) {
441 std::unique_ptr<HttpStream> stream =
442 GetOrCreateTestGroup().CreateTextBasedStream(
443 std::make_unique<FakeStreamSocket>(),
444 StreamSocketHandle::SocketReuseType::kUnused,
445 LoadTimingInfo::ConnectTiming());
446 CHECK(stream);
447
448 // Destroy the session. This should not cause a crash.
449 DestroyHttpNetworkSession();
450 }
451
TEST_F(HttpStreamPoolGroupTest,EnableDisableQuic)452 TEST_F(HttpStreamPoolGroupTest, EnableDisableQuic) {
453 const url::SchemeHostPort kHost("https", "www.example.com", 443);
454
455 set_enable_quic(true);
456 InitializePool();
457 ASSERT_TRUE(pool().CanUseQuic(kHost, NetworkAnonymizationKey(),
458 /*enable_ip_based_pooling=*/true,
459 /*enable_alternative_services=*/true));
460
461 set_enable_quic(false);
462 InitializePool();
463 ASSERT_FALSE(pool().CanUseQuic(kHost, NetworkAnonymizationKey(),
464 /*enable_ip_based_pooling=*/true,
465 /*enable_alternative_services=*/true));
466 }
467
468 } // namespace net
469