xref: /aosp_15_r20/external/cronet/net/test/quic_simple_test_server.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/test/quic_simple_test_server.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/functional/bind.h"
13 #include "base/message_loop/message_pump_type.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/threading/thread.h"
19 #include "net/base/ip_address.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/base/port_util.h"
22 #include "net/quic/crypto/proof_source_chromium.h"
23 #include "net/test/test_data_directory.h"
24 #include "net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.h"
25 #include "net/third_party/quiche/src/quiche/quic/tools/quic_memory_cache_backend.h"
26 #include "net/tools/quic/quic_simple_server.h"
27 
28 namespace {
29 
30 const char kTestServerDomain[] = "example.com";
31 // This must match the certificate used (quic-chain.pem and quic-leaf-cert.key).
32 const char kTestServerHost[] = "test.example.com";
33 
34 const char kStatusHeader[] = ":status";
35 
36 const char kHelloPath[] = "/hello.txt";
37 const char kHelloBodyValue[] = "Hello from QUIC Server";
38 const char kHelloStatus[] = "200";
39 
40 const char kHelloHeaderName[] = "hello_header";
41 const char kHelloHeaderValue[] = "hello header value";
42 
43 const char kHelloTrailerName[] = "hello_trailer";
44 const char kHelloTrailerValue[] = "hello trailer value";
45 
46 const char kSimplePath[] = "/simple.txt";
47 const char kSimpleBodyValue[] = "Simple Hello from QUIC Server";
48 const char kSimpleStatus[] = "200";
49 
50 const char kSimpleHeaderName[] = "hello_header";
51 const char kSimpleHeaderValue[] = "hello header value";
52 const std::string kCombinedHelloHeaderValue = std::string("foo\0bar", 7);
53 const char kCombinedHeaderName[] = "combined";
54 
55 base::Thread* g_quic_server_thread = nullptr;
56 quic::QuicMemoryCacheBackend* g_quic_cache_backend = nullptr;
57 net::QuicSimpleServer* g_quic_server = nullptr;
58 int g_quic_server_port = 0;
59 
60 }  // namespace
61 
62 namespace net {
63 
GetDomain()64 std::string const QuicSimpleTestServer::GetDomain() {
65   return kTestServerDomain;
66 }
67 
GetHost()68 std::string const QuicSimpleTestServer::GetHost() {
69   return kTestServerHost;
70 }
71 
GetHostPort()72 HostPortPair const QuicSimpleTestServer::GetHostPort() {
73   return HostPortPair(kTestServerHost, GetPort());
74 }
75 
GetFileURL(const std::string & file_path)76 GURL QuicSimpleTestServer::GetFileURL(const std::string& file_path) {
77   return GURL("https://test.example.com:" + base::NumberToString(GetPort()))
78       .Resolve(file_path);
79 }
80 
GetHelloURL()81 GURL QuicSimpleTestServer::GetHelloURL() {
82   // Don't include |port| into Hello URL as it is mapped differently.
83   return GURL("https://test.example.com").Resolve(kHelloPath);
84 }
85 
GetStatusHeaderName()86 std::string const QuicSimpleTestServer::GetStatusHeaderName() {
87   return kStatusHeader;
88 }
89 
90 // Hello Url returns response with HTTP/2 headers and trailers.
GetHelloPath()91 std::string const QuicSimpleTestServer::GetHelloPath() {
92   return kHelloPath;
93 }
94 
GetHelloBodyValue()95 std::string const QuicSimpleTestServer::GetHelloBodyValue() {
96   return kHelloBodyValue;
97 }
GetHelloStatus()98 std::string const QuicSimpleTestServer::GetHelloStatus() {
99   return kHelloStatus;
100 }
101 
GetHelloHeaderName()102 std::string const QuicSimpleTestServer::GetHelloHeaderName() {
103   return kHelloHeaderName;
104 }
105 
GetHelloHeaderValue()106 std::string const QuicSimpleTestServer::GetHelloHeaderValue() {
107   return kHelloHeaderValue;
108 }
109 
GetCombinedHeaderName()110 std::string const QuicSimpleTestServer::GetCombinedHeaderName() {
111   return kCombinedHeaderName;
112 }
113 
GetHelloTrailerName()114 std::string const QuicSimpleTestServer::GetHelloTrailerName() {
115   return kHelloTrailerName;
116 }
117 
GetHelloTrailerValue()118 std::string const QuicSimpleTestServer::GetHelloTrailerValue() {
119   return kHelloTrailerValue;
120 }
121 
122 // Simple Url returns response without HTTP/2 trailers.
GetSimpleURL()123 GURL QuicSimpleTestServer::GetSimpleURL() {
124   // Don't include |port| into Simple URL as it is mapped differently.
125   return GURL("https://test.example.com").Resolve(kSimplePath);
126 }
127 
GetSimpleBodyValue()128 std::string const QuicSimpleTestServer::GetSimpleBodyValue() {
129   return kSimpleBodyValue;
130 }
131 
GetSimpleStatus()132 std::string const QuicSimpleTestServer::GetSimpleStatus() {
133   return kSimpleStatus;
134 }
135 
GetSimpleHeaderName()136 std::string const QuicSimpleTestServer::GetSimpleHeaderName() {
137   return kSimpleHeaderName;
138 }
139 
GetSimpleHeaderValue()140 std::string const QuicSimpleTestServer::GetSimpleHeaderValue() {
141   return kSimpleHeaderValue;
142 }
143 
SetupQuicMemoryCacheBackend()144 void SetupQuicMemoryCacheBackend() {
145   spdy::Http2HeaderBlock headers;
146   headers[kHelloHeaderName] = kHelloHeaderValue;
147   headers[kStatusHeader] = kHelloStatus;
148   headers[kCombinedHeaderName] = kCombinedHelloHeaderValue;
149   spdy::Http2HeaderBlock trailers;
150   trailers[kHelloTrailerName] = kHelloTrailerValue;
151   g_quic_cache_backend = new quic::QuicMemoryCacheBackend();
152   g_quic_cache_backend->AddResponse(base::StringPrintf("%s", kTestServerHost),
153                                     kHelloPath, std::move(headers),
154                                     kHelloBodyValue, std::move(trailers));
155   headers[kSimpleHeaderName] = kSimpleHeaderValue;
156   headers[kStatusHeader] = kSimpleStatus;
157   g_quic_cache_backend->AddResponse(base::StringPrintf("%s", kTestServerHost),
158                                     kSimplePath, std::move(headers),
159                                     kSimpleBodyValue);
160 }
161 
StartQuicServerOnServerThread(const base::FilePath & test_files_root,base::WaitableEvent * server_started_event)162 void StartQuicServerOnServerThread(const base::FilePath& test_files_root,
163                                    base::WaitableEvent* server_started_event) {
164   CHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
165   CHECK(!g_quic_server);
166 
167   quic::QuicConfig config;
168   // Set up server certs.
169   base::FilePath directory;
170   directory = test_files_root;
171   auto proof_source = std::make_unique<ProofSourceChromium>();
172   CHECK(proof_source->Initialize(directory.AppendASCII("quic-chain.pem"),
173                                  directory.AppendASCII("quic-leaf-cert.key"),
174                                  base::FilePath()));
175   SetupQuicMemoryCacheBackend();
176 
177   // If we happen to list on a disallowed port, connections will fail. Try in a
178   // loop until we get an allowed port.
179   std::unique_ptr<QuicSimpleServer> server;
180   bool got_allowed_port = false;
181   constexpr int kMaxTries = 100;
182   int rv = 0;
183 
184   for (int tries = 0; !got_allowed_port && tries < kMaxTries; ++tries) {
185     server = std::make_unique<QuicSimpleServer>(
186         std::move(proof_source), config,
187         quic::QuicCryptoServerConfig::ConfigOptions(),
188         quic::AllSupportedVersions(), g_quic_cache_backend);
189 
190     // Start listening on an unbound port.
191     rv = server->Listen(IPEndPoint(IPAddress::IPv4AllZeros(), 0));
192     if (rv >= 0) {
193       got_allowed_port |= IsPortAllowedForScheme(
194           server->server_address().port(), url::kHttpsScheme);
195     }
196   }
197 
198   CHECK_GE(rv, 0) << "QuicSimpleTestServer: Listen failed";
199   CHECK(got_allowed_port);
200   g_quic_server_port = server->server_address().port();
201   g_quic_server = server.release();
202   server_started_event->Signal();
203 }
204 
ShutdownOnServerThread(base::WaitableEvent * server_stopped_event)205 void ShutdownOnServerThread(base::WaitableEvent* server_stopped_event) {
206   DCHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
207   g_quic_server->Shutdown();
208   delete g_quic_server;
209   g_quic_server = nullptr;
210   delete g_quic_cache_backend;
211   g_quic_cache_backend = nullptr;
212   server_stopped_event->Signal();
213 }
214 
ShutdownDispatcherOnServerThread(base::WaitableEvent * dispatcher_stopped_event)215 void ShutdownDispatcherOnServerThread(
216     base::WaitableEvent* dispatcher_stopped_event) {
217   DCHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
218   g_quic_server->dispatcher()->Shutdown();
219   dispatcher_stopped_event->Signal();
220 }
221 
Start()222 bool QuicSimpleTestServer::Start() {
223   CHECK(!g_quic_server_thread);
224   g_quic_server_thread = new base::Thread("quic server thread");
225   base::Thread::Options thread_options;
226   thread_options.message_pump_type = base::MessagePumpType::IO;
227   bool started =
228       g_quic_server_thread->StartWithOptions(std::move(thread_options));
229   CHECK(started);
230   base::FilePath test_files_root = GetTestCertsDirectory();
231 
232   base::WaitableEvent server_started_event(
233       base::WaitableEvent::ResetPolicy::MANUAL,
234       base::WaitableEvent::InitialState::NOT_SIGNALED);
235   g_quic_server_thread->task_runner()->PostTask(
236       FROM_HERE, base::BindOnce(&StartQuicServerOnServerThread, test_files_root,
237                                 &server_started_event));
238   server_started_event.Wait();
239   return true;
240 }
241 
AddResponse(const std::string & path,spdy::Http2HeaderBlock response_headers,const std::string & response_body)242 void QuicSimpleTestServer::AddResponse(const std::string& path,
243                                        spdy::Http2HeaderBlock response_headers,
244                                        const std::string& response_body) {
245   g_quic_cache_backend->AddResponse(
246       base::StringPrintf("%s:%d", kTestServerHost, GetPort()), path,
247       std::move(response_headers), response_body);
248 }
249 
AddResponseWithEarlyHints(const std::string & path,const spdy::Http2HeaderBlock & response_headers,const std::string & response_body,const std::vector<spdy::Http2HeaderBlock> & early_hints)250 void QuicSimpleTestServer::AddResponseWithEarlyHints(
251     const std::string& path,
252     const spdy::Http2HeaderBlock& response_headers,
253     const std::string& response_body,
254     const std::vector<spdy::Http2HeaderBlock>& early_hints) {
255   g_quic_cache_backend->AddResponseWithEarlyHints(kTestServerHost, path,
256                                                   response_headers.Clone(),
257                                                   response_body, early_hints);
258 }
259 
SetResponseDelay(const std::string & path,base::TimeDelta delay)260 void QuicSimpleTestServer::SetResponseDelay(const std::string& path,
261                                             base::TimeDelta delay) {
262   g_quic_cache_backend->SetResponseDelay(
263       base::StringPrintf("%s:%d", kTestServerHost, GetPort()), path,
264       quic::QuicTime::Delta::FromMicroseconds(delay.InMicroseconds()));
265 }
266 
267 // Shut down the server dispatcher, and the stream should error out.
ShutdownDispatcherForTesting()268 void QuicSimpleTestServer::ShutdownDispatcherForTesting() {
269   if (!g_quic_server)
270     return;
271   DCHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
272   base::WaitableEvent dispatcher_stopped_event(
273       base::WaitableEvent::ResetPolicy::MANUAL,
274       base::WaitableEvent::InitialState::NOT_SIGNALED);
275   g_quic_server_thread->task_runner()->PostTask(
276       FROM_HERE, base::BindOnce(&ShutdownDispatcherOnServerThread,
277                                 &dispatcher_stopped_event));
278   dispatcher_stopped_event.Wait();
279 }
280 
Shutdown()281 void QuicSimpleTestServer::Shutdown() {
282   if (!g_quic_server)
283     return;
284   DCHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
285   base::WaitableEvent server_stopped_event(
286       base::WaitableEvent::ResetPolicy::MANUAL,
287       base::WaitableEvent::InitialState::NOT_SIGNALED);
288   g_quic_server_thread->task_runner()->PostTask(
289       FROM_HERE,
290       base::BindOnce(&ShutdownOnServerThread, &server_stopped_event));
291   server_stopped_event.Wait();
292   delete g_quic_server_thread;
293   g_quic_server_thread = nullptr;
294 }
295 
GetPort()296 int QuicSimpleTestServer::GetPort() {
297   return g_quic_server_port;
298 }
299 
300 }  // namespace net
301