1 // Copyright 2023 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 <memory>
6
7 #include "absl/status/status.h"
8 #include "absl/status/statusor.h"
9 #include "absl/strings/numbers.h"
10 #include "absl/strings/string_view.h"
11 #include "quiche/quic/core/web_transport_interface.h"
12 #include "quiche/quic/platform/api/quic_socket_address.h"
13 #include "quiche/quic/tools/devious_baton.h"
14 #include "quiche/quic/tools/quic_server.h"
15 #include "quiche/quic/tools/web_transport_only_backend.h"
16 #include "quiche/quic/tools/web_transport_test_visitors.h"
17 #include "quiche/common/platform/api/quiche_command_line_flags.h"
18 #include "quiche/common/platform/api/quiche_default_proof_providers.h"
19 #include "quiche/common/platform/api/quiche_googleurl.h"
20 #include "quiche/common/platform/api/quiche_logging.h"
21 #include "quiche/common/platform/api/quiche_system_event_loop.h"
22 #include "quiche/common/quiche_random.h"
23 #include "quiche/web_transport/web_transport.h"
24
25 DEFINE_QUICHE_COMMAND_LINE_FLAG(
26 int32_t, port, 6121, "The port the WebTransport server will listen on.");
27
28 namespace quic {
29 namespace {
30
ProcessRequest(absl::string_view path,WebTransportSession * session)31 absl::StatusOr<std::unique_ptr<webtransport::SessionVisitor>> ProcessRequest(
32 absl::string_view path, WebTransportSession* session) {
33 GURL url(absl::StrCat("https://localhost", path));
34 if (!url.is_valid()) {
35 return absl::InvalidArgumentError("Unable to parse the :path");
36 }
37
38 if (url.path() == "/webtransport/echo") {
39 return std::make_unique<EchoWebTransportSessionVisitor>(session);
40 }
41 if (url.path() == "/webtransport/devious-baton") {
42 int count = 1;
43 DeviousBatonValue initial_value =
44 quiche::QuicheRandom::GetInstance()->RandUint64() % 256;
45 std::string query = url.query();
46 url::Component query_component, key_component, value_component;
47 query_component.begin = 0;
48 query_component.len = query.size();
49 while (url::ExtractQueryKeyValue(query.data(), &query_component,
50 &key_component, &value_component)) {
51 absl::string_view key(query.data() + key_component.begin,
52 key_component.len);
53 absl::string_view value(query.data() + value_component.begin,
54 value_component.len);
55 int parsed_value;
56 if (!absl::SimpleAtoi(value, &parsed_value) || parsed_value < 0 ||
57 parsed_value > 255) {
58 if (key == "count" || key == "baton") {
59 return absl::InvalidArgumentError(
60 absl::StrCat("Failed to parse query param ", key));
61 }
62 continue;
63 }
64 if (key == "count") {
65 count = parsed_value;
66 }
67 if (key == "baton") {
68 initial_value = parsed_value;
69 }
70 }
71 return std::make_unique<DeviousBatonSessionVisitor>(
72 session, /*is_server=*/true, initial_value, count);
73 }
74 return absl::NotFoundError("Path not found");
75 }
76
Main(int argc,char ** argv)77 int Main(int argc, char** argv) {
78 quiche::QuicheSystemEventLoop event_loop("web_transport_test_server");
79 const char* usage = "Usage: web_transport_test_server [options]";
80 std::vector<std::string> non_option_args =
81 quiche::QuicheParseCommandLineFlags(usage, argc, argv);
82
83 WebTransportOnlyBackend backend(ProcessRequest);
84 QuicServer server(quiche::CreateDefaultProofSource(), &backend);
85 quic::QuicSocketAddress addr(quic::QuicIpAddress::Any6(),
86 quiche::GetQuicheCommandLineFlag(FLAGS_port));
87 if (!server.CreateUDPSocketAndListen(addr)) {
88 QUICHE_LOG(ERROR) << "Failed to bind the port address";
89 }
90 QUICHE_LOG(INFO) << "Bound the server on " << addr;
91 server.HandleEventsForever();
92 return 0;
93 }
94
95 } // namespace
96 } // namespace quic
97
main(int argc,char ** argv)98 int main(int argc, char** argv) { return quic::Main(argc, argv); }
99