• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 
5 #include "quiche/quic/tools/quic_toy_server.h"
6 
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include "absl/container/flat_hash_set.h"
12 #include "absl/strings/str_cat.h"
13 #include "absl/strings/str_split.h"
14 #include "absl/strings/string_view.h"
15 #include "quiche/quic/core/quic_server_id.h"
16 #include "quiche/quic/core/quic_versions.h"
17 #include "quiche/quic/platform/api/quic_default_proof_providers.h"
18 #include "quiche/quic/platform/api/quic_socket_address.h"
19 #include "quiche/quic/tools/connect_server_backend.h"
20 #include "quiche/quic/tools/quic_memory_cache_backend.h"
21 #include "quiche/common/platform/api/quiche_command_line_flags.h"
22 #include "quiche/common/platform/api/quiche_logging.h"
23 #include "quiche/common/quiche_random.h"
24 
25 DEFINE_QUICHE_COMMAND_LINE_FLAG(int32_t, port, 6121,
26                                 "The port the quic server will listen on.");
27 
28 DEFINE_QUICHE_COMMAND_LINE_FLAG(
29     std::string, quic_response_cache_dir, "",
30     "Specifies the directory used during QuicHttpResponseCache "
31     "construction to seed the cache. Cache directory can be "
32     "generated using `wget -p --save-headers <url>`");
33 
34 DEFINE_QUICHE_COMMAND_LINE_FLAG(
35     bool, generate_dynamic_responses, false,
36     "If true, then URLs which have a numeric path will send a dynamically "
37     "generated response of that many bytes.");
38 
39 DEFINE_QUICHE_COMMAND_LINE_FLAG(
40     std::string, quic_versions, "",
41     "QUIC versions to enable, e.g. \"h3-25,h3-27\". If not set, then all "
42     "available versions are enabled.");
43 
44 DEFINE_QUICHE_COMMAND_LINE_FLAG(bool, enable_webtransport, false,
45                                 "If true, WebTransport support is enabled.");
46 
47 DEFINE_QUICHE_COMMAND_LINE_FLAG(
48     std::string, connect_proxy_destinations, "",
49     "Specifies a comma-separated list of destinations (\"hostname:port\") to "
50     "which the QUIC server will allow tunneling via CONNECT.");
51 
52 DEFINE_QUICHE_COMMAND_LINE_FLAG(
53     std::string, connect_udp_proxy_targets, "",
54     "Specifies a comma-separated list of target servers (\"hostname:port\") to "
55     "which the QUIC server will allow tunneling via CONNECT-UDP.");
56 
57 DEFINE_QUICHE_COMMAND_LINE_FLAG(
58     std::string, proxy_server_label, "",
59     "Specifies an identifier to identify the server in proxy error headers, "
60     "per the requirements of RFC 9209, Section 2. It should uniquely identify "
61     "the running service between separate running instances of the QUIC toy "
62     "server binary. If not specified, one will be randomly generated as "
63     "\"QuicToyServerN\" where N is a random uint64_t.");
64 
65 namespace quic {
66 
67 std::unique_ptr<quic::QuicSimpleServerBackend>
CreateBackend()68 QuicToyServer::MemoryCacheBackendFactory::CreateBackend() {
69   auto memory_cache_backend = std::make_unique<QuicMemoryCacheBackend>();
70   if (quiche::GetQuicheCommandLineFlag(FLAGS_generate_dynamic_responses)) {
71     memory_cache_backend->GenerateDynamicResponses();
72   }
73   if (!quiche::GetQuicheCommandLineFlag(FLAGS_quic_response_cache_dir)
74            .empty()) {
75     memory_cache_backend->InitializeBackend(
76         quiche::GetQuicheCommandLineFlag(FLAGS_quic_response_cache_dir));
77   }
78   if (quiche::GetQuicheCommandLineFlag(FLAGS_enable_webtransport)) {
79     memory_cache_backend->EnableWebTransport();
80   }
81 
82   if (!quiche::GetQuicheCommandLineFlag(FLAGS_connect_proxy_destinations)
83            .empty() ||
84       !quiche::GetQuicheCommandLineFlag(FLAGS_connect_udp_proxy_targets)
85            .empty()) {
86     absl::flat_hash_set<QuicServerId> connect_proxy_destinations;
87     for (absl::string_view destination : absl::StrSplit(
88              quiche::GetQuicheCommandLineFlag(FLAGS_connect_proxy_destinations),
89              ',', absl::SkipEmpty())) {
90       std::optional<QuicServerId> destination_server_id =
91           QuicServerId::ParseFromHostPortString(destination);
92       QUICHE_CHECK(destination_server_id.has_value());
93       connect_proxy_destinations.insert(
94           std::move(destination_server_id).value());
95     }
96 
97     absl::flat_hash_set<QuicServerId> connect_udp_proxy_targets;
98     for (absl::string_view target : absl::StrSplit(
99              quiche::GetQuicheCommandLineFlag(FLAGS_connect_udp_proxy_targets),
100              ',', absl::SkipEmpty())) {
101       std::optional<QuicServerId> target_server_id =
102           QuicServerId::ParseFromHostPortString(target);
103       QUICHE_CHECK(target_server_id.has_value());
104       connect_udp_proxy_targets.insert(std::move(target_server_id).value());
105     }
106 
107     QUICHE_CHECK(!connect_proxy_destinations.empty() ||
108                  !connect_udp_proxy_targets.empty());
109 
110     std::string proxy_server_label =
111         quiche::GetQuicheCommandLineFlag(FLAGS_proxy_server_label);
112     if (proxy_server_label.empty()) {
113       proxy_server_label = absl::StrCat(
114           "QuicToyServer",
115           quiche::QuicheRandom::GetInstance()->InsecureRandUint64());
116     }
117 
118     return std::make_unique<ConnectServerBackend>(
119         std::move(memory_cache_backend), std::move(connect_proxy_destinations),
120         std::move(connect_udp_proxy_targets), std::move(proxy_server_label));
121   }
122 
123   return memory_cache_backend;
124 }
125 
QuicToyServer(BackendFactory * backend_factory,ServerFactory * server_factory)126 QuicToyServer::QuicToyServer(BackendFactory* backend_factory,
127                              ServerFactory* server_factory)
128     : backend_factory_(backend_factory), server_factory_(server_factory) {}
129 
Start()130 int QuicToyServer::Start() {
131   ParsedQuicVersionVector supported_versions = AllSupportedVersions();
132   std::string versions_string =
133       quiche::GetQuicheCommandLineFlag(FLAGS_quic_versions);
134   if (!versions_string.empty()) {
135     supported_versions = ParseQuicVersionVectorString(versions_string);
136   }
137   if (supported_versions.empty()) {
138     return 1;
139   }
140   for (const auto& version : supported_versions) {
141     QuicEnableVersion(version);
142   }
143   auto proof_source = quic::CreateDefaultProofSource();
144   auto backend = backend_factory_->CreateBackend();
145   auto server = server_factory_->CreateServer(
146       backend.get(), std::move(proof_source), supported_versions);
147 
148   if (!server->CreateUDPSocketAndListen(quic::QuicSocketAddress(
149           quic::QuicIpAddress::Any6(),
150           quiche::GetQuicheCommandLineFlag(FLAGS_port)))) {
151     return 1;
152   }
153 
154   server->HandleEventsForever();
155   return 0;
156 }
157 
158 }  // namespace quic
159