Add a new ExtractQuicVersionFromAltSvcEntry method to SpdyUtils for parsing QUIC versions out of Alt-Svc entries. Will be used in both Chrome and Envoy.

PiperOrigin-RevId: 427540864
diff --git a/quic/core/http/spdy_utils.cc b/quic/core/http/spdy_utils.cc
index 74c9c53..5b74407 100644
--- a/quic/core/http/spdy_utils.cc
+++ b/quic/core/http/spdy_utils.cc
@@ -13,6 +13,7 @@
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
+#include "quic/core/quic_versions.h"
 #include "quic/platform/api/quic_flag_utils.h"
 #include "quic/platform/api/quic_flags.h"
 #include "quic/platform/api/quic_logging.h"
@@ -194,4 +195,23 @@
   (*headers)["datagram-flow-id"] = absl::StrCat(flow_id);
 }
 
+// static
+ParsedQuicVersion SpdyUtils::ExtractQuicVersionFromAltSvcEntry(
+    const spdy::SpdyAltSvcWireFormat::AlternativeService&
+        alternative_service_entry,
+    const ParsedQuicVersionVector& supported_versions) {
+  for (const ParsedQuicVersion& version : supported_versions) {
+    if (version.AlpnDeferToRFCv1()) {
+      // Versions with share an ALPN with v1 are currently unable to be
+      // advertised with Alt-Svc.
+      continue;
+    }
+    if (AlpnForVersion(version) == alternative_service_entry.protocol_id) {
+      return version;
+    }
+  }
+
+  return ParsedQuicVersion::Unsupported();
+}
+
 }  // namespace quic
diff --git a/quic/core/http/spdy_utils.h b/quic/core/http/spdy_utils.h
index 01fae4f..85099ab 100644
--- a/quic/core/http/spdy_utils.h
+++ b/quic/core/http/spdy_utils.h
@@ -14,6 +14,7 @@
 #include "quic/core/http/quic_header_list.h"
 #include "quic/core/quic_packets.h"
 #include "quic/platform/api/quic_export.h"
+#include "spdy/core/spdy_alt_svc_wire_format.h"
 #include "spdy/core/spdy_header_block.h"
 
 namespace quic {
@@ -61,6 +62,14 @@
   // Adds the "datagram-flow-id" header.
   static void AddDatagramFlowIdHeader(spdy::SpdyHeaderBlock* headers,
                                       QuicDatagramStreamId flow_id);
+
+  // Returns the advertised QUIC version from the specified alternative service
+  // advertisement, or ParsedQuicVersion::Unsupported() if no supported version
+  // is advertised.
+  static ParsedQuicVersion ExtractQuicVersionFromAltSvcEntry(
+      const spdy::SpdyAltSvcWireFormat::AlternativeService&
+          alternative_service_entry,
+      const ParsedQuicVersionVector& supported_versions);
 };
 
 }  // namespace quic
diff --git a/quic/core/http/spdy_utils_test.cc b/quic/core/http/spdy_utils_test.cc
index 918739d..85c5cec 100644
--- a/quic/core/http/spdy_utils_test.cc
+++ b/quic/core/http/spdy_utils_test.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "quic/core/http/spdy_utils.h"
+
 #include <memory>
 #include <string>
 
 #include "absl/base/macros.h"
 #include "absl/strings/string_view.h"
-#include "quic/core/http/spdy_utils.h"
+#include "quic/core/quic_versions.h"
 #include "quic/platform/api/quic_test.h"
 
 using spdy::SpdyHeaderBlock;
@@ -408,5 +410,33 @@
   ValidateDatagramFlowId("44; ecn-ect0, 42, 48; ecn-ce, 46; ecn-ect1", 42);
 }
 
+using ExtractQuicVersionFromAltSvcEntry = QuicTest;
+
+TEST_F(ExtractQuicVersionFromAltSvcEntry, SupportedVersion) {
+  ParsedQuicVersionVector supported_versions = AllSupportedVersions();
+  spdy::SpdyAltSvcWireFormat::AlternativeService entry;
+  for (const ParsedQuicVersion& version : supported_versions) {
+    entry.protocol_id = AlpnForVersion(version);
+    ParsedQuicVersion expected_version = version;
+    // Versions with share an ALPN with v1 are currently unable to be
+    // advertised with Alt-Svc.
+    if (entry.protocol_id == AlpnForVersion(ParsedQuicVersion::RFCv1()) &&
+        version != ParsedQuicVersion::RFCv1()) {
+      expected_version = ParsedQuicVersion::RFCv1();
+    }
+    EXPECT_EQ(expected_version, SpdyUtils::ExtractQuicVersionFromAltSvcEntry(
+                                    entry, supported_versions))
+        << "version: " << version;
+  }
+}
+
+TEST_F(ExtractQuicVersionFromAltSvcEntry, UnsupportedVersion) {
+  spdy::SpdyAltSvcWireFormat::AlternativeService entry;
+  entry.protocol_id = "quic";
+  EXPECT_EQ(ParsedQuicVersion::Unsupported(),
+            SpdyUtils::ExtractQuicVersionFromAltSvcEntry(
+                entry, AllSupportedVersions()));
+}
+
 }  // namespace test
 }  // namespace quic