xref: /aosp_15_r20/external/cronet/net/quic/quic_session_pool_proxy_job_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 <memory>
6 
7 #include "net/base/network_anonymization_key.h"
8 #include "net/base/proxy_chain.h"
9 #include "net/base/proxy_server.h"
10 #include "net/cert/x509_certificate.h"
11 #include "net/quic/crypto/proof_verifier_chromium.h"
12 #include "net/quic/mock_quic_data.h"
13 #include "net/quic/quic_context.h"
14 #include "net/quic/quic_http_stream.h"
15 #include "net/quic/quic_session_pool.h"
16 #include "net/quic/quic_session_pool_test_base.h"
17 #include "net/quic/quic_test_packet_maker.h"
18 #include "net/test/cert_test_util.h"
19 #include "net/test/test_data_directory.h"
20 #include "net/third_party/quiche/src/quiche/quic/core/quic_types.h"
21 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
22 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace net::test {
26 
27 class QuicSessionPoolProxyJobTest
28     : public QuicSessionPoolTestBase,
29       public ::testing::TestWithParam<quic::ParsedQuicVersion> {
30  protected:
QuicSessionPoolProxyJobTest()31   QuicSessionPoolProxyJobTest() : QuicSessionPoolTestBase(GetParam()) {}
32 };
33 
34 INSTANTIATE_TEST_SUITE_P(All,
35                          QuicSessionPoolProxyJobTest,
36                          ::testing::ValuesIn(AllSupportedQuicVersions()));
37 
TEST_P(QuicSessionPoolProxyJobTest,CreateProxiedQuicSession)38 TEST_P(QuicSessionPoolProxyJobTest, CreateProxiedQuicSession) {
39   Initialize();
40 
41   GURL url("https://www.example.org/");
42   GURL proxy(kProxy1Url);
43   auto origin = url::SchemeHostPort(url);
44   auto proxy_origin = url::SchemeHostPort(proxy);
45 
46   scoped_refptr<X509Certificate> cert(
47       ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
48   ASSERT_TRUE(cert->VerifyNameMatch(origin.host()));
49   ASSERT_TRUE(cert->VerifyNameMatch(proxy_origin.host()));
50   ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname));
51 
52   ProofVerifyDetailsChromium verify_details;
53   verify_details.cert_verify_result.verified_cert = cert;
54   verify_details.cert_verify_result.is_issued_by_known_root = true;
55   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
56 
57   // QUIC proxies do not use priority header.
58   client_maker_.set_use_priority_header(false);
59 
60   // Use a separate packet maker for the connection to the endpoint.
61   QuicTestPacketMaker endpoint_maker(
62       version_,
63       quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()),
64       context_.clock(), kDefaultServerHostName, quic::Perspective::IS_CLIENT,
65       /*client_priority_uses_incremental=*/true,
66       /*use_priority_header=*/true);
67 
68   const uint64_t stream_id = GetNthClientInitiatedBidirectionalStreamId(0);
69   MockQuicData socket_data(version_);
70   socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(1));
71   socket_data.AddWrite(
72       SYNCHRONOUS, ConstructConnectUdpRequestPacket(
73                        2, stream_id, proxy.host(),
74                        "/.well-known/masque/udp/www.example.org/443/", false));
75   socket_data.AddRead(ASYNC, ConstructServerSettingsPacket(3));
76   socket_data.AddRead(ASYNC, ConstructOkResponsePacket(4, stream_id, true));
77   socket_data.AddReadPauseForever();
78   socket_data.AddWrite(ASYNC, client_maker_.MakeAckPacket(3, 3, 4, 3));
79   socket_data.AddWrite(ASYNC, ConstructClientH3DatagramPacket(
80                                   4, stream_id, kConnectUdpContextId,
81                                   endpoint_maker.MakeInitialSettingsPacket(1)));
82   socket_data.AddSocketDataToFactory(socket_factory_.get());
83 
84   auto proxy_chain = ProxyChain::ForIpProtection({
85       ProxyServer::FromSchemeHostAndPort(ProxyServer::SCHEME_QUIC,
86                                          proxy_origin.host(), 443),
87   });
88   EXPECT_TRUE(proxy_chain.IsValid());
89 
90   RequestBuilder builder(this);
91   builder.destination = origin;
92   builder.proxy_chain = proxy_chain;
93   builder.http_user_agent_settings = &http_user_agent_settings_;
94   builder.url = url;
95   EXPECT_EQ(ERR_IO_PENDING, builder.CallRequest());
96   ASSERT_EQ(OK, callback_.WaitForResult());
97   std::unique_ptr<HttpStream> stream = CreateStream(&builder.request);
98   EXPECT_TRUE(stream.get());
99   QuicChromiumClientSession* session =
100       GetActiveSession(origin, NetworkAnonymizationKey(), proxy_chain);
101   ASSERT_TRUE(session);
102 
103   // Max datagram size is limited by two layers of packet framing (38 bytes
104   // each), 1 byte for the quarter-stream-ID (which is always less than 64, thus
105   // one byte), and one byte for the CONNECT-UDP context.
106   quic::QuicByteCount largest_message_payload =
107       quic::kDefaultMaxPacketSize - 38 * 2 - 1 - 1;
108   EXPECT_EQ(session->GetGuaranteedLargestMessagePayload(),
109             largest_message_payload);
110 
111   stream.reset();
112 
113   // Ensure the session finishes creating before proceeding.
114   RunUntilIdle();
115 
116   socket_data.ExpectAllReadDataConsumed();
117   socket_data.ExpectAllWriteDataConsumed();
118 }
119 
TEST_P(QuicSessionPoolProxyJobTest,CreateProxySessionFails)120 TEST_P(QuicSessionPoolProxyJobTest, CreateProxySessionFails) {
121   Initialize();
122 
123   GURL url("https://www.example.org/");
124   GURL proxy(kProxy1Url);
125   auto origin = url::SchemeHostPort(url);
126   auto proxy_origin = url::SchemeHostPort(proxy);
127 
128   scoped_refptr<X509Certificate> cert(
129       ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
130   ASSERT_TRUE(cert->VerifyNameMatch(origin.host()));
131   ASSERT_TRUE(cert->VerifyNameMatch(proxy_origin.host()));
132   ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname));
133 
134   ProofVerifyDetailsChromium verify_details;
135   verify_details.cert_verify_result.verified_cert = cert;
136   verify_details.cert_verify_result.is_issued_by_known_root = true;
137   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
138 
139   MockQuicData socket_data(version_);
140   socket_data.AddReadPauseForever();
141   // Creation of underlying session fails immediately.
142   socket_data.AddWrite(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED);
143   socket_data.AddSocketDataToFactory(socket_factory_.get());
144 
145   auto proxy_chain = ProxyChain::ForIpProtection({
146       ProxyServer::FromSchemeHostAndPort(ProxyServer::SCHEME_QUIC,
147                                          proxy_origin.host(), 443),
148   });
149   EXPECT_TRUE(proxy_chain.IsValid());
150 
151   RequestBuilder builder(this);
152   builder.destination = origin;
153   builder.proxy_chain = proxy_chain;
154   builder.http_user_agent_settings = &http_user_agent_settings_;
155   builder.url = url;
156   EXPECT_EQ(ERR_IO_PENDING, builder.CallRequest());
157   ASSERT_EQ(ERR_QUIC_HANDSHAKE_FAILED, callback_.WaitForResult());
158 
159   socket_data.ExpectAllReadDataConsumed();
160   socket_data.ExpectAllWriteDataConsumed();
161 }
162 
TEST_P(QuicSessionPoolProxyJobTest,CreateSessionFails)163 TEST_P(QuicSessionPoolProxyJobTest, CreateSessionFails) {
164   Initialize();
165 
166   GURL url("https://www.example.org/");
167   GURL proxy(kProxy1Url);
168   auto origin = url::SchemeHostPort(url);
169   auto proxy_origin = url::SchemeHostPort(proxy);
170 
171   scoped_refptr<X509Certificate> cert(
172       ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
173   ASSERT_TRUE(cert->VerifyNameMatch(origin.host()));
174   ASSERT_TRUE(cert->VerifyNameMatch(proxy_origin.host()));
175   ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname));
176 
177   ProofVerifyDetailsChromium verify_details;
178   verify_details.cert_verify_result.verified_cert = cert;
179   verify_details.cert_verify_result.is_issued_by_known_root = true;
180   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
181 
182   // QUIC proxies do not use priority header.
183   client_maker_.set_use_priority_header(false);
184 
185   MockQuicData socket_data(version_);
186   socket_data.AddReadPauseForever();  // SYNC/ERR_IO_PENDING
187   socket_data.AddWritePause();
188   socket_data.AddWrite(ASYNC, ConstructInitialSettingsPacket(1));
189   socket_data.AddSocketDataToFactory(socket_factory_.get());
190 
191   auto proxy_chain = ProxyChain::ForIpProtection({
192       ProxyServer::FromSchemeHostAndPort(ProxyServer::SCHEME_QUIC,
193                                          proxy_origin.host(), 443),
194   });
195   EXPECT_TRUE(proxy_chain.IsValid());
196 
197   RequestBuilder builder(this);
198   builder.destination = origin;
199   builder.proxy_chain = proxy_chain;
200   builder.http_user_agent_settings = &http_user_agent_settings_;
201   builder.url = url;
202   EXPECT_EQ(ERR_IO_PENDING, builder.CallRequest());
203 
204   RunUntilIdle();
205 
206   // Oops, the session went away. This generates an error
207   // from `QuicSessionPool::CreateSessionOnProxyStream`.
208   factory_->CloseAllSessions(ERR_QUIC_HANDSHAKE_FAILED,
209                              quic::QuicErrorCode::QUIC_INTERNAL_ERROR);
210   socket_data.Resume();
211 
212   ASSERT_EQ(ERR_QUIC_HANDSHAKE_FAILED, callback_.WaitForResult());
213 }
214 
215 }  // namespace net::test
216