Allow sending additional headers with masque_client

This CL adds the ability to send custom headers on MASQUE requests from the command line.

PiperOrigin-RevId: 593797450
diff --git a/quiche/quic/masque/masque_client_bin.cc b/quiche/quic/masque/masque_client_bin.cc
index 99e93d2..5ee715f 100644
--- a/quiche/quic/masque/masque_client_bin.cc
+++ b/quiche/quic/masque/masque_client_bin.cc
@@ -41,6 +41,12 @@
     "Allows setting MASQUE mode, currently only valid value is \"open\".");
 
 DEFINE_QUICHE_COMMAND_LINE_FLAG(
+    std::string, proxy_headers, "",
+    "A list of HTTP headers to add to request to the MASQUE proxy. "
+    "Separated with colons and semicolons. "
+    "For example: \"name1:value1;name2:value2\".");
+
+DEFINE_QUICHE_COMMAND_LINE_FLAG(
     bool, bring_up_tun, false,
     "If set to true, no URLs need to be specified and instead a TUN device "
     "is brought up with the assigned IP from the MASQUE CONNECT-IP server.");
@@ -306,6 +312,9 @@
   QUIC_LOG(INFO) << "MASQUE is connected " << masque_client->connection_id()
                  << " in " << masque_mode << " mode";
 
+  masque_client->masque_client_session()->set_additional_headers(
+      quiche::GetQuicheCommandLineFlag(FLAGS_proxy_headers));
+
   if (bring_up_tun) {
     QUIC_LOG(INFO) << "Bringing up tun";
     MasqueTunSession tun_session(event_loop.get(),
diff --git a/quiche/quic/masque/masque_client_session.cc b/quiche/quic/masque/masque_client_session.cc
index 57f26d1..14cf58a 100644
--- a/quiche/quic/masque/masque_client_session.cc
+++ b/quiche/quic/masque/masque_client_session.cc
@@ -6,11 +6,13 @@
 
 #include <cstring>
 #include <string>
+#include <vector>
 
 #include "absl/algorithm/container.h"
 #include "absl/container/flat_hash_map.h"
 #include "absl/container/flat_hash_set.h"
 #include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/http/spdy_utils.h"
 #include "quiche/quic/core/quic_data_reader.h"
@@ -21,6 +23,7 @@
 #include "quiche/quic/tools/quic_url.h"
 #include "quiche/common/platform/api/quiche_googleurl.h"
 #include "quiche/common/platform/api/quiche_url_utils.h"
+#include "quiche/common/quiche_text_utils.h"
 #include "quiche/spdy/core/http2_header_block.h"
 
 namespace quic {
@@ -146,6 +149,7 @@
   headers[":authority"] = authority;
   headers[":path"] = canonicalized_path;
   headers["connect-udp-version"] = "12";
+  AddAdditionalHeaders(headers);
   size_t bytes_sent =
       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
   if (bytes_sent == 0) {
@@ -192,6 +196,7 @@
   headers[":authority"] = authority;
   headers[":path"] = path;
   headers["connect-ip-version"] = "3";
+  AddAdditionalHeaders(headers);
   size_t bytes_sent =
       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
   if (bytes_sent == 0) {
@@ -240,6 +245,7 @@
   headers[":scheme"] = scheme;
   headers[":authority"] = authority;
   headers[":path"] = path;
+  AddAdditionalHeaders(headers);
   size_t bytes_sent =
       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
   if (bytes_sent == 0) {
@@ -679,4 +685,22 @@
   fake_addresses_.erase(fake_address.ToPackedString());
 }
 
+void MasqueClientSession::AddAdditionalHeaders(
+    spdy::Http2HeaderBlock& headers) const {
+  if (additional_headers_.empty()) {
+    return;
+  }
+  for (absl::string_view sp : absl::StrSplit(additional_headers_, ';')) {
+    quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&sp);
+    if (sp.empty()) {
+      continue;
+    }
+    std::vector<absl::string_view> kv =
+        absl::StrSplit(sp, absl::MaxSplits(':', 1));
+    quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]);
+    quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]);
+    headers[kv[0]] = kv[1];
+  }
+}
+
 }  // namespace quic
diff --git a/quiche/quic/masque/masque_client_session.h b/quiche/quic/masque/masque_client_session.h
index 9307f74..8b8331e 100644
--- a/quiche/quic/masque/masque_client_session.h
+++ b/quiche/quic/masque/masque_client_session.h
@@ -93,8 +93,7 @@
                       const QuicConfig& config,
                       const ParsedQuicVersionVector& supported_versions,
                       QuicConnection* connection, const QuicServerId& server_id,
-                      QuicCryptoClientConfig* crypto_config,
-                      Owner* owner);
+                      QuicCryptoClientConfig* crypto_config, Owner* owner);
 
   // Disallow copy and assign.
   MasqueClientSession(const MasqueClientSession&) = delete;
@@ -145,6 +144,13 @@
   // Removes a fake address that was previously created by GetFakeAddress().
   void RemoveFakeAddress(const quiche::QuicheIpAddress& fake_address);
 
+  // Set additional HTTP headers that will be sent on all requests to the MASQUE
+  // proxy. Separated with colons and semicolons.
+  // For example: "name1:value1;name2:value2".
+  void set_additional_headers(absl::string_view additional_headers) {
+    additional_headers_ = additional_headers;
+  }
+
  private:
   // State that the MasqueClientSession keeps for each CONNECT-UDP request.
   class QUIC_NO_EXPORT ConnectUdpClientState
@@ -284,8 +290,11 @@
   const ConnectEthernetClientState* GetOrCreateConnectEthernetClientState(
       EncapsulatedEthernetSession* encapsulated_ethernet_session);
 
+  void AddAdditionalHeaders(spdy::Http2HeaderBlock& headers) const;
+
   MasqueMode masque_mode_;
   std::string uri_template_;
+  std::string additional_headers_;
   std::list<ConnectUdpClientState> connect_udp_client_states_;
   std::list<ConnectIpClientState> connect_ip_client_states_;
   std::list<ConnectEthernetClientState> connect_ethernet_client_states_;