Add MasqueSimpleFetch and MasqueSimpleGet

This will help test tools quickly load data using HTTP.

PiperOrigin-RevId: 922773032
diff --git a/quiche/quic/masque/masque_connection_pool.cc b/quiche/quic/masque/masque_connection_pool.cc
index 08b237e..d3803c8 100644
--- a/quiche/quic/masque/masque_connection_pool.cc
+++ b/quiche/quic/masque/masque_connection_pool.cc
@@ -14,6 +14,7 @@
 #include "absl/cleanup/cleanup.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
+#include "absl/strings/match.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_split.h"
@@ -24,13 +25,17 @@
 #include "openssl/ssl.h"
 #include "openssl/stack.h"
 #include "quiche/quic/core/crypto/proof_verifier.h"
+#include "quiche/quic/core/io/quic_default_event_loop.h"
 #include "quiche/quic/core/io/quic_event_loop.h"
 #include "quiche/quic/core/io/socket.h"
+#include "quiche/quic/core/quic_default_clock.h"
+#include "quiche/quic/core/quic_time.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/masque/masque_h2_connection.h"
 #include "quiche/quic/platform/api/quic_default_proof_providers.h"
 #include "quiche/quic/tools/fake_proof_verifier.h"
 #include "quiche/quic/tools/quic_name_lookup.h"
+#include "quiche/quic/tools/quic_url.h"
 #include "quiche/common/http/http_header_block.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/quiche_socket_address.h"
@@ -58,8 +63,104 @@
   }
 };
 
+class SimpleFetcher : public MasqueConnectionPool::Visitor {
+ public:
+  using Message = MasqueConnectionPool::Message;
+  using RequestId = MasqueConnectionPool::RequestId;
+  using DnsConfig = MasqueConnectionPool::DnsConfig;
+  ~SimpleFetcher() override = default;
+
+  static absl::StatusOr<Message> Fetch(const Message& request,
+                                       absl::string_view info_string,
+                                       const DnsConfig& dns_config,
+                                       bool disable_certificate_verification) {
+    SimpleFetcher fetcher;
+    std::unique_ptr<QuicEventLoop> event_loop =
+        GetDefaultEventLoop()->Create(QuicDefaultClock::Get());
+    QUICHE_ASSIGN_OR_RETURN(bssl::UniquePtr<SSL_CTX> ssl_ctx,
+                            MasqueConnectionPool::CreateSslCtx("", ""));
+    MasqueConnectionPool pool(event_loop.get(), ssl_ctx.get(),
+                              disable_certificate_verification, dns_config,
+                              &fetcher, info_string);
+    QUICHE_RETURN_IF_ERROR(pool.SendRequest(request).status());
+    while (!fetcher.done_ && fetcher.status_.ok()) {
+      event_loop->RunEventLoopOnce(quic::QuicTime::Delta::FromMilliseconds(50));
+    }
+    QUICHE_RETURN_IF_ERROR(fetcher.status_);
+    uint16_t status_code =
+        MasqueConnectionPool::GetStatusCode(fetcher.response_);
+    if (status_code < 200 || status_code >= 300) {
+      return absl::InternalError(
+          absl::StrCat("Non-2xx status code: ", status_code));
+    }
+    return std::move(fetcher).response_;
+  }
+
+  static absl::StatusOr<Message> Get(absl::string_view url_string,
+                                     absl::string_view info_string,
+                                     const DnsConfig& dns_config,
+                                     bool disable_certificate_verification) {
+    Message request;
+    QuicUrl url(url_string, "https");
+    if (url.host().empty() && !absl::StrContains(url_string, "://")) {
+      url = QuicUrl(absl::StrCat("https://", url_string));
+    }
+    request.headers[":method"] = "GET";
+    request.headers[":scheme"] = url.scheme();
+    request.headers[":authority"] = url.HostPort();
+    request.headers[":path"] = url.PathParamsQuery();
+    return Fetch(std::move(request), info_string, dns_config,
+                 disable_certificate_verification);
+  }
+
+  // From MasqueConnectionPool::Visitor.
+  void OnPoolResponse(MasqueConnectionPool* /*pool*/, RequestId /*request_id*/,
+                      absl::StatusOr<Message>&& response,
+                      bool end_stream) override {
+    if (!end_stream) {
+      // This should never happen because we don't stream responses.
+      status_ = absl::InternalError("Unexpected non-end_stream OnPoolResponse");
+      return;
+    }
+    if (!response.ok()) {
+      status_ = response.status();
+      return;
+    }
+    response_ = std::move(*response);
+    done_ = true;
+  }
+  void OnPoolData(MasqueConnectionPool* /*pool*/, RequestId /*request_id*/,
+                  absl::string_view /*data*/, bool /*end_stream*/) override {
+    // This should never happen because we don't stream responses.
+    status_ = absl::InternalError("Unexpected OnPoolData");
+  }
+
+ private:
+  SimpleFetcher() = default;
+
+  absl::Status status_ = absl::OkStatus();
+  Message response_;
+  bool done_ = false;
+};
+
 }  // namespace
 
+absl::StatusOr<MasqueConnectionPool::Message> MasqueSimpleFetch(
+    const MasqueConnectionPool::Message& request, absl::string_view info_string,
+    const MasqueConnectionPool::DnsConfig& dns_config,
+    bool disable_certificate_verification) {
+  return SimpleFetcher::Fetch(request, info_string, dns_config,
+                              disable_certificate_verification);
+}
+
+absl::StatusOr<MasqueConnectionPool::Message> MasqueSimpleGet(
+    absl::string_view url_string, absl::string_view info_string,
+    const MasqueConnectionPool::DnsConfig& dns_config,
+    bool disable_certificate_verification) {
+  return SimpleFetcher::Get(url_string, info_string, dns_config,
+                            disable_certificate_verification);
+}
+
 // static
 int16_t MasqueConnectionPool::GetStatusCode(const Message& message) {
   auto it = message.headers.find(":status");
diff --git a/quiche/quic/masque/masque_connection_pool.h b/quiche/quic/masque/masque_connection_pool.h
index 764f72f..26860d9 100644
--- a/quiche/quic/masque/masque_connection_pool.h
+++ b/quiche/quic/masque/masque_connection_pool.h
@@ -194,6 +194,24 @@
   const std::string info_;
 };
 
+// Synchronously performs an HTTP fetch using a single-use MasqueConnectionPool.
+// Returns the HTTP response message or an error. `info_string` is used to
+// identify the request in logs.
+absl::StatusOr<MasqueConnectionPool::Message> MasqueSimpleFetch(
+    const MasqueConnectionPool::Message& request, absl::string_view info_string,
+    const MasqueConnectionPool::DnsConfig& dns_config =
+        MasqueConnectionPool::DnsConfig(),
+    bool disable_certificate_verification = false);
+
+// Synchronously performs an HTTP GET using a single-use MasqueConnectionPool.
+// Returns the HTTP response message or an error. `info_string` is used to
+// identify the request in logs.
+absl::StatusOr<MasqueConnectionPool::Message> MasqueSimpleGet(
+    absl::string_view url_string, absl::string_view info_string,
+    const MasqueConnectionPool::DnsConfig& dns_config =
+        MasqueConnectionPool::DnsConfig(),
+    bool disable_certificate_verification = false);
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_MASQUE_MASQUE_CONNECTION_POOL_H_