| // Copyright 2019 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // This file is reponsible for the masque_client binary. It allows testing | 
 | // our MASQUE client code by connecting to a MASQUE proxy and then sending | 
 | // HTTP/3 requests to web servers tunnelled over that MASQUE connection. | 
 | // e.g.: masque_client $PROXY_HOST:$PROXY_PORT $URL1 $URL2 | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include "absl/strings/str_cat.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "url/third_party/mozilla/url_parse.h" | 
 | #include "quic/core/quic_server_id.h" | 
 | #include "quic/masque/masque_client_tools.h" | 
 | #include "quic/masque/masque_encapsulated_epoll_client.h" | 
 | #include "quic/masque/masque_epoll_client.h" | 
 | #include "quic/masque/masque_utils.h" | 
 | #include "quic/platform/api/quic_default_proof_providers.h" | 
 | #include "quic/platform/api/quic_flags.h" | 
 | #include "quic/platform/api/quic_socket_address.h" | 
 | #include "quic/platform/api/quic_system_event_loop.h" | 
 | #include "quic/tools/fake_proof_verifier.h" | 
 |  | 
 | DEFINE_QUIC_COMMAND_LINE_FLAG(bool, | 
 |                               disable_certificate_verification, | 
 |                               false, | 
 |                               "If true, don't verify the server certificate."); | 
 |  | 
 | DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, | 
 |                               masque_mode, | 
 |                               "", | 
 |                               "Allows setting MASQUE mode, valid values are " | 
 |                               "open and legacy. Defaults to open."); | 
 |  | 
 | namespace quic { | 
 |  | 
 | namespace { | 
 |  | 
 | int RunMasqueClient(int argc, char* argv[]) { | 
 |   QuicSystemEventLoop event_loop("masque_client"); | 
 |   const char* usage = "Usage: masque_client [options] <url>"; | 
 |  | 
 |   // The first non-flag argument is the URI template of the MASQUE server. | 
 |   // All subsequent ones are interpreted as URLs to fetch via the MASQUE server. | 
 |   // Note that the URI template expansion currently only supports string | 
 |   // replacement of {target_host} and {target_port}, not | 
 |   // {?target_host,target_port}. | 
 |   std::vector<std::string> urls = QuicParseCommandLineFlags(usage, argc, argv); | 
 |   if (urls.empty()) { | 
 |     QuicPrintCommandLineFlagHelp(usage); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   const bool disable_certificate_verification = | 
 |       GetQuicFlag(FLAGS_disable_certificate_verification); | 
 |   QuicEpollServer epoll_server; | 
 |  | 
 |   std::string uri_template = urls[0]; | 
 |   if (!absl::StrContains(uri_template, '/')) { | 
 |     // Allow passing in authority instead of URI template. | 
 |     uri_template = | 
 |         absl::StrCat("https://", uri_template, "/{target_host}/{target_port}/"); | 
 |   } | 
 |   url::Parsed parsed_uri_template; | 
 |   url::ParseStandardURL(uri_template.c_str(), uri_template.length(), | 
 |                         &parsed_uri_template); | 
 |   if (!parsed_uri_template.scheme.is_nonempty() || | 
 |       !parsed_uri_template.host.is_nonempty() || | 
 |       !parsed_uri_template.path.is_nonempty()) { | 
 |     std::cerr << "Failed to parse MASQUE URI template \"" << urls[0] << "\"" | 
 |               << std::endl; | 
 |     return 1; | 
 |   } | 
 |   std::string host = uri_template.substr(parsed_uri_template.host.begin, | 
 |                                          parsed_uri_template.host.len); | 
 |   std::unique_ptr<ProofVerifier> proof_verifier; | 
 |   if (disable_certificate_verification) { | 
 |     proof_verifier = std::make_unique<FakeProofVerifier>(); | 
 |   } else { | 
 |     proof_verifier = CreateDefaultProofVerifier(host); | 
 |   } | 
 |   MasqueMode masque_mode = MasqueMode::kOpen; | 
 |   std::string mode_string = GetQuicFlag(FLAGS_masque_mode); | 
 |   if (mode_string == "legacy") { | 
 |     masque_mode = MasqueMode::kLegacy; | 
 |   } else if (!mode_string.empty() && mode_string != "open") { | 
 |     std::cerr << "Invalid masque_mode \"" << mode_string << "\"" << std::endl; | 
 |     return 1; | 
 |   } | 
 |   std::unique_ptr<MasqueEpollClient> masque_client = MasqueEpollClient::Create( | 
 |       uri_template, masque_mode, &epoll_server, std::move(proof_verifier)); | 
 |   if (masque_client == nullptr) { | 
 |     return 1; | 
 |   } | 
 |  | 
 |   std::cerr << "MASQUE is connected " << masque_client->connection_id() | 
 |             << " in " << masque_mode << " mode" << std::endl; | 
 |  | 
 |   for (size_t i = 1; i < urls.size(); ++i) { | 
 |     if (!tools::SendEncapsulatedMasqueRequest( | 
 |             masque_client.get(), &epoll_server, urls[i], | 
 |             disable_certificate_verification)) { | 
 |       return 1; | 
 |     } | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | }  // namespace quic | 
 |  | 
 | int main(int argc, char* argv[]) { | 
 |   return quic::RunMasqueClient(argc, argv); | 
 | } |