Add a QUIC protocol flag to not require the the kSPAD connection option
in order to use QUIC server preferred address support.
quic_always_support_server_preferred_address defaults to false to match
existing behavior but may be set to true.  This will make it easier for
QUICHE servers to support non-QUICHE clients using server preferred address.

For context: https://github.com/envoyproxy/envoy/pull/32130

PiperOrigin-RevId: 603488744
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index 6024569..3eaddf2 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -467,7 +467,9 @@
       server_writer_ = new PacketDroppingTestWriter();
       StartServer();
 
-      client_config_.SetConnectionOptionsToSend(QuicTagVector{kSPAD});
+      if (!GetQuicFlag(quic_always_support_server_preferred_address)) {
+        client_config_.SetConnectionOptionsToSend(QuicTagVector{kSPAD});
+      }
     }
 
     if (!connect_to_server_on_initialize_) {
@@ -5467,6 +5469,35 @@
   EXPECT_FALSE(client_stats.failed_to_validate_server_preferred_address);
 }
 
+TEST_P(EndToEndTest, SimpleServerPreferredAddressTestNoSPAD) {
+  SetQuicFlag(quic_always_support_server_preferred_address, true);
+  use_preferred_address_ = true;
+  ASSERT_TRUE(Initialize());
+  if (!version_.HasIetfQuicFrames()) {
+    return;
+  }
+  client_.reset(CreateQuicClient(nullptr));
+  QuicConnection* client_connection = GetClientConnection();
+  EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed());
+  EXPECT_EQ(server_address_, client_connection->effective_peer_address());
+  EXPECT_EQ(server_address_, client_connection->peer_address());
+  EXPECT_TRUE(client_->client()->HasPendingPathValidation());
+  QuicConnectionId server_cid1 = client_connection->connection_id();
+
+  SendSynchronousFooRequestAndCheckResponse();
+  while (client_->client()->HasPendingPathValidation()) {
+    client_->client()->WaitForEvents();
+  }
+  EXPECT_EQ(server_preferred_address_,
+            client_connection->effective_peer_address());
+  EXPECT_EQ(server_preferred_address_, client_connection->peer_address());
+  EXPECT_NE(server_cid1, client_connection->connection_id());
+
+  const auto client_stats = GetClientConnection()->GetStats();
+  EXPECT_TRUE(client_stats.server_preferred_address_validated);
+  EXPECT_FALSE(client_stats.failed_to_validate_server_preferred_address);
+}
+
 TEST_P(EndToEndTest, OptimizedServerPreferredAddress) {
   use_preferred_address_ = true;
   ASSERT_TRUE(Initialize());
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc
index 75d29f3..2516c8c 100644
--- a/quiche/quic/core/quic_config.cc
+++ b/quiche/quic/core/quic_config.cc
@@ -1428,4 +1428,9 @@
   }
 }
 
+bool QuicConfig::SupportsServerPreferredAddress(Perspective perspective) const {
+  return HasClientSentConnectionOption(kSPAD, perspective) ||
+         GetQuicFlag(quic_always_support_server_preferred_address);
+}
+
 }  // namespace quic
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h
index bf1cc6c..c635689 100644
--- a/quiche/quic/core/quic_config.h
+++ b/quiche/quic/core/quic_config.h
@@ -418,6 +418,11 @@
   void ClearAlternateServerAddressToSend(
       quiche::IpAddressFamily address_family);
 
+  // Returns true if this config supports server preferred address,
+  // either via the kSPAD connection option or the QUIC protocol flag
+  // quic_always_support_server_preferred_address.
+  bool SupportsServerPreferredAddress(Perspective perspective) const;
+
   // Original destination connection ID.
   void SetOriginalConnectionIdToSend(
       const QuicConnectionId& original_destination_connection_id);
diff --git a/quiche/quic/core/quic_config_test.cc b/quiche/quic/core/quic_config_test.cc
index 86e5a99..625f645 100644
--- a/quiche/quic/core/quic_config_test.cc
+++ b/quiche/quic/core/quic_config_test.cc
@@ -568,6 +568,26 @@
             kTestServerAddressV6);
 }
 
+TEST_P(QuicConfigTest, SupportsServerPreferredAddress) {
+  SetQuicFlag(quic_always_support_server_preferred_address, true);
+  EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT));
+  EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER));
+
+  SetQuicFlag(quic_always_support_server_preferred_address, false);
+  EXPECT_FALSE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT));
+  EXPECT_FALSE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER));
+
+  QuicTagVector copt;
+  copt.push_back(kSPAD);
+  config_.SetConnectionOptionsToSend(copt);
+  EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT));
+  EXPECT_FALSE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER));
+
+  config_.SetInitialReceivedConnectionOptions(copt);
+  EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT));
+  EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER));
+}
+
 TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
   if (!version_.UsesTls()) {
     // TransportParameters are only used for QUIC+TLS.
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 3a3b356..88f52d8 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -648,7 +648,7 @@
 
   if (version().HasIetfQuicFrames() &&
       config.HasReceivedPreferredAddressConnectionIdAndToken() &&
-      config.HasClientSentConnectionOption(kSPAD, perspective_)) {
+      config.SupportsServerPreferredAddress(perspective_)) {
     if (self_address().host().IsIPv4() &&
         config.HasReceivedIPv4AlternateServerAddress()) {
       received_server_preferred_address_ =
diff --git a/quiche/quic/core/quic_protocol_flags_list.h b/quiche/quic/core/quic_protocol_flags_list.h
index bd337e9..417c1a6 100644
--- a/quiche/quic/core/quic_protocol_flags_list.h
+++ b/quiche/quic/core/quic_protocol_flags_list.h
@@ -231,4 +231,8 @@
     bool, quic_enable_chaos_protection, true,
     "If true, use chaos protection to randomize client initials.")
 
+QUIC_PROTOCOL_FLAG(bool, quic_always_support_server_preferred_address, false,
+                   "If false, the kSPAD connection option is required to use "
+                   "QUIC server preferred address support.")
+
 #endif
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index 6e655c5..359841a 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -1384,7 +1384,7 @@
 
   if (perspective_ == Perspective::IS_SERVER && version().HasIetfQuicFrames() &&
       connection_->effective_peer_address().IsInitialized()) {
-    if (config_.HasClientSentConnectionOption(kSPAD, perspective_)) {
+    if (config_.SupportsServerPreferredAddress(perspective_)) {
       quiche::IpAddressFamily address_family =
           connection_->effective_peer_address()
               .Normalized()