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