Send the path and query parameters of QuicTransport URL in the client indication.

gfe-relnote: n/a (not used in production)
PiperOrigin-RevId: 283837693
Change-Id: I14d5de3a8da4af3af2ee7c00e07ac3feaa4e39f9
diff --git a/quic/quic_transport/quic_transport_client_session.cc b/quic/quic_transport/quic_transport_client_session.cc
index f0110b7..e9487ec 100644
--- a/quic/quic_transport/quic_transport_client_session.cc
+++ b/quic/quic_transport/quic_transport_client_session.cc
@@ -43,7 +43,7 @@
     Visitor* owner,
     const QuicConfig& config,
     const ParsedQuicVersionVector& supported_versions,
-    const QuicServerId& server_id,
+    const GURL& url,
     QuicCryptoClientConfig* crypto_config,
     url::Origin origin,
     ClientVisitor* visitor)
@@ -52,6 +52,7 @@
                   config,
                   supported_versions,
                   /*num_expected_unidirectional_static_streams*/ 0),
+      url_(url),
       origin_(origin),
       visitor_(visitor) {
   for (const ParsedQuicVersion& version : supported_versions) {
@@ -61,8 +62,9 @@
   // ProofHandler API is not used by TLS 1.3.
   static DummyProofHandler* proof_handler = new DummyProofHandler();
   crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
-      server_id, this, crypto_config->proof_verifier()->CreateDefaultContext(),
-      crypto_config, proof_handler);
+      QuicServerId(url.host(), url.EffectiveIntPort()), this,
+      crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config,
+      proof_handler);
 }
 
 QuicStream* QuicTransportClientSession::CreateIncomingStream(QuicStreamId id) {
@@ -153,16 +155,40 @@
   QUIC_DLOG(INFO) << "Sending client indication with origin "
                   << serialized_origin;
 
-  std::string buffer;
-  buffer.resize(/* key */ sizeof(QuicTransportClientIndicationKeys) +
-                /* length */ sizeof(uint16_t) + serialized_origin.size());
-  QuicDataWriter writer(buffer.size(), &buffer[0]);
-  writer.WriteUInt16(
-      static_cast<uint16_t>(QuicTransportClientIndicationKeys::kOrigin));
-  writer.WriteUInt16(serialized_origin.size());
-  writer.WriteStringPiece(serialized_origin);
+  std::string path = url_.PathForRequest();
+  if (path.size() > std::numeric_limits<uint16_t>::max()) {
+    connection()->CloseConnection(
+        QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, "Requested URL path too long",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return "";
+  }
 
-  buffer.resize(writer.length());
+  constexpr size_t kPrefixSize =
+      sizeof(QuicTransportClientIndicationKeys) + sizeof(uint16_t);
+  const size_t buffer_size =
+      2 * kPrefixSize + serialized_origin.size() + path.size();
+  if (buffer_size > std::numeric_limits<uint16_t>::max()) {
+    connection()->CloseConnection(
+        QUIC_TRANSPORT_INVALID_CLIENT_INDICATION,
+        "Client indication size limit exceeded",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return "";
+  }
+
+  std::string buffer;
+  buffer.resize(buffer_size);
+  QuicDataWriter writer(buffer.size(), &buffer[0]);
+  bool success =
+      writer.WriteUInt16(
+          static_cast<uint16_t>(QuicTransportClientIndicationKeys::kOrigin)) &&
+      writer.WriteUInt16(serialized_origin.size()) &&
+      writer.WriteStringPiece(serialized_origin) &&
+      writer.WriteUInt16(
+          static_cast<uint16_t>(QuicTransportClientIndicationKeys::kPath)) &&
+      writer.WriteUInt16(path.size()) && writer.WriteStringPiece(path);
+  QUIC_BUG_IF(!success) << "Failed to serialize client indication";
+  QUIC_BUG_IF(writer.length() != buffer.length())
+      << "Serialized client indication has length different from expected";
   return buffer;
 }
 
diff --git a/quic/quic_transport/quic_transport_client_session.h b/quic/quic_transport/quic_transport_client_session.h
index 5872bf1..b3d8f17 100644
--- a/quic/quic_transport/quic_transport_client_session.h
+++ b/quic/quic_transport/quic_transport_client_session.h
@@ -8,6 +8,7 @@
 #include <cstdint>
 #include <memory>
 
+#include "url/gurl.h"
 #include "url/origin.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
 #include "net/third_party/quiche/src/quic/core/quic_config.h"
@@ -47,7 +48,7 @@
                              Visitor* owner,
                              const QuicConfig& config,
                              const ParsedQuicVersionVector& supported_versions,
-                             const QuicServerId& server_id,
+                             const GURL& url,
                              QuicCryptoClientConfig* crypto_config,
                              url::Origin origin,
                              ClientVisitor* visitor);
@@ -116,6 +117,7 @@
   void SendClientIndication();
 
   std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
+  GURL url_;
   url::Origin origin_;
   ClientVisitor* visitor_;  // not owned
   bool client_indication_sent_ = false;
diff --git a/quic/quic_transport/quic_transport_client_session_test.cc b/quic/quic_transport/quic_transport_client_session_test.cc
index 53213a4..17a4757 100644
--- a/quic/quic_transport/quic_transport_client_session_test.cc
+++ b/quic/quic_transport/quic_transport_client_session_test.cc
@@ -30,8 +30,6 @@
 using testing::ElementsAre;
 
 const char* kTestOrigin = "https://test-origin.test";
-constexpr char kTestOriginClientIndication[] =
-    "\0\0\0\x18https://test-origin.test";
 url::Origin GetTestOrigin() {
   GURL origin_url(kTestOrigin);
   return url::Origin::Create(origin_url);
@@ -58,15 +56,15 @@
                     &alarm_factory_,
                     Perspective::IS_CLIENT,
                     GetVersions()),
-        server_id_("test.example.com", 443),
         crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {
     SetQuicReloadableFlag(quic_supports_tls_handshake, true);
-    CreateSession(GetTestOrigin());
+    CreateSession(GetTestOrigin(), "");
   }
 
-  void CreateSession(url::Origin origin) {
+  void CreateSession(url::Origin origin, std::string url_suffix) {
     session_ = std::make_unique<QuicTransportClientSession>(
-        &connection_, nullptr, DefaultQuicConfig(), GetVersions(), server_id_,
+        &connection_, nullptr, DefaultQuicConfig(), GetVersions(),
+        GURL("quic-transport://test.example.com:50000" + url_suffix),
         &crypto_config_, origin, &visitor_);
     session_->Initialize();
     crypto_stream_ = static_cast<QuicCryptoClientStream*>(
@@ -87,7 +85,6 @@
   MockQuicConnectionHelper helper_;
 
   PacketSavingConnection connection_;
-  QuicServerId server_id_;
   QuicCryptoClientConfig crypto_config_;
   MockClientVisitor visitor_;
   std::unique_ptr<QuicTransportClientSession> session_;
@@ -99,6 +96,39 @@
 }
 
 TEST_F(QuicTransportClientSessionTest, SuccessfulConnection) {
+  constexpr char kTestOriginClientIndication[] =
+      "\0\0"                      // key (0x0000, origin)
+      "\0\x18"                    // length
+      "https://test-origin.test"  // value
+      "\0\x01"                    // key (0x0001, path)
+      "\0\x01"                    // length
+      "/";                        // value
+
+  Connect();
+  EXPECT_TRUE(session_->IsSessionReady());
+
+  QuicStream* client_indication_stream =
+      QuicSessionPeer::zombie_streams(session_.get())[ClientIndicationStream()]
+          .get();
+  ASSERT_TRUE(client_indication_stream != nullptr);
+  const std::string client_indication = DataInStream(client_indication_stream);
+  const std::string expected_client_indication{
+      kTestOriginClientIndication,
+      QUIC_ARRAYSIZE(kTestOriginClientIndication) - 1};
+  EXPECT_EQ(client_indication, expected_client_indication);
+}
+
+TEST_F(QuicTransportClientSessionTest, SuccessfulConnectionWithPath) {
+  constexpr char kSuffix[] = "/foo/bar?hello=world#not-sent";
+  constexpr char kTestOriginClientIndication[] =
+      "\0\0"                      // key (0x0000, origin)
+      "\0\x18"                    // length
+      "https://test-origin.test"  // value
+      "\0\x01"                    // key (0x0001, path)
+      "\0\x14"                    // length
+      "/foo/bar?hello=world";     // value
+
+  CreateSession(GetTestOrigin(), kSuffix);
   Connect();
   EXPECT_TRUE(session_->IsSessionReady());
 
@@ -117,7 +147,7 @@
   std::string long_string(68000, 'a');
   GURL bad_origin_url{"https://" + long_string + ".example/"};
   EXPECT_TRUE(bad_origin_url.is_valid());
-  CreateSession(url::Origin::Create(bad_origin_url));
+  CreateSession(url::Origin::Create(bad_origin_url), "");
 
   EXPECT_QUIC_BUG(Connect(), "Client origin too long");
 }
diff --git a/quic/quic_transport/quic_transport_integration_test.cc b/quic/quic_transport/quic_transport_integration_test.cc
index 715bd9f..57f5380 100644
--- a/quic/quic_transport/quic_transport_integration_test.cc
+++ b/quic/quic_transport/quic_transport_integration_test.cc
@@ -80,7 +80,7 @@
                  nullptr,
                  DefaultQuicConfig(),
                  GetVersions(),
-                 QuicServerId("test.example.com", 443),
+                 GURL("quic-transport://test.example.com:50000"),
                  &crypto_config_,
                  origin,
                  &visitor_) {
diff --git a/quic/quic_transport/quic_transport_protocol.h b/quic/quic_transport/quic_transport_protocol.h
index 47ed877..f97b8e7 100644
--- a/quic/quic_transport/quic_transport_protocol.h
+++ b/quic/quic_transport/quic_transport_protocol.h
@@ -29,6 +29,7 @@
 // The keys of the fields in the client indication.
 enum class QuicTransportClientIndicationKeys : uint16_t {
   kOrigin = 0x0000,
+  kPath = 0x0001,
 };
 
 }  // namespace quic