spdy_session_pool_unittest.cc 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807
  1. // Copyright (c) 2013 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. #include "net/spdy/spdy_session_pool.h"
  5. #include <cstddef>
  6. #include <tuple>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/memory/ref_counted.h"
  12. #include "base/run_loop.h"
  13. #include "base/test/bind.h"
  14. #include "base/test/metrics/histogram_tester.h"
  15. #include "base/trace_event/memory_allocator_dump.h"
  16. #include "base/trace_event/process_memory_dump.h"
  17. #include "base/trace_event/traced_value.h"
  18. #include "build/build_config.h"
  19. #include "net/base/proxy_string_util.h"
  20. #include "net/base/test_completion_callback.h"
  21. #include "net/dns/host_cache.h"
  22. #include "net/dns/public/secure_dns_policy.h"
  23. #include "net/http/http_network_session.h"
  24. #include "net/log/net_log_with_source.h"
  25. #include "net/log/test_net_log.h"
  26. #include "net/socket/client_socket_handle.h"
  27. #include "net/socket/socket_tag.h"
  28. #include "net/socket/socket_test_util.h"
  29. #include "net/socket/transport_client_socket_pool.h"
  30. #include "net/spdy/spdy_session.h"
  31. #include "net/spdy/spdy_stream_test_util.h"
  32. #include "net/spdy/spdy_test_util_common.h"
  33. #include "net/test/cert_test_util.h"
  34. #include "net/test/gtest_util.h"
  35. #include "net/test/test_certificate_data.h"
  36. #include "net/test/test_data_directory.h"
  37. #include "net/test/test_with_task_environment.h"
  38. #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
  39. #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  40. #include "testing/gmock/include/gmock/gmock.h"
  41. #include "testing/gtest/include/gtest/gtest.h"
  42. using base::trace_event::MemoryAllocatorDump;
  43. using net::test::IsError;
  44. using net::test::IsOk;
  45. using testing::Contains;
  46. using testing::Eq;
  47. using testing::Contains;
  48. using testing::ByRef;
  49. namespace net {
  50. class SpdySessionPoolTest : public TestWithTaskEnvironment {
  51. protected:
  52. // Used by RunIPPoolingTest().
  53. enum SpdyPoolCloseSessionsType {
  54. SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
  55. SPDY_POOL_CLOSE_CURRENT_SESSIONS,
  56. SPDY_POOL_CLOSE_IDLE_SESSIONS,
  57. };
  58. SpdySessionPoolTest() = default;
  59. void CreateNetworkSession() {
  60. http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
  61. spdy_session_pool_ = http_session_->spdy_session_pool();
  62. }
  63. void AddSSLSocketData() {
  64. auto ssl = std::make_unique<SSLSocketDataProvider>(SYNCHRONOUS, OK);
  65. ssl->ssl_info.cert =
  66. ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
  67. ASSERT_TRUE(ssl->ssl_info.cert);
  68. session_deps_.socket_factory->AddSSLSocketDataProvider(ssl.get());
  69. ssl_data_vector_.push_back(std::move(ssl));
  70. }
  71. void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
  72. void RunIPPoolingDisabledTest(SSLSocketDataProvider* ssl);
  73. size_t num_active_streams(base::WeakPtr<SpdySession> session) {
  74. return session->active_streams_.size();
  75. }
  76. size_t max_concurrent_streams(base::WeakPtr<SpdySession> session) {
  77. return session->max_concurrent_streams_;
  78. }
  79. SpdySessionDependencies session_deps_;
  80. std::unique_ptr<HttpNetworkSession> http_session_;
  81. raw_ptr<SpdySessionPool> spdy_session_pool_ = nullptr;
  82. std::vector<std::unique_ptr<SSLSocketDataProvider>> ssl_data_vector_;
  83. };
  84. class SpdySessionRequestDelegate
  85. : public SpdySessionPool::SpdySessionRequest::Delegate {
  86. public:
  87. SpdySessionRequestDelegate() = default;
  88. SpdySessionRequestDelegate(const SpdySessionRequestDelegate&) = delete;
  89. SpdySessionRequestDelegate& operator=(const SpdySessionRequestDelegate&) =
  90. delete;
  91. ~SpdySessionRequestDelegate() override = default;
  92. void OnSpdySessionAvailable(
  93. base::WeakPtr<SpdySession> spdy_session) override {
  94. EXPECT_FALSE(callback_invoked_);
  95. callback_invoked_ = true;
  96. spdy_session_ = spdy_session;
  97. }
  98. bool callback_invoked() const { return callback_invoked_; }
  99. SpdySession* spdy_session() { return spdy_session_.get(); }
  100. private:
  101. bool callback_invoked_ = false;
  102. base::WeakPtr<SpdySession> spdy_session_;
  103. };
  104. // Attempts to set up an alias for |key| using an already existing session in
  105. // |pool|. To do this, simulates a host resolution that returns
  106. // |ip_address_list|.
  107. bool TryCreateAliasedSpdySession(SpdySessionPool* pool,
  108. const SpdySessionKey& key,
  109. const std::string& ip_address_list,
  110. bool enable_ip_based_pooling = true,
  111. bool is_websocket = false) {
  112. // The requested session must not already exist.
  113. EXPECT_FALSE(pool->FindAvailableSession(key, enable_ip_based_pooling,
  114. is_websocket, NetLogWithSource()));
  115. // Create a request for the session. There should be no matching session
  116. // (aliased or otherwise) yet. A pending request is necessary for the session
  117. // to create an alias on host resolution completion.
  118. std::unique_ptr<SpdySessionPool::SpdySessionRequest> request;
  119. bool is_blocking_request_for_session = false;
  120. SpdySessionRequestDelegate request_delegate;
  121. EXPECT_FALSE(pool->RequestSession(
  122. key, enable_ip_based_pooling, is_websocket, NetLogWithSource(),
  123. /* on_blocking_request_destroyed_callback = */ base::RepeatingClosure(),
  124. &request_delegate, &request, &is_blocking_request_for_session));
  125. EXPECT_TRUE(request);
  126. EXPECT_TRUE(is_blocking_request_for_session);
  127. AddressList address_list;
  128. EXPECT_THAT(ParseAddressList(ip_address_list, &address_list.endpoints()),
  129. IsOk());
  130. address_list = AddressList::CopyWithPort(address_list, 443);
  131. // Simulate a host resolution completing.
  132. OnHostResolutionCallbackResult result =
  133. pool->OnHostResolutionComplete(key, is_websocket, address_list);
  134. // Spin the message loop and see if it creates an H2 session.
  135. base::RunLoop().RunUntilIdle();
  136. EXPECT_EQ(request_delegate.callback_invoked(),
  137. result == OnHostResolutionCallbackResult::kMayBeDeletedAsync);
  138. EXPECT_EQ(request_delegate.callback_invoked(),
  139. request_delegate.spdy_session() != nullptr);
  140. request.reset();
  141. // Calling RequestSession again should return request_delegate.spdy_session()
  142. // (i.e. the newly created session, if a session was created, or nullptr, if
  143. // one was not.)
  144. EXPECT_EQ(request_delegate.spdy_session(),
  145. pool->RequestSession(key, enable_ip_based_pooling, is_websocket,
  146. NetLogWithSource(),
  147. /* on_blocking_request_destroyed_callback = */
  148. base::RepeatingClosure(), &request_delegate,
  149. &request, &is_blocking_request_for_session)
  150. .get());
  151. return request_delegate.spdy_session() != nullptr;
  152. }
  153. // A delegate that opens a new session when it is closed.
  154. class SessionOpeningDelegate : public SpdyStream::Delegate {
  155. public:
  156. SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
  157. const SpdySessionKey& key)
  158. : spdy_session_pool_(spdy_session_pool),
  159. key_(key) {}
  160. ~SessionOpeningDelegate() override = default;
  161. void OnHeadersSent() override {}
  162. void OnEarlyHintsReceived(const spdy::Http2HeaderBlock& headers) override {}
  163. void OnHeadersReceived(
  164. const spdy::Http2HeaderBlock& response_headers,
  165. const spdy::Http2HeaderBlock* pushed_request_headers) override {}
  166. void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) override {}
  167. void OnDataSent() override {}
  168. void OnTrailers(const spdy::Http2HeaderBlock& trailers) override {}
  169. void OnClose(int status) override {
  170. std::ignore = CreateFakeSpdySession(spdy_session_pool_, key_);
  171. }
  172. bool CanGreaseFrameType() const override { return false; }
  173. NetLogSource source_dependency() const override { return NetLogSource(); }
  174. private:
  175. const raw_ptr<SpdySessionPool> spdy_session_pool_;
  176. const SpdySessionKey key_;
  177. };
  178. // Set up a SpdyStream to create a new session when it is closed.
  179. // CloseCurrentSessions should not close the newly-created session.
  180. TEST_F(SpdySessionPoolTest, CloseCurrentSessions) {
  181. const char kTestHost[] = "www.foo.com";
  182. const int kTestPort = 80;
  183. HostPortPair test_host_port_pair(kTestHost, kTestPort);
  184. SpdySessionKey test_key = SpdySessionKey(
  185. test_host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
  186. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  187. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  188. MockConnect connect_data(SYNCHRONOUS, OK);
  189. MockRead reads[] = {
  190. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  191. };
  192. StaticSocketDataProvider data(reads, base::span<MockWrite>());
  193. data.set_connect_data(connect_data);
  194. session_deps_.socket_factory->AddSocketDataProvider(&data);
  195. SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
  196. session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
  197. CreateNetworkSession();
  198. // Setup the first session to the first host.
  199. base::WeakPtr<SpdySession> session =
  200. CreateSpdySession(http_session_.get(), test_key, NetLogWithSource());
  201. // Flush the SpdySession::OnReadComplete() task.
  202. base::RunLoop().RunUntilIdle();
  203. // Verify that we have sessions for everything.
  204. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
  205. // Set the stream to create a new session when it is closed.
  206. base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
  207. SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
  208. NetLogWithSource());
  209. SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
  210. spdy_stream->SetDelegate(&delegate);
  211. // Close the current session.
  212. spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
  213. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
  214. }
  215. TEST_F(SpdySessionPoolTest, CloseCurrentIdleSessions) {
  216. const std::string close_session_description = "Closing idle sessions.";
  217. MockConnect connect_data(SYNCHRONOUS, OK);
  218. MockRead reads[] = {
  219. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  220. };
  221. StaticSocketDataProvider data1(reads, base::span<MockWrite>());
  222. data1.set_connect_data(connect_data);
  223. session_deps_.socket_factory->AddSocketDataProvider(&data1);
  224. AddSSLSocketData();
  225. AddSSLSocketData();
  226. AddSSLSocketData();
  227. CreateNetworkSession();
  228. // Set up session 1
  229. const GURL url1("https://www.example.org");
  230. HostPortPair test_host_port_pair1(HostPortPair::FromURL(url1));
  231. SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
  232. PRIVACY_MODE_DISABLED,
  233. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  234. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  235. base::WeakPtr<SpdySession> session1 =
  236. CreateSpdySession(http_session_.get(), key1, NetLogWithSource());
  237. base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
  238. SPDY_BIDIRECTIONAL_STREAM, session1, url1, MEDIUM, NetLogWithSource());
  239. ASSERT_TRUE(spdy_stream1);
  240. // Set up session 2
  241. StaticSocketDataProvider data2(reads, base::span<MockWrite>());
  242. session_deps_.socket_factory->AddSocketDataProvider(&data2);
  243. const GURL url2("https://mail.example.org");
  244. HostPortPair test_host_port_pair2(HostPortPair::FromURL(url2));
  245. SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
  246. PRIVACY_MODE_DISABLED,
  247. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  248. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  249. base::WeakPtr<SpdySession> session2 =
  250. CreateSpdySession(http_session_.get(), key2, NetLogWithSource());
  251. base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
  252. SPDY_BIDIRECTIONAL_STREAM, session2, url2, MEDIUM, NetLogWithSource());
  253. ASSERT_TRUE(spdy_stream2);
  254. // Set up session 3
  255. StaticSocketDataProvider data3(reads, base::span<MockWrite>());
  256. data3.set_connect_data(connect_data);
  257. session_deps_.socket_factory->AddSocketDataProvider(&data3);
  258. const GURL url3("https://mail.example.com");
  259. HostPortPair test_host_port_pair3(HostPortPair::FromURL(url3));
  260. SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
  261. PRIVACY_MODE_DISABLED,
  262. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  263. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  264. base::WeakPtr<SpdySession> session3 =
  265. CreateSpdySession(http_session_.get(), key3, NetLogWithSource());
  266. base::WeakPtr<SpdyStream> spdy_stream3 = CreateStreamSynchronously(
  267. SPDY_BIDIRECTIONAL_STREAM, session3, url3, MEDIUM, NetLogWithSource());
  268. ASSERT_TRUE(spdy_stream3);
  269. // All sessions are active and not closed
  270. EXPECT_TRUE(session1->is_active());
  271. EXPECT_TRUE(session1->IsAvailable());
  272. EXPECT_TRUE(session2->is_active());
  273. EXPECT_TRUE(session2->IsAvailable());
  274. EXPECT_TRUE(session3->is_active());
  275. EXPECT_TRUE(session3->IsAvailable());
  276. // Should not do anything, all are active
  277. spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
  278. EXPECT_TRUE(session1->is_active());
  279. EXPECT_TRUE(session1->IsAvailable());
  280. EXPECT_TRUE(session2->is_active());
  281. EXPECT_TRUE(session2->IsAvailable());
  282. EXPECT_TRUE(session3->is_active());
  283. EXPECT_TRUE(session3->IsAvailable());
  284. // Make sessions 1 and 3 inactive, but keep them open.
  285. // Session 2 still open and active
  286. session1->CloseCreatedStream(spdy_stream1, OK);
  287. EXPECT_FALSE(spdy_stream1);
  288. session3->CloseCreatedStream(spdy_stream3, OK);
  289. EXPECT_FALSE(spdy_stream3);
  290. EXPECT_FALSE(session1->is_active());
  291. EXPECT_TRUE(session1->IsAvailable());
  292. EXPECT_TRUE(session2->is_active());
  293. EXPECT_TRUE(session2->IsAvailable());
  294. EXPECT_FALSE(session3->is_active());
  295. EXPECT_TRUE(session3->IsAvailable());
  296. // Should close session 1 and 3, 2 should be left open
  297. spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
  298. base::RunLoop().RunUntilIdle();
  299. EXPECT_FALSE(session1);
  300. EXPECT_TRUE(session2->is_active());
  301. EXPECT_TRUE(session2->IsAvailable());
  302. EXPECT_FALSE(session3);
  303. // Should not do anything
  304. spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
  305. base::RunLoop().RunUntilIdle();
  306. EXPECT_TRUE(session2->is_active());
  307. EXPECT_TRUE(session2->IsAvailable());
  308. // Make 2 not active
  309. session2->CloseCreatedStream(spdy_stream2, OK);
  310. base::RunLoop().RunUntilIdle();
  311. EXPECT_FALSE(spdy_stream2);
  312. EXPECT_FALSE(session2->is_active());
  313. EXPECT_TRUE(session2->IsAvailable());
  314. // This should close session 2
  315. spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
  316. base::RunLoop().RunUntilIdle();
  317. EXPECT_FALSE(session2);
  318. }
  319. // Set up a SpdyStream to create a new session when it is closed.
  320. // CloseAllSessions should close the newly-created session.
  321. TEST_F(SpdySessionPoolTest, CloseAllSessions) {
  322. const char kTestHost[] = "www.foo.com";
  323. const int kTestPort = 80;
  324. HostPortPair test_host_port_pair(kTestHost, kTestPort);
  325. SpdySessionKey test_key = SpdySessionKey(
  326. test_host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
  327. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  328. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  329. MockConnect connect_data(SYNCHRONOUS, OK);
  330. MockRead reads[] = {
  331. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  332. };
  333. StaticSocketDataProvider data(reads, base::span<MockWrite>());
  334. data.set_connect_data(connect_data);
  335. session_deps_.socket_factory->AddSocketDataProvider(&data);
  336. SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
  337. session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
  338. CreateNetworkSession();
  339. // Setup the first session to the first host.
  340. base::WeakPtr<SpdySession> session =
  341. CreateSpdySession(http_session_.get(), test_key, NetLogWithSource());
  342. // Flush the SpdySession::OnReadComplete() task.
  343. base::RunLoop().RunUntilIdle();
  344. // Verify that we have sessions for everything.
  345. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
  346. // Set the stream to create a new session when it is closed.
  347. base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
  348. SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
  349. NetLogWithSource());
  350. SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
  351. spdy_stream->SetDelegate(&delegate);
  352. // Close the current session.
  353. spdy_session_pool_->CloseAllSessions();
  354. EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
  355. }
  356. // Code testing SpdySessionPool::OnIPAddressChange requires a SpdySessionPool
  357. // with some active sessions. This fixture takes care of setting most things up
  358. // but doesn't create the pool yet, allowing tests to possibly further
  359. // configure sessions_deps_.
  360. class SpdySessionPoolOnIPAddressChangeTest : public SpdySessionPoolTest {
  361. protected:
  362. SpdySessionPoolOnIPAddressChangeTest()
  363. : test_host_port_pair_(kTestHost, kTestPort),
  364. reads_({
  365. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  366. }),
  367. test_key_(SpdySessionKey(test_host_port_pair_,
  368. ProxyServer::Direct(),
  369. PRIVACY_MODE_DISABLED,
  370. SpdySessionKey::IsProxySession::kFalse,
  371. SocketTag(),
  372. NetworkIsolationKey(),
  373. SecureDnsPolicy::kAllow)),
  374. connect_data_(SYNCHRONOUS, OK),
  375. data_(reads_, base::span<MockWrite>()),
  376. ssl_(SYNCHRONOUS, OK) {
  377. data_.set_connect_data(connect_data_);
  378. session_deps_.socket_factory->AddSocketDataProvider(&data_);
  379. session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
  380. }
  381. static constexpr char kTestHost[] = "www.foo.com";
  382. static constexpr int kTestPort = 80;
  383. static constexpr int kReadSize = 1;
  384. const HostPortPair test_host_port_pair_;
  385. const std::array<MockRead, kReadSize> reads_;
  386. const SpdySessionKey test_key_;
  387. const MockConnect connect_data_;
  388. StaticSocketDataProvider data_;
  389. SSLSocketDataProvider ssl_;
  390. };
  391. TEST_F(SpdySessionPoolOnIPAddressChangeTest, DoNotIgnoreIPAddressChanges) {
  392. // Default behavior should be ignore_ip_address_changes = false;
  393. CreateNetworkSession();
  394. base::WeakPtr<SpdySession> session =
  395. CreateSpdySession(http_session_.get(), test_key_, NetLogWithSource());
  396. // Flush the SpdySession::OnReadComplete() task.
  397. base::RunLoop().RunUntilIdle();
  398. // Verify that we have a session.
  399. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key_));
  400. // Without setting session_deps_.ignore_ip_address_changes = true the pool
  401. // should close (or make unavailable) all sessions after an IP address change.
  402. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
  403. base::RunLoop().RunUntilIdle();
  404. EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key_));
  405. }
  406. TEST_F(SpdySessionPoolOnIPAddressChangeTest, IgnoreIPAddressChanges) {
  407. session_deps_.ignore_ip_address_changes = true;
  408. CreateNetworkSession();
  409. // Setup the first session to the first host.
  410. base::WeakPtr<SpdySession> session =
  411. CreateSpdySession(http_session_.get(), test_key_, NetLogWithSource());
  412. // Flush the SpdySession::OnReadComplete() task.
  413. base::RunLoop().RunUntilIdle();
  414. // Verify that we have a session.
  415. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key_));
  416. // Since we set ignore_ip_address_changes = true, the session should still be
  417. // there after an IP address change.
  418. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
  419. base::RunLoop().RunUntilIdle();
  420. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key_));
  421. }
  422. // This test has three variants, one for each style of closing the connection.
  423. // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
  424. // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
  425. // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
  426. // sessions are closed with SpdySessionPool::CloseCurrentSessions().
  427. // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
  428. // sessions are closed with SpdySessionPool::CloseIdleSessions().
  429. void SpdySessionPoolTest::RunIPPoolingTest(
  430. SpdyPoolCloseSessionsType close_sessions_type) {
  431. constexpr int kTestPort = 443;
  432. struct TestHosts {
  433. std::string url;
  434. std::string name;
  435. std::string iplist;
  436. SpdySessionKey key;
  437. } test_hosts[] = {
  438. {"http://www.example.org", "www.example.org",
  439. "192.0.2.33,192.168.0.1,192.168.0.5"},
  440. {"http://mail.example.org", "mail.example.org",
  441. "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"},
  442. {"http://mail.example.com", "mail.example.com",
  443. "192.168.0.4,192.168.0.3"},
  444. };
  445. for (auto& test_host : test_hosts) {
  446. session_deps_.host_resolver->rules()->AddIPLiteralRule(
  447. test_host.name, test_host.iplist, std::string());
  448. test_host.key = SpdySessionKey(
  449. HostPortPair(test_host.name, kTestPort), ProxyServer::Direct(),
  450. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  451. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  452. }
  453. MockConnect connect_data(SYNCHRONOUS, OK);
  454. MockRead reads[] = {
  455. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  456. };
  457. StaticSocketDataProvider data1(reads, base::span<MockWrite>());
  458. data1.set_connect_data(connect_data);
  459. session_deps_.socket_factory->AddSocketDataProvider(&data1);
  460. AddSSLSocketData();
  461. CreateNetworkSession();
  462. // Setup the first session to the first host.
  463. base::WeakPtr<SpdySession> session = CreateSpdySession(
  464. http_session_.get(), test_hosts[0].key, NetLogWithSource());
  465. // Flush the SpdySession::OnReadComplete() task.
  466. base::RunLoop().RunUntilIdle();
  467. // The third host has no overlap with the first, so it can't pool IPs.
  468. EXPECT_FALSE(TryCreateAliasedSpdySession(
  469. spdy_session_pool_, test_hosts[2].key, test_hosts[2].iplist));
  470. // The second host overlaps with the first, and should IP pool.
  471. EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
  472. test_hosts[1].iplist));
  473. // However, if IP pooling is disabled, FindAvailableSession() should not find
  474. // |session| for the second host.
  475. base::WeakPtr<SpdySession> session1 =
  476. spdy_session_pool_->FindAvailableSession(
  477. test_hosts[1].key, /* enable_ip_based_pooling = */ false,
  478. /* is_websocket = */ false, NetLogWithSource());
  479. EXPECT_FALSE(session1);
  480. // Verify that the second host, through a proxy, won't share the IP, even if
  481. // the IP list matches.
  482. SpdySessionKey proxy_key(
  483. test_hosts[1].key.host_port_pair(),
  484. PacResultElementToProxyServer("HTTP http://proxy.foo.com/"),
  485. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  486. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  487. EXPECT_FALSE(TryCreateAliasedSpdySession(spdy_session_pool_, proxy_key,
  488. test_hosts[1].iplist));
  489. // Verify that the second host, with a different SecureDnsPolicy,
  490. // won't share the IP, even if the IP list matches.
  491. SpdySessionKey disable_secure_dns_key(
  492. test_hosts[1].key.host_port_pair(), ProxyServer::Direct(),
  493. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  494. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kDisable);
  495. EXPECT_FALSE(TryCreateAliasedSpdySession(
  496. spdy_session_pool_, disable_secure_dns_key, test_hosts[1].iplist));
  497. // Overlap between 2 and 3 is not transitive to 1.
  498. EXPECT_FALSE(TryCreateAliasedSpdySession(
  499. spdy_session_pool_, test_hosts[2].key, test_hosts[2].iplist));
  500. // Create a new session to host 2.
  501. StaticSocketDataProvider data2(reads, base::span<MockWrite>());
  502. data2.set_connect_data(connect_data);
  503. session_deps_.socket_factory->AddSocketDataProvider(&data2);
  504. AddSSLSocketData();
  505. base::WeakPtr<SpdySession> session2 = CreateSpdySession(
  506. http_session_.get(), test_hosts[2].key, NetLogWithSource());
  507. // Verify that we have sessions for everything.
  508. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
  509. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
  510. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
  511. // Grab the session to host 1 and verify that it is the same session
  512. // we got with host 0, and that is a different from host 2's session.
  513. session1 = spdy_session_pool_->FindAvailableSession(
  514. test_hosts[1].key, /* enable_ip_based_pooling = */ true,
  515. /* is_websocket = */ false, NetLogWithSource());
  516. EXPECT_EQ(session.get(), session1.get());
  517. EXPECT_NE(session2.get(), session1.get());
  518. // Remove the aliases and observe that we still have a session for host1.
  519. SpdySessionPoolPeer pool_peer(spdy_session_pool_);
  520. pool_peer.RemoveAliases(test_hosts[0].key);
  521. pool_peer.RemoveAliases(test_hosts[1].key);
  522. EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
  523. // Cleanup the sessions.
  524. switch (close_sessions_type) {
  525. case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
  526. session->CloseSessionOnError(ERR_ABORTED, std::string());
  527. session2->CloseSessionOnError(ERR_ABORTED, std::string());
  528. base::RunLoop().RunUntilIdle();
  529. EXPECT_FALSE(session);
  530. EXPECT_FALSE(session2);
  531. break;
  532. case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
  533. spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
  534. break;
  535. case SPDY_POOL_CLOSE_IDLE_SESSIONS:
  536. GURL url(test_hosts[0].url);
  537. base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
  538. SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
  539. GURL url1(test_hosts[1].url);
  540. base::WeakPtr<SpdyStream> spdy_stream1 =
  541. CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session1, url1,
  542. MEDIUM, NetLogWithSource());
  543. GURL url2(test_hosts[2].url);
  544. base::WeakPtr<SpdyStream> spdy_stream2 =
  545. CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session2, url2,
  546. MEDIUM, NetLogWithSource());
  547. // Close streams to make spdy_session and spdy_session1 inactive.
  548. session->CloseCreatedStream(spdy_stream, OK);
  549. EXPECT_FALSE(spdy_stream);
  550. session1->CloseCreatedStream(spdy_stream1, OK);
  551. EXPECT_FALSE(spdy_stream1);
  552. // Check spdy_session and spdy_session1 are not closed.
  553. EXPECT_FALSE(session->is_active());
  554. EXPECT_TRUE(session->IsAvailable());
  555. EXPECT_FALSE(session1->is_active());
  556. EXPECT_TRUE(session1->IsAvailable());
  557. EXPECT_TRUE(session2->is_active());
  558. EXPECT_TRUE(session2->IsAvailable());
  559. // Test that calling CloseIdleSessions, does not cause a crash.
  560. // http://crbug.com/181400
  561. spdy_session_pool_->CloseCurrentIdleSessions("Closing idle sessions.");
  562. base::RunLoop().RunUntilIdle();
  563. // Verify spdy_session and spdy_session1 are closed.
  564. EXPECT_FALSE(session);
  565. EXPECT_FALSE(session1);
  566. EXPECT_TRUE(session2->is_active());
  567. EXPECT_TRUE(session2->IsAvailable());
  568. spdy_stream2->Cancel(ERR_ABORTED);
  569. EXPECT_FALSE(spdy_stream);
  570. EXPECT_FALSE(spdy_stream1);
  571. EXPECT_FALSE(spdy_stream2);
  572. session2->CloseSessionOnError(ERR_ABORTED, std::string());
  573. base::RunLoop().RunUntilIdle();
  574. EXPECT_FALSE(session2);
  575. break;
  576. }
  577. // Verify that the map is all cleaned up.
  578. EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
  579. EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
  580. EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
  581. EXPECT_FALSE(TryCreateAliasedSpdySession(
  582. spdy_session_pool_, test_hosts[0].key, test_hosts[0].iplist));
  583. EXPECT_FALSE(TryCreateAliasedSpdySession(
  584. spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist));
  585. EXPECT_FALSE(TryCreateAliasedSpdySession(
  586. spdy_session_pool_, test_hosts[2].key, test_hosts[2].iplist));
  587. }
  588. void SpdySessionPoolTest::RunIPPoolingDisabledTest(SSLSocketDataProvider* ssl) {
  589. constexpr int kTestPort = 443;
  590. struct TestHosts {
  591. std::string name;
  592. std::string iplist;
  593. SpdySessionKey key;
  594. } test_hosts[] = {
  595. {"www.webkit.org", "192.0.2.33,192.168.0.1,192.168.0.5"},
  596. {"js.webkit.com", "192.168.0.4,192.168.0.1,192.0.2.33"},
  597. };
  598. session_deps_.host_resolver->set_synchronous_mode(true);
  599. for (auto& test_host : test_hosts) {
  600. session_deps_.host_resolver->rules()->AddIPLiteralRule(
  601. test_host.name, test_host.iplist, std::string());
  602. // Setup a SpdySessionKey
  603. test_host.key = SpdySessionKey(
  604. HostPortPair(test_host.name, kTestPort), ProxyServer::Direct(),
  605. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  606. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  607. }
  608. MockRead reads[] = {
  609. MockRead(ASYNC, ERR_IO_PENDING),
  610. };
  611. StaticSocketDataProvider data(reads, base::span<MockWrite>());
  612. session_deps_.socket_factory->AddSocketDataProvider(&data);
  613. session_deps_.socket_factory->AddSSLSocketDataProvider(ssl);
  614. CreateNetworkSession();
  615. base::WeakPtr<SpdySession> spdy_session = CreateSpdySession(
  616. http_session_.get(), test_hosts[0].key, NetLogWithSource());
  617. EXPECT_TRUE(
  618. HasSpdySession(http_session_->spdy_session_pool(), test_hosts[0].key));
  619. EXPECT_FALSE(TryCreateAliasedSpdySession(
  620. spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
  621. /* enable_ip_based_pooling = */ false));
  622. http_session_->spdy_session_pool()->CloseAllSessions();
  623. }
  624. TEST_F(SpdySessionPoolTest, IPPooling) {
  625. RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
  626. }
  627. TEST_F(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
  628. RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
  629. }
  630. TEST_F(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
  631. RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
  632. }
  633. // Regression test for https://crbug.com/643025.
  634. TEST_F(SpdySessionPoolTest, IPPoolingNetLog) {
  635. // Define two hosts with identical IP address.
  636. constexpr int kTestPort = 443;
  637. struct TestHosts {
  638. std::string name;
  639. std::string iplist;
  640. SpdySessionKey key;
  641. } test_hosts[] = {
  642. {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
  643. };
  644. // Populate the HostResolver cache.
  645. session_deps_.host_resolver->set_synchronous_mode(true);
  646. for (auto& test_host : test_hosts) {
  647. session_deps_.host_resolver->rules()->AddIPLiteralRule(
  648. test_host.name, test_host.iplist, std::string());
  649. test_host.key = SpdySessionKey(
  650. HostPortPair(test_host.name, kTestPort), ProxyServer::Direct(),
  651. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  652. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  653. }
  654. MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
  655. StaticSocketDataProvider data(reads, base::span<MockWrite>());
  656. MockConnect connect_data(SYNCHRONOUS, OK);
  657. data.set_connect_data(connect_data);
  658. session_deps_.socket_factory->AddSocketDataProvider(&data);
  659. AddSSLSocketData();
  660. CreateNetworkSession();
  661. // Open SpdySession to the first host.
  662. base::WeakPtr<SpdySession> session0 = CreateSpdySession(
  663. http_session_.get(), test_hosts[0].key, NetLogWithSource());
  664. // The second host should pool to the existing connection.
  665. RecordingNetLogObserver net_log_observer;
  666. base::HistogramTester histogram_tester;
  667. EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
  668. test_hosts[1].iplist));
  669. histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 1);
  670. base::WeakPtr<SpdySession> session1 =
  671. spdy_session_pool_->FindAvailableSession(
  672. test_hosts[1].key, /* enable_ip_based_pooling = */ true,
  673. /* is_websocket = */ false,
  674. NetLogWithSource::Make(NetLogSourceType::NONE));
  675. EXPECT_EQ(session0.get(), session1.get());
  676. ASSERT_EQ(1u, net_log_observer.GetSize());
  677. histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 2);
  678. // FindAvailableSession() should have logged a netlog event indicating IP
  679. // pooling.
  680. auto entry_list = net_log_observer.GetEntries();
  681. EXPECT_EQ(
  682. NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
  683. entry_list[0].type);
  684. // Both FindAvailableSession() calls (including one from
  685. // TryCreateAliasedSpdySession) should log histogram entries indicating IP
  686. // pooling.
  687. histogram_tester.ExpectUniqueSample("Net.SpdySessionGet", 2, 2);
  688. }
  689. TEST_F(SpdySessionPoolTest, IPPoolingDisabled) {
  690. // Define two hosts with identical IP address.
  691. constexpr int kTestPort = 443;
  692. struct TestHosts {
  693. std::string name;
  694. std::string iplist;
  695. SpdySessionKey key;
  696. } test_hosts[] = {
  697. {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
  698. };
  699. // Populate the HostResolver cache.
  700. session_deps_.host_resolver->set_synchronous_mode(true);
  701. for (auto& test_host : test_hosts) {
  702. session_deps_.host_resolver->rules()->AddIPLiteralRule(
  703. test_host.name, test_host.iplist, std::string());
  704. test_host.key = SpdySessionKey(
  705. HostPortPair(test_host.name, kTestPort), ProxyServer::Direct(),
  706. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  707. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  708. }
  709. MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
  710. StaticSocketDataProvider data(reads, base::span<MockWrite>());
  711. MockConnect connect_data(SYNCHRONOUS, OK);
  712. data.set_connect_data(connect_data);
  713. session_deps_.socket_factory->AddSocketDataProvider(&data);
  714. AddSSLSocketData();
  715. MockRead reads1[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
  716. StaticSocketDataProvider data1(reads1, base::span<MockWrite>());
  717. MockConnect connect_data1(SYNCHRONOUS, OK);
  718. data1.set_connect_data(connect_data1);
  719. session_deps_.socket_factory->AddSocketDataProvider(&data1);
  720. AddSSLSocketData();
  721. CreateNetworkSession();
  722. // Open SpdySession to the first host.
  723. base::WeakPtr<SpdySession> session0 = CreateSpdySession(
  724. http_session_.get(), test_hosts[0].key, NetLogWithSource());
  725. // |test_hosts[1]| should pool to the existing connection.
  726. EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
  727. test_hosts[1].iplist));
  728. base::WeakPtr<SpdySession> session1 =
  729. spdy_session_pool_->FindAvailableSession(
  730. test_hosts[1].key, /* enable_ip_based_pooling = */ true,
  731. /* is_websocket = */ false, NetLogWithSource());
  732. EXPECT_EQ(session0.get(), session1.get());
  733. // A request to the second host should not pool to the existing connection if
  734. // IP based pooling is disabled.
  735. session1 = spdy_session_pool_->FindAvailableSession(
  736. test_hosts[1].key, /* enable_ip_based_pooling = */ false,
  737. /* is_websocket = */ false, NetLogWithSource());
  738. EXPECT_FALSE(session1);
  739. // It should be possible to open a new SpdySession, even if a previous call to
  740. // FindAvailableSession() linked the second key to the first connection in the
  741. // IP pooled bucket of SpdySessionPool::available_session_map_.
  742. session1 = CreateSpdySessionWithIpBasedPoolingDisabled(
  743. http_session_.get(), test_hosts[1].key, NetLogWithSource());
  744. EXPECT_TRUE(session1);
  745. EXPECT_NE(session0.get(), session1.get());
  746. }
  747. // Verifies that an SSL connection with client authentication disables SPDY IP
  748. // pooling.
  749. TEST_F(SpdySessionPoolTest, IPPoolingClientCert) {
  750. SSLSocketDataProvider ssl(ASYNC, OK);
  751. ssl.ssl_info.cert = X509Certificate::CreateFromBytes(webkit_der);
  752. ASSERT_TRUE(ssl.ssl_info.cert);
  753. ssl.ssl_info.client_cert_sent = true;
  754. ssl.next_proto = kProtoHTTP2;
  755. RunIPPoolingDisabledTest(&ssl);
  756. }
  757. // Construct a Pool with SpdySessions in various availability states. Simulate
  758. // an IP address change. Ensure sessions gracefully shut down. Regression test
  759. // for crbug.com/379469.
  760. TEST_F(SpdySessionPoolTest, GoAwayOnIPAddressChanged) {
  761. MockConnect connect_data(SYNCHRONOUS, OK);
  762. session_deps_.host_resolver->set_synchronous_mode(true);
  763. // This isn't testing anything having to do with SPDY frames; we
  764. // can ignore issues of how dependencies are set. We default to
  765. // setting them (when doing the appropriate protocol) since that's
  766. // where we're eventually headed for all HTTP/2 connections.
  767. SpdyTestUtil spdy_util;
  768. MockRead reads[] = {
  769. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  770. };
  771. spdy::SpdySerializedFrame req(
  772. spdy_util.ConstructSpdyGet("http://www.example.org", 1, MEDIUM));
  773. MockWrite writes[] = {CreateMockWrite(req, 1)};
  774. StaticSocketDataProvider dataA(reads, writes);
  775. dataA.set_connect_data(connect_data);
  776. session_deps_.socket_factory->AddSocketDataProvider(&dataA);
  777. AddSSLSocketData();
  778. session_deps_.go_away_on_ip_change = true;
  779. CreateNetworkSession();
  780. // Set up session A: Going away, but with an active stream.
  781. const std::string kTestHostA("www.example.org");
  782. HostPortPair test_host_port_pairA(kTestHostA, 80);
  783. SpdySessionKey keyA(test_host_port_pairA, ProxyServer::Direct(),
  784. PRIVACY_MODE_DISABLED,
  785. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  786. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  787. base::WeakPtr<SpdySession> sessionA =
  788. CreateSpdySession(http_session_.get(), keyA, NetLogWithSource());
  789. GURL urlA("http://www.example.org");
  790. base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
  791. SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, NetLogWithSource());
  792. test::StreamDelegateDoNothing delegateA(spdy_streamA);
  793. spdy_streamA->SetDelegate(&delegateA);
  794. spdy::Http2HeaderBlock headers(
  795. spdy_util.ConstructGetHeaderBlock(urlA.spec()));
  796. spdy_streamA->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
  797. base::RunLoop().RunUntilIdle(); // Allow headers to write.
  798. EXPECT_TRUE(delegateA.send_headers_completed());
  799. sessionA->MakeUnavailable();
  800. EXPECT_TRUE(sessionA->IsGoingAway());
  801. EXPECT_FALSE(delegateA.StreamIsClosed());
  802. // Set up session B: Available, with a created stream.
  803. StaticSocketDataProvider dataB(reads, writes);
  804. dataB.set_connect_data(connect_data);
  805. session_deps_.socket_factory->AddSocketDataProvider(&dataB);
  806. AddSSLSocketData();
  807. const std::string kTestHostB("mail.example.org");
  808. HostPortPair test_host_port_pairB(kTestHostB, 80);
  809. SpdySessionKey keyB(test_host_port_pairB, ProxyServer::Direct(),
  810. PRIVACY_MODE_DISABLED,
  811. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  812. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  813. base::WeakPtr<SpdySession> sessionB =
  814. CreateSpdySession(http_session_.get(), keyB, NetLogWithSource());
  815. EXPECT_TRUE(sessionB->IsAvailable());
  816. GURL urlB("http://mail.example.org");
  817. base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
  818. SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, NetLogWithSource());
  819. test::StreamDelegateDoNothing delegateB(spdy_streamB);
  820. spdy_streamB->SetDelegate(&delegateB);
  821. // Set up session C: Draining.
  822. StaticSocketDataProvider dataC(reads, writes);
  823. dataC.set_connect_data(connect_data);
  824. session_deps_.socket_factory->AddSocketDataProvider(&dataC);
  825. AddSSLSocketData();
  826. const std::string kTestHostC("mail.example.com");
  827. HostPortPair test_host_port_pairC(kTestHostC, 80);
  828. SpdySessionKey keyC(test_host_port_pairC, ProxyServer::Direct(),
  829. PRIVACY_MODE_DISABLED,
  830. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  831. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  832. base::WeakPtr<SpdySession> sessionC =
  833. CreateSpdySession(http_session_.get(), keyC, NetLogWithSource());
  834. sessionC->CloseSessionOnError(ERR_HTTP2_PROTOCOL_ERROR, "Error!");
  835. EXPECT_TRUE(sessionC->IsDraining());
  836. spdy_session_pool_->OnIPAddressChanged();
  837. EXPECT_TRUE(sessionA->IsGoingAway());
  838. EXPECT_TRUE(sessionB->IsDraining());
  839. EXPECT_TRUE(sessionC->IsDraining());
  840. EXPECT_EQ(1u,
  841. num_active_streams(sessionA)); // Active stream is still active.
  842. EXPECT_FALSE(delegateA.StreamIsClosed());
  843. EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed.
  844. EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
  845. sessionA->CloseSessionOnError(ERR_ABORTED, "Closing");
  846. sessionB->CloseSessionOnError(ERR_ABORTED, "Closing");
  847. EXPECT_TRUE(delegateA.StreamIsClosed());
  848. EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_ABORTED));
  849. }
  850. // Construct a Pool with SpdySessions in various availability states. Simulate
  851. // an IP address change. Ensure sessions gracefully shut down. Regression test
  852. // for crbug.com/379469.
  853. TEST_F(SpdySessionPoolTest, CloseOnIPAddressChanged) {
  854. MockConnect connect_data(SYNCHRONOUS, OK);
  855. session_deps_.host_resolver->set_synchronous_mode(true);
  856. // This isn't testing anything having to do with SPDY frames; we
  857. // can ignore issues of how dependencies are set. We default to
  858. // setting them (when doing the appropriate protocol) since that's
  859. // where we're eventually headed for all HTTP/2 connections.
  860. SpdyTestUtil spdy_util;
  861. MockRead reads[] = {
  862. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  863. };
  864. spdy::SpdySerializedFrame req(
  865. spdy_util.ConstructSpdyGet("http://www.example.org", 1, MEDIUM));
  866. MockWrite writes[] = {CreateMockWrite(req, 1)};
  867. StaticSocketDataProvider dataA(reads, writes);
  868. dataA.set_connect_data(connect_data);
  869. session_deps_.socket_factory->AddSocketDataProvider(&dataA);
  870. AddSSLSocketData();
  871. session_deps_.go_away_on_ip_change = false;
  872. CreateNetworkSession();
  873. // Set up session A: Going away, but with an active stream.
  874. const std::string kTestHostA("www.example.org");
  875. HostPortPair test_host_port_pairA(kTestHostA, 80);
  876. SpdySessionKey keyA(test_host_port_pairA, ProxyServer::Direct(),
  877. PRIVACY_MODE_DISABLED,
  878. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  879. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  880. base::WeakPtr<SpdySession> sessionA =
  881. CreateSpdySession(http_session_.get(), keyA, NetLogWithSource());
  882. GURL urlA("http://www.example.org");
  883. base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
  884. SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, NetLogWithSource());
  885. test::StreamDelegateDoNothing delegateA(spdy_streamA);
  886. spdy_streamA->SetDelegate(&delegateA);
  887. spdy::Http2HeaderBlock headers(
  888. spdy_util.ConstructGetHeaderBlock(urlA.spec()));
  889. spdy_streamA->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
  890. base::RunLoop().RunUntilIdle(); // Allow headers to write.
  891. EXPECT_TRUE(delegateA.send_headers_completed());
  892. sessionA->MakeUnavailable();
  893. EXPECT_TRUE(sessionA->IsGoingAway());
  894. EXPECT_FALSE(delegateA.StreamIsClosed());
  895. // Set up session B: Available, with a created stream.
  896. StaticSocketDataProvider dataB(reads, writes);
  897. dataB.set_connect_data(connect_data);
  898. session_deps_.socket_factory->AddSocketDataProvider(&dataB);
  899. AddSSLSocketData();
  900. const std::string kTestHostB("mail.example.org");
  901. HostPortPair test_host_port_pairB(kTestHostB, 80);
  902. SpdySessionKey keyB(test_host_port_pairB, ProxyServer::Direct(),
  903. PRIVACY_MODE_DISABLED,
  904. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  905. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  906. base::WeakPtr<SpdySession> sessionB =
  907. CreateSpdySession(http_session_.get(), keyB, NetLogWithSource());
  908. EXPECT_TRUE(sessionB->IsAvailable());
  909. GURL urlB("http://mail.example.org");
  910. base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
  911. SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, NetLogWithSource());
  912. test::StreamDelegateDoNothing delegateB(spdy_streamB);
  913. spdy_streamB->SetDelegate(&delegateB);
  914. // Set up session C: Draining.
  915. StaticSocketDataProvider dataC(reads, writes);
  916. dataC.set_connect_data(connect_data);
  917. session_deps_.socket_factory->AddSocketDataProvider(&dataC);
  918. AddSSLSocketData();
  919. const std::string kTestHostC("mail.example.com");
  920. HostPortPair test_host_port_pairC(kTestHostC, 80);
  921. SpdySessionKey keyC(test_host_port_pairC, ProxyServer::Direct(),
  922. PRIVACY_MODE_DISABLED,
  923. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  924. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  925. base::WeakPtr<SpdySession> sessionC =
  926. CreateSpdySession(http_session_.get(), keyC, NetLogWithSource());
  927. sessionC->CloseSessionOnError(ERR_HTTP2_PROTOCOL_ERROR, "Error!");
  928. EXPECT_TRUE(sessionC->IsDraining());
  929. spdy_session_pool_->OnIPAddressChanged();
  930. EXPECT_TRUE(sessionA->IsDraining());
  931. EXPECT_TRUE(sessionB->IsDraining());
  932. EXPECT_TRUE(sessionC->IsDraining());
  933. // Both streams were closed with an error.
  934. EXPECT_TRUE(delegateA.StreamIsClosed());
  935. EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
  936. EXPECT_TRUE(delegateB.StreamIsClosed());
  937. EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
  938. }
  939. // Regression test for https://crbug.com/789791.
  940. TEST_F(SpdySessionPoolTest, HandleIPAddressChangeThenShutdown) {
  941. MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
  942. SpdyTestUtil spdy_util;
  943. spdy::SpdySerializedFrame req(
  944. spdy_util.ConstructSpdyGet(kDefaultUrl, 1, MEDIUM));
  945. MockWrite writes[] = {CreateMockWrite(req, 1)};
  946. StaticSocketDataProvider data(reads, writes);
  947. MockConnect connect_data(SYNCHRONOUS, OK);
  948. data.set_connect_data(connect_data);
  949. session_deps_.socket_factory->AddSocketDataProvider(&data);
  950. AddSSLSocketData();
  951. CreateNetworkSession();
  952. const GURL url(kDefaultUrl);
  953. SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
  954. PRIVACY_MODE_DISABLED,
  955. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  956. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  957. base::WeakPtr<SpdySession> session =
  958. CreateSpdySession(http_session_.get(), key, NetLogWithSource());
  959. base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
  960. SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
  961. test::StreamDelegateDoNothing delegate(spdy_stream);
  962. spdy_stream->SetDelegate(&delegate);
  963. spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
  964. spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
  965. base::RunLoop().RunUntilIdle();
  966. EXPECT_TRUE(delegate.send_headers_completed());
  967. spdy_session_pool_->OnIPAddressChanged();
  968. #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
  969. EXPECT_EQ(1u, num_active_streams(session));
  970. EXPECT_TRUE(session->IsGoingAway());
  971. EXPECT_FALSE(session->IsDraining());
  972. #else
  973. EXPECT_EQ(0u, num_active_streams(session));
  974. EXPECT_FALSE(session->IsGoingAway());
  975. EXPECT_TRUE(session->IsDraining());
  976. #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
  977. http_session_.reset();
  978. data.AllReadDataConsumed();
  979. data.AllWriteDataConsumed();
  980. }
  981. // Regression test for https://crbug.com/789791.
  982. TEST_F(SpdySessionPoolTest, HandleGracefulGoawayThenShutdown) {
  983. SpdyTestUtil spdy_util;
  984. spdy::SpdySerializedFrame goaway(spdy_util.ConstructSpdyGoAway(
  985. 0x7fffffff, spdy::ERROR_CODE_NO_ERROR, "Graceful shutdown."));
  986. MockRead reads[] = {
  987. MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2),
  988. MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, OK, 4)};
  989. spdy::SpdySerializedFrame req(
  990. spdy_util.ConstructSpdyGet(kDefaultUrl, 1, MEDIUM));
  991. MockWrite writes[] = {CreateMockWrite(req, 0)};
  992. SequencedSocketData data(reads, writes);
  993. MockConnect connect_data(SYNCHRONOUS, OK);
  994. data.set_connect_data(connect_data);
  995. session_deps_.socket_factory->AddSocketDataProvider(&data);
  996. AddSSLSocketData();
  997. CreateNetworkSession();
  998. const GURL url(kDefaultUrl);
  999. SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
  1000. PRIVACY_MODE_DISABLED,
  1001. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  1002. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1003. base::WeakPtr<SpdySession> session =
  1004. CreateSpdySession(http_session_.get(), key, NetLogWithSource());
  1005. base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
  1006. SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
  1007. test::StreamDelegateDoNothing delegate(spdy_stream);
  1008. spdy_stream->SetDelegate(&delegate);
  1009. spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
  1010. spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
  1011. // Send headers.
  1012. base::RunLoop().RunUntilIdle();
  1013. EXPECT_TRUE(delegate.send_headers_completed());
  1014. EXPECT_EQ(1u, num_active_streams(session));
  1015. EXPECT_FALSE(session->IsGoingAway());
  1016. EXPECT_FALSE(session->IsDraining());
  1017. // Read GOAWAY.
  1018. data.Resume();
  1019. base::RunLoop().RunUntilIdle();
  1020. EXPECT_EQ(1u, num_active_streams(session));
  1021. EXPECT_TRUE(session->IsGoingAway());
  1022. EXPECT_FALSE(session->IsDraining());
  1023. http_session_.reset();
  1024. data.AllReadDataConsumed();
  1025. data.AllWriteDataConsumed();
  1026. }
  1027. TEST_F(SpdySessionPoolTest, IPConnectionPoolingWithWebSockets) {
  1028. // Define two hosts with identical IP address.
  1029. const int kTestPort = 443;
  1030. struct TestHosts {
  1031. std::string name;
  1032. std::string iplist;
  1033. SpdySessionKey key;
  1034. } test_hosts[] = {
  1035. {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
  1036. };
  1037. // Populate the HostResolver cache.
  1038. session_deps_.host_resolver->set_synchronous_mode(true);
  1039. for (auto& test_host : test_hosts) {
  1040. session_deps_.host_resolver->rules()->AddIPLiteralRule(
  1041. test_host.name, test_host.iplist, std::string());
  1042. test_host.key = SpdySessionKey(
  1043. HostPortPair(test_host.name, kTestPort), ProxyServer::Direct(),
  1044. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  1045. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1046. }
  1047. SpdyTestUtil spdy_util;
  1048. spdy::SpdySerializedFrame req(
  1049. spdy_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
  1050. spdy::SpdySerializedFrame settings_ack(spdy_util.ConstructSpdySettingsAck());
  1051. MockWrite writes[] = {CreateMockWrite(req, 0),
  1052. CreateMockWrite(settings_ack, 2)};
  1053. spdy::SettingsMap settings;
  1054. settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
  1055. spdy::SpdySerializedFrame settings_frame(
  1056. spdy_util.ConstructSpdySettings(settings));
  1057. spdy::SpdySerializedFrame resp(
  1058. spdy_util.ConstructSpdyGetReply(nullptr, 0, 1));
  1059. spdy::SpdySerializedFrame body(spdy_util.ConstructSpdyDataFrame(1, true));
  1060. MockRead reads[] = {CreateMockRead(settings_frame, 1),
  1061. CreateMockRead(resp, 3), CreateMockRead(body, 4),
  1062. MockRead(ASYNC, ERR_IO_PENDING, 5),
  1063. MockRead(ASYNC, 0, 6)};
  1064. SequencedSocketData data(reads, writes);
  1065. session_deps_.socket_factory->AddSocketDataProvider(&data);
  1066. AddSSLSocketData();
  1067. CreateNetworkSession();
  1068. // Create a connection to the first host.
  1069. base::WeakPtr<SpdySession> session = CreateSpdySession(
  1070. http_session_.get(), test_hosts[0].key, NetLogWithSource());
  1071. // SpdySession does not support Websocket before SETTINGS frame is read.
  1072. EXPECT_FALSE(session->support_websocket());
  1073. NetLogWithSource net_log_with_source{
  1074. NetLogWithSource::Make(NetLogSourceType::NONE)};
  1075. // TryCreateAliasedSpdySession should not find |session| for either
  1076. // SpdySessionKeys if |is_websocket| argument is set.
  1077. EXPECT_FALSE(TryCreateAliasedSpdySession(
  1078. spdy_session_pool_, test_hosts[0].key, test_hosts[0].iplist,
  1079. /* enable_ip_based_pooling = */ true,
  1080. /* is_websocket = */ true));
  1081. EXPECT_FALSE(TryCreateAliasedSpdySession(
  1082. spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
  1083. /* enable_ip_based_pooling = */ true,
  1084. /* is_websocket = */ true));
  1085. // Start request that triggers reading the SETTINGS frame.
  1086. const GURL url(kDefaultUrl);
  1087. base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
  1088. SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, NetLogWithSource());
  1089. test::StreamDelegateDoNothing delegate(spdy_stream);
  1090. spdy_stream->SetDelegate(&delegate);
  1091. spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
  1092. spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
  1093. base::RunLoop().RunUntilIdle();
  1094. // Now SpdySession has read the SETTINGS frame and thus supports Websocket.
  1095. EXPECT_TRUE(session->support_websocket());
  1096. // FindAvailableSession() on the first host should now find the existing
  1097. // session with websockets enabled, and TryCreateAliasedSpdySession() should
  1098. // now set up aliases for |session| for the second one.
  1099. base::WeakPtr<SpdySession> result = spdy_session_pool_->FindAvailableSession(
  1100. test_hosts[0].key, /* enable_ip_based_pooling = */ true,
  1101. /* is_websocket = */ true, net_log_with_source);
  1102. EXPECT_EQ(session.get(), result.get());
  1103. EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
  1104. test_hosts[1].iplist,
  1105. /* enable_ip_based_pooling = */ true,
  1106. /* is_websocket = */ true));
  1107. // FindAvailableSession() should return |session| for either SpdySessionKeys
  1108. // when IP based pooling is enabled.
  1109. result = spdy_session_pool_->FindAvailableSession(
  1110. test_hosts[0].key, /* enable_ip_based_pooling = */ true,
  1111. /* is_websocket = */ true, net_log_with_source);
  1112. EXPECT_EQ(session.get(), result.get());
  1113. result = spdy_session_pool_->FindAvailableSession(
  1114. test_hosts[1].key, /* enable_ip_based_pooling = */ true,
  1115. /* is_websocket = */ true, net_log_with_source);
  1116. EXPECT_EQ(session.get(), result.get());
  1117. // FindAvailableSession() should only return |session| for the first
  1118. // SpdySessionKey when IP based pooling is disabled.
  1119. result = spdy_session_pool_->FindAvailableSession(
  1120. test_hosts[0].key, /* enable_ip_based_pooling = */ false,
  1121. /* is_websocket = */ true, net_log_with_source);
  1122. EXPECT_EQ(session.get(), result.get());
  1123. result = spdy_session_pool_->FindAvailableSession(
  1124. test_hosts[1].key, /* enable_ip_based_pooling = */ false,
  1125. /* is_websocket = */ true, net_log_with_source);
  1126. EXPECT_FALSE(result);
  1127. // Read EOF.
  1128. data.Resume();
  1129. base::RunLoop().RunUntilIdle();
  1130. EXPECT_TRUE(data.AllReadDataConsumed());
  1131. EXPECT_TRUE(data.AllWriteDataConsumed());
  1132. }
  1133. class TestOnRequestDeletedCallback {
  1134. public:
  1135. TestOnRequestDeletedCallback() = default;
  1136. TestOnRequestDeletedCallback(const TestOnRequestDeletedCallback&) = delete;
  1137. TestOnRequestDeletedCallback& operator=(const TestOnRequestDeletedCallback&) =
  1138. delete;
  1139. ~TestOnRequestDeletedCallback() = default;
  1140. base::RepeatingClosure Callback() {
  1141. return base::BindRepeating(&TestOnRequestDeletedCallback::OnRequestDeleted,
  1142. base::Unretained(this));
  1143. }
  1144. bool invoked() const { return invoked_; }
  1145. void WaitUntilInvoked() { run_loop_.Run(); }
  1146. void SetRequestDeletedCallback(base::OnceClosure request_deleted_callback) {
  1147. DCHECK(!request_deleted_callback_);
  1148. request_deleted_callback_ = std::move(request_deleted_callback);
  1149. }
  1150. private:
  1151. void OnRequestDeleted() {
  1152. EXPECT_FALSE(invoked_);
  1153. invoked_ = true;
  1154. if (request_deleted_callback_)
  1155. std::move(request_deleted_callback_).Run();
  1156. run_loop_.Quit();
  1157. }
  1158. bool invoked_ = false;
  1159. base::RunLoop run_loop_;
  1160. base::OnceClosure request_deleted_callback_;
  1161. };
  1162. class TestRequestDelegate
  1163. : public SpdySessionPool::SpdySessionRequest::Delegate {
  1164. public:
  1165. TestRequestDelegate() = default;
  1166. TestRequestDelegate(const TestRequestDelegate&) = delete;
  1167. TestRequestDelegate& operator=(const TestRequestDelegate&) = delete;
  1168. ~TestRequestDelegate() override = default;
  1169. // SpdySessionPool::SpdySessionRequest::Delegate implementation:
  1170. void OnSpdySessionAvailable(
  1171. base::WeakPtr<SpdySession> spdy_session) override {}
  1172. };
  1173. TEST_F(SpdySessionPoolTest, RequestSessionWithNoSessions) {
  1174. const SpdySessionKey kSessionKey(
  1175. HostPortPair("foo.test", 443), ProxyServer::Direct(),
  1176. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  1177. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1178. CreateNetworkSession();
  1179. // First request. Its request deleted callback should never be invoked.
  1180. TestOnRequestDeletedCallback request_deleted_callback1;
  1181. TestRequestDelegate request_delegate1;
  1182. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request1;
  1183. bool is_first_request_for_session;
  1184. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1185. kSessionKey, /* enable_ip_based_pooling = */ false,
  1186. /* is_websocket = */ false, NetLogWithSource(),
  1187. request_deleted_callback1.Callback(), &request_delegate1,
  1188. &spdy_session_request1, &is_first_request_for_session));
  1189. EXPECT_TRUE(is_first_request_for_session);
  1190. // Second request.
  1191. TestOnRequestDeletedCallback request_deleted_callback2;
  1192. TestRequestDelegate request_delegate2;
  1193. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request2;
  1194. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1195. kSessionKey, /* enable_ip_based_pooling = */ false,
  1196. /* is_websocket = */ false, NetLogWithSource(),
  1197. request_deleted_callback2.Callback(), &request_delegate2,
  1198. &spdy_session_request2, &is_first_request_for_session));
  1199. EXPECT_FALSE(is_first_request_for_session);
  1200. // Third request.
  1201. TestOnRequestDeletedCallback request_deleted_callback3;
  1202. TestRequestDelegate request_delegate3;
  1203. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request3;
  1204. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1205. kSessionKey, /* enable_ip_based_pooling = */ false,
  1206. /* is_websocket = */ false, NetLogWithSource(),
  1207. request_deleted_callback3.Callback(), &request_delegate3,
  1208. &spdy_session_request3, &is_first_request_for_session));
  1209. EXPECT_FALSE(is_first_request_for_session);
  1210. // Destroying the second request shouldn't cause anything to happen.
  1211. spdy_session_request2.reset();
  1212. base::RunLoop().RunUntilIdle();
  1213. EXPECT_FALSE(request_deleted_callback1.invoked());
  1214. EXPECT_FALSE(request_deleted_callback2.invoked());
  1215. EXPECT_FALSE(request_deleted_callback3.invoked());
  1216. // But destroying the first request should cause the second and third
  1217. // callbacks to be invoked.
  1218. spdy_session_request1.reset();
  1219. request_deleted_callback2.WaitUntilInvoked();
  1220. request_deleted_callback3.WaitUntilInvoked();
  1221. EXPECT_FALSE(request_deleted_callback1.invoked());
  1222. // Nothing should happen when the third request is destroyed.
  1223. spdy_session_request3.reset();
  1224. base::RunLoop().RunUntilIdle();
  1225. EXPECT_FALSE(request_deleted_callback1.invoked());
  1226. }
  1227. TEST_F(SpdySessionPoolTest, RequestSessionDuringNotification) {
  1228. const SpdySessionKey kSessionKey(
  1229. HostPortPair("foo.test", 443), ProxyServer::Direct(),
  1230. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  1231. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1232. CreateNetworkSession();
  1233. // First request. Its request deleted callback should never be invoked.
  1234. TestOnRequestDeletedCallback request_deleted_callback1;
  1235. TestRequestDelegate request_delegate1;
  1236. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request1;
  1237. bool is_first_request_for_session;
  1238. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1239. kSessionKey, /* enable_ip_based_pooling = */ false,
  1240. /* is_websocket = */ false, NetLogWithSource(),
  1241. request_deleted_callback1.Callback(), &request_delegate1,
  1242. &spdy_session_request1, &is_first_request_for_session));
  1243. EXPECT_TRUE(is_first_request_for_session);
  1244. // Second request.
  1245. TestOnRequestDeletedCallback request_deleted_callback2;
  1246. TestRequestDelegate request_delegate2;
  1247. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request2;
  1248. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1249. kSessionKey, /* enable_ip_based_pooling = */ false,
  1250. /* is_websocket = */ false, NetLogWithSource(),
  1251. request_deleted_callback2.Callback(), &request_delegate2,
  1252. &spdy_session_request2, &is_first_request_for_session));
  1253. EXPECT_FALSE(is_first_request_for_session);
  1254. TestOnRequestDeletedCallback request_deleted_callback3;
  1255. TestRequestDelegate request_delegate3;
  1256. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request3;
  1257. TestOnRequestDeletedCallback request_deleted_callback4;
  1258. TestRequestDelegate request_delegate4;
  1259. std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request4;
  1260. request_deleted_callback2.SetRequestDeletedCallback(
  1261. base::BindLambdaForTesting([&]() {
  1262. // Third request. It should again be marked as the first request for the
  1263. // session, since it's only created after the original two have been
  1264. // removed.
  1265. bool is_first_request_for_session;
  1266. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1267. kSessionKey, /* enable_ip_based_pooling = */ false,
  1268. /* is_websocket = */ false, NetLogWithSource(),
  1269. request_deleted_callback3.Callback(), &request_delegate3,
  1270. &spdy_session_request3, &is_first_request_for_session));
  1271. EXPECT_TRUE(is_first_request_for_session);
  1272. // Fourth request.
  1273. EXPECT_FALSE(spdy_session_pool_->RequestSession(
  1274. kSessionKey, /* enable_ip_based_pooling = */ false,
  1275. /* is_websocket = */ false, NetLogWithSource(),
  1276. request_deleted_callback4.Callback(), &request_delegate4,
  1277. &spdy_session_request4, &is_first_request_for_session));
  1278. EXPECT_FALSE(is_first_request_for_session);
  1279. }));
  1280. // Destroying the first request should cause the second callback to be
  1281. // invoked, and the third and fourth request to be made.
  1282. spdy_session_request1.reset();
  1283. request_deleted_callback2.WaitUntilInvoked();
  1284. base::RunLoop().RunUntilIdle();
  1285. EXPECT_FALSE(request_deleted_callback1.invoked());
  1286. EXPECT_FALSE(request_deleted_callback3.invoked());
  1287. EXPECT_FALSE(request_deleted_callback4.invoked());
  1288. EXPECT_TRUE(spdy_session_request3);
  1289. EXPECT_TRUE(spdy_session_request4);
  1290. // Destroying the third request should cause the fourth callback to be
  1291. // invoked.
  1292. spdy_session_request3.reset();
  1293. request_deleted_callback4.WaitUntilInvoked();
  1294. EXPECT_FALSE(request_deleted_callback1.invoked());
  1295. EXPECT_FALSE(request_deleted_callback3.invoked());
  1296. }
  1297. static const char kSSLServerTestHost[] = "config-changed.test";
  1298. static const struct {
  1299. const char* url;
  1300. const char* proxy_pac_string;
  1301. bool expect_invalidated;
  1302. } kSSLServerTests[] = {
  1303. // If the host and port match, the session should be invalidated.
  1304. {"https://config-changed.test", "DIRECT", true},
  1305. // If host and port do not match, the session should not be invalidated.
  1306. {"https://mail.config-changed.test", "DIRECT", false},
  1307. {"https://config-changed.test:444", "DIRECT", false},
  1308. // If the proxy matches, the session should be invalidated independent of
  1309. // the host.
  1310. {"https://config-changed.test", "HTTPS config-changed.test:443", true},
  1311. {"https://mail.config-changed.test", "HTTPS config-changed.test:443", true},
  1312. // HTTP and SOCKS proxies do not have client certificates.
  1313. {"https://mail.config-changed.test", "PROXY config-changed.test:443",
  1314. false},
  1315. {"https://mail.config-changed.test", "SOCKS5 config-changed.test:443",
  1316. false},
  1317. // The proxy host and port must match.
  1318. {"https://mail.config-changed.test", "HTTPS mail.config-changed.test:443",
  1319. false},
  1320. {"https://mail.config-changed.test", "HTTPS config-changed.test:444",
  1321. false},
  1322. };
  1323. // Tests the OnSSLConfigForServerChanged() method matches SpdySessions as
  1324. // expected.
  1325. TEST_F(SpdySessionPoolTest, SSLConfigForServerChanged) {
  1326. const MockConnect connect_data(SYNCHRONOUS, OK);
  1327. const MockRead reads[] = {
  1328. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  1329. };
  1330. std::vector<std::unique_ptr<StaticSocketDataProvider>> socket_data;
  1331. size_t num_tests = std::size(kSSLServerTests);
  1332. for (size_t i = 0; i < num_tests; i++) {
  1333. socket_data.push_back(std::make_unique<StaticSocketDataProvider>(
  1334. reads, base::span<MockWrite>()));
  1335. socket_data.back()->set_connect_data(connect_data);
  1336. session_deps_.socket_factory->AddSocketDataProvider(
  1337. socket_data.back().get());
  1338. AddSSLSocketData();
  1339. }
  1340. CreateNetworkSession();
  1341. std::vector<base::WeakPtr<SpdySession>> sessions;
  1342. for (size_t i = 0; i < num_tests; i++) {
  1343. SpdySessionKey key(
  1344. HostPortPair::FromURL(GURL(kSSLServerTests[i].url)),
  1345. PacResultElementToProxyServer(kSSLServerTests[i].proxy_pac_string),
  1346. PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
  1347. SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1348. sessions.push_back(
  1349. CreateSpdySession(http_session_.get(), key, NetLogWithSource()));
  1350. }
  1351. // All sessions are available.
  1352. for (size_t i = 0; i < num_tests; i++) {
  1353. SCOPED_TRACE(i);
  1354. EXPECT_TRUE(sessions[i]->IsAvailable());
  1355. }
  1356. spdy_session_pool_->OnSSLConfigForServerChanged(
  1357. HostPortPair(kSSLServerTestHost, 443));
  1358. base::RunLoop().RunUntilIdle();
  1359. // Sessions were inactive, so the unavailable sessions are closed.
  1360. for (size_t i = 0; i < num_tests; i++) {
  1361. SCOPED_TRACE(i);
  1362. if (kSSLServerTests[i].expect_invalidated) {
  1363. EXPECT_FALSE(sessions[i]);
  1364. } else {
  1365. ASSERT_TRUE(sessions[i]);
  1366. EXPECT_TRUE(sessions[i]->IsAvailable());
  1367. }
  1368. }
  1369. }
  1370. // Tests the OnSSLConfigForServerChanged() method when there are streams open.
  1371. TEST_F(SpdySessionPoolTest, SSLConfigForServerChangedWithStreams) {
  1372. // Set up a SpdySession with an active, created, and pending stream.
  1373. SpdyTestUtil spdy_util;
  1374. spdy::SettingsMap settings;
  1375. settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
  1376. spdy::SpdySerializedFrame settings_frame =
  1377. spdy_util.ConstructSpdySettings(settings);
  1378. spdy::SpdySerializedFrame settings_ack = spdy_util.ConstructSpdySettingsAck();
  1379. spdy::SpdySerializedFrame req(
  1380. spdy_util.ConstructSpdyGet(nullptr, 0, 1, MEDIUM));
  1381. const MockConnect connect_data(SYNCHRONOUS, OK);
  1382. const MockRead reads[] = {
  1383. CreateMockRead(settings_frame),
  1384. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  1385. };
  1386. const MockWrite writes[] = {
  1387. CreateMockWrite(settings_ack),
  1388. CreateMockWrite(req),
  1389. };
  1390. StaticSocketDataProvider socket_data(reads, writes);
  1391. socket_data.set_connect_data(connect_data);
  1392. session_deps_.socket_factory->AddSocketDataProvider(&socket_data);
  1393. AddSSLSocketData();
  1394. CreateNetworkSession();
  1395. const GURL url(kDefaultUrl);
  1396. SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
  1397. PRIVACY_MODE_DISABLED,
  1398. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  1399. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1400. base::WeakPtr<SpdySession> session =
  1401. CreateSpdySession(http_session_.get(), key, NetLogWithSource());
  1402. // Pick up the SETTINGS frame to update SETTINGS_MAX_CONCURRENT_STREAMS.
  1403. base::RunLoop().RunUntilIdle();
  1404. EXPECT_EQ(2u, max_concurrent_streams(session));
  1405. // The first two stream requests should succeed.
  1406. base::WeakPtr<SpdyStream> active_stream = CreateStreamSynchronously(
  1407. SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, NetLogWithSource());
  1408. test::StreamDelegateDoNothing active_stream_delegate(active_stream);
  1409. active_stream->SetDelegate(&active_stream_delegate);
  1410. base::WeakPtr<SpdyStream> created_stream = CreateStreamSynchronously(
  1411. SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, NetLogWithSource());
  1412. test::StreamDelegateDoNothing created_stream_delegate(created_stream);
  1413. created_stream->SetDelegate(&created_stream_delegate);
  1414. // The third will block.
  1415. TestCompletionCallback callback;
  1416. SpdyStreamRequest stream_request;
  1417. EXPECT_THAT(
  1418. stream_request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session, url,
  1419. /*can_send_early=*/false, MEDIUM, SocketTag(),
  1420. NetLogWithSource(), callback.callback(),
  1421. TRAFFIC_ANNOTATION_FOR_TESTS),
  1422. IsError(ERR_IO_PENDING));
  1423. // Activate the first stream by sending data.
  1424. spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
  1425. active_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
  1426. base::RunLoop().RunUntilIdle();
  1427. // The active stream should now have a stream ID.
  1428. EXPECT_EQ(1u, active_stream->stream_id());
  1429. EXPECT_EQ(spdy::kInvalidStreamId, created_stream->stream_id());
  1430. EXPECT_TRUE(session->is_active());
  1431. EXPECT_TRUE(session->IsAvailable());
  1432. spdy_session_pool_->OnSSLConfigForServerChanged(HostPortPair::FromURL(url));
  1433. base::RunLoop().RunUntilIdle();
  1434. // The active stream is still alive, so the session is still active.
  1435. ASSERT_TRUE(session);
  1436. EXPECT_TRUE(session->is_active());
  1437. ASSERT_TRUE(active_stream);
  1438. // The session is no longer available.
  1439. EXPECT_FALSE(session->IsAvailable());
  1440. EXPECT_TRUE(session->IsGoingAway());
  1441. // The pending and created stream are cancelled.
  1442. // TODO(https://crbug.com/1213609): Ideally, this would be recoverable.
  1443. EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NETWORK_CHANGED));
  1444. EXPECT_THAT(created_stream_delegate.WaitForClose(),
  1445. IsError(ERR_NETWORK_CHANGED));
  1446. // Close the active stream.
  1447. active_stream->Close();
  1448. // TODO(https://crbug.com/982499): The invalidated session should be closed
  1449. // after a RunUntilIdle(), but it is not.
  1450. }
  1451. // Tests the OnSSLConfigForServerChanged() method when there only pending
  1452. // streams active.
  1453. TEST_F(SpdySessionPoolTest, SSLConfigForServerChangedWithOnlyPendingStreams) {
  1454. // Set up a SpdySession that accepts no streams.
  1455. SpdyTestUtil spdy_util;
  1456. spdy::SettingsMap settings;
  1457. settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = 0;
  1458. spdy::SpdySerializedFrame settings_frame =
  1459. spdy_util.ConstructSpdySettings(settings);
  1460. spdy::SpdySerializedFrame settings_ack = spdy_util.ConstructSpdySettingsAck();
  1461. const MockConnect connect_data(SYNCHRONOUS, OK);
  1462. const MockRead reads[] = {
  1463. CreateMockRead(settings_frame),
  1464. MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
  1465. };
  1466. const MockWrite writes[] = {
  1467. CreateMockWrite(settings_ack),
  1468. };
  1469. StaticSocketDataProvider socket_data(reads, writes);
  1470. socket_data.set_connect_data(connect_data);
  1471. session_deps_.socket_factory->AddSocketDataProvider(&socket_data);
  1472. AddSSLSocketData();
  1473. CreateNetworkSession();
  1474. const GURL url(kDefaultUrl);
  1475. SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
  1476. PRIVACY_MODE_DISABLED,
  1477. SpdySessionKey::IsProxySession::kFalse, SocketTag(),
  1478. NetworkIsolationKey(), SecureDnsPolicy::kAllow);
  1479. base::WeakPtr<SpdySession> session =
  1480. CreateSpdySession(http_session_.get(), key, NetLogWithSource());
  1481. // Pick up the SETTINGS frame to update SETTINGS_MAX_CONCURRENT_STREAMS.
  1482. base::RunLoop().RunUntilIdle();
  1483. EXPECT_EQ(0u, max_concurrent_streams(session));
  1484. // Create a stream. It should block on the stream limit.
  1485. TestCompletionCallback callback;
  1486. SpdyStreamRequest stream_request;
  1487. ASSERT_THAT(
  1488. stream_request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session, url,
  1489. /*can_send_early=*/false, MEDIUM, SocketTag(),
  1490. NetLogWithSource(), callback.callback(),
  1491. TRAFFIC_ANNOTATION_FOR_TESTS),
  1492. IsError(ERR_IO_PENDING));
  1493. spdy_session_pool_->OnSSLConfigForServerChanged(HostPortPair::FromURL(url));
  1494. base::RunLoop().RunUntilIdle();
  1495. // The pending stream is cancelled.
  1496. // TODO(https://crbug.com/1213609): Ideally, this would be recoverable.
  1497. EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NETWORK_CHANGED));
  1498. EXPECT_FALSE(session);
  1499. }
  1500. } // namespace net