Make ALPN an array in QuicBufferedPacketStore
This is required to support QUIC+TLS where
ALPN is encoded as a list instead of a
single value.
gfe-relnote: refactor, no behavior change, not flag protected
PiperOrigin-RevId: 307922725
Change-Id: I08bbb0dc6db9264d17a64f569cf459ca590787c9
diff --git a/quic/core/quic_buffered_packet_store.cc b/quic/core/quic_buffered_packet_store.cc
index e363461..24ca6ef 100644
--- a/quic/core/quic_buffered_packet_store.cc
+++ b/quic/core/quic_buffered_packet_store.cc
@@ -138,7 +138,7 @@
// Add CHLO to the beginning of buffered packets so that it can be delivered
// first later.
queue.buffered_packets.push_front(std::move(new_entry));
- queue.alpn = alpn;
+ queue.alpns = {alpn};
connections_with_chlo_[connection_id] = false; // Dummy value.
// Set the version of buffered packets of this connection on CHLO.
queue.version = version;
diff --git a/quic/core/quic_buffered_packet_store.h b/quic/core/quic_buffered_packet_store.h
index 52d957e..3d9290e 100644
--- a/quic/core/quic_buffered_packet_store.h
+++ b/quic/core/quic_buffered_packet_store.h
@@ -66,8 +66,8 @@
std::list<BufferedPacket> buffered_packets;
QuicTime creation_time;
- // The alpn from the CHLO, if one was found.
- std::string alpn;
+ // The ALPNs from the CHLO, if found.
+ std::vector<std::string> alpns;
// Indicating whether this is an IETF QUIC connection.
bool ietf_quic;
// If buffered_packets contains the CHLO, it is the version of the CHLO.
diff --git a/quic/core/quic_buffered_packet_store_test.cc b/quic/core/quic_buffered_packet_store_test.cc
index dbf6c16..1b1544b 100644
--- a/quic/core/quic_buffered_packet_store_test.cc
+++ b/quic/core/quic_buffered_packet_store_test.cc
@@ -80,7 +80,7 @@
const std::list<BufferedPacket>& queue = packets.buffered_packets;
ASSERT_EQ(1u, queue.size());
// The alpn should be ignored for non-chlo packets.
- ASSERT_EQ("", packets.alpn);
+ ASSERT_TRUE(packets.alpns.empty());
// There is no valid version because CHLO has not arrived.
EXPECT_EQ(invalid_version_, packets.version);
// Check content of the only packet in the queue.
@@ -415,7 +415,8 @@
EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2));
auto packets = store_.DeliverPackets(connection_id_2);
EXPECT_EQ(1u, packets.buffered_packets.size());
- EXPECT_EQ("h3", packets.alpn);
+ ASSERT_EQ(1u, packets.alpns.size());
+ EXPECT_EQ("h3", packets.alpns[0]);
// Since connection_id_2's chlo arrives, verify version is set.
EXPECT_EQ(valid_version_, packets.version);
EXPECT_TRUE(store_.HasChlosBuffered());
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index c3261d8..36932c3 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -180,7 +180,7 @@
QuicTimeWaitListManager* time_wait_list_manager_;
};
-// Class which extracts the ALPN from a CHLO packet.
+// Class which extracts the ALPN from a QUIC_CRYPTO CHLO packet.
class ChloAlpnExtractor : public ChloExtractor::Delegate {
public:
void OnChlo(QuicTransportVersion /*version*/,
@@ -522,6 +522,23 @@
}
}
+std::string QuicDispatcher::SelectAlpn(const std::vector<std::string>& alpns) {
+ if (alpns.empty()) {
+ return "";
+ }
+ if (alpns.size() > 1u) {
+ const std::vector<std::string>& supported_alpns =
+ version_manager_->GetSupportedAlpns();
+ for (const std::string& alpn : alpns) {
+ if (std::find(supported_alpns.begin(), supported_alpns.end(), alpn) !=
+ supported_alpns.end()) {
+ return alpn;
+ }
+ }
+ }
+ return alpns[0];
+}
+
QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
const ReceivedPacketInfo& packet_info) {
if (!packet_info.version_flag) {
@@ -831,9 +848,10 @@
QuicConnectionId original_connection_id = server_connection_id;
server_connection_id = MaybeReplaceServerConnectionId(server_connection_id,
packet_list.version);
+ std::string alpn = SelectAlpn(packet_list.alpns);
std::unique_ptr<QuicSession> session =
CreateQuicSession(server_connection_id, packets.front().peer_address,
- packet_list.alpn, packet_list.version);
+ alpn, packet_list.version);
if (original_connection_id != server_connection_id) {
session->connection()->AddIncomingConnectionId(original_connection_id);
session->connection()->InstallInitialCrypters(original_connection_id);
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index 1c1229a..849a8c9 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -300,6 +300,12 @@
// Called if a packet from an unseen connection is reset or rejected.
virtual void OnNewConnectionRejected() {}
+ // Selects the preferred ALPN from a vector of ALPNs.
+ // This runs through the list of ALPNs provided by the client and picks the
+ // first one it supports. If no supported versions are found, the first
+ // element of the vector is returned.
+ std::string SelectAlpn(const std::vector<std::string>& alpns);
+
private:
friend class test::QuicDispatcherPeer;
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index cc98335..fe5adb0 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -1412,6 +1412,17 @@
ProcessFirstFlight(client_address, TestConnectionId(1));
}
+TEST_P(QuicDispatcherTestOneVersion, SelectAlpn) {
+ EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {}), "");
+ EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {""}), "");
+ EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {"hq"}), "hq");
+ // Q033 is no longer supported but Q050 is.
+ QuicEnableVersion(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
+ EXPECT_EQ(
+ QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {"h3-Q033", "h3-Q050"}),
+ "h3-Q050");
+}
+
// Verify the stopgap test: Packets with truncated connection IDs should be
// dropped.
class QuicDispatcherTestStrayPacketConnectionId
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index 105d23d..0a014be 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -50,6 +50,11 @@
return filtered_supported_versions_with_quic_crypto_;
}
+const std::vector<std::string>& QuicVersionManager::GetSupportedAlpns() {
+ MaybeRefilterSupportedVersions();
+ return filtered_supported_alpns_;
+}
+
void QuicVersionManager::MaybeRefilterSupportedVersions() {
static_assert(SupportedVersions().size() == 8u,
"Supported versions out of sync");
@@ -89,7 +94,8 @@
FilterSupportedVersions(allowed_supported_versions_);
filtered_supported_versions_with_quic_crypto_.clear();
filtered_transport_versions_.clear();
- for (ParsedQuicVersion version : filtered_supported_versions_) {
+ filtered_supported_alpns_.clear();
+ for (const ParsedQuicVersion& version : filtered_supported_versions_) {
auto transport_version = version.transport_version;
if (std::find(filtered_transport_versions_.begin(),
filtered_transport_versions_.end(),
@@ -99,7 +105,12 @@
if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
filtered_supported_versions_with_quic_crypto_.push_back(version);
}
+ filtered_supported_alpns_.emplace_back(AlpnForVersion(version));
}
}
+void QuicVersionManager::AddCustomAlpn(const std::string& alpn) {
+ filtered_supported_alpns_.push_back(alpn);
+}
+
} // namespace quic
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index 381cef4..c5111ed 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -29,6 +29,10 @@
// Returns currently supported versions using QUIC crypto.
const ParsedQuicVersionVector& GetSupportedVersionsWithQuicCrypto();
+ // Returns the list of supported ALPNs, based on the current supported
+ // versions and any custom additions by subclasses.
+ const std::vector<std::string>& GetSupportedAlpns();
+
protected:
// If the value of any reloadable flag is different from the cached value,
// re-filter |filtered_supported_versions_| and update the cached flag values.
@@ -42,6 +46,10 @@
return filtered_transport_versions_;
}
+ // Mechanism for subclasses to add custom ALPNs to the supported list.
+ // Should be called in constructor and RefilterSupportedVersions.
+ void AddCustomAlpn(const std::string& alpn);
+
private:
// Cached value of reloadable flags.
// quic_enable_version_draft_27 flag
@@ -72,6 +80,9 @@
// |filtered_supported_versions_|. No guarantees are made that the same
// transport version isn't repeated.
QuicTransportVersionVector filtered_transport_versions_;
+ // Contains the list of ALPNs corresponding to filtered_supported_versions_
+ // with custom ALPNs added.
+ std::vector<std::string> filtered_supported_alpns_;
};
} // namespace quic
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index 9ecad57..3a8e98f 100644
--- a/quic/core/quic_version_manager_test.cc
+++ b/quic/core/quic_version_manager_test.cc
@@ -9,6 +9,8 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+using ::testing::ElementsAre;
+
namespace quic {
namespace test {
namespace {
@@ -48,6 +50,9 @@
manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(
+ manager.GetSupportedAlpns(),
+ ElementsAre("h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043"));
SetQuicReloadableFlag(quic_enable_version_draft_27, true);
expected_parsed_versions.insert(
@@ -60,6 +65,9 @@
manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-27", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046",
+ "h3-Q043"));
SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
expected_parsed_versions.insert(
@@ -70,6 +78,9 @@
manager.GetSupportedVersionsWithQuicCrypto().size());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-27", "h3-25", "h3-Q050", "h3-Q049", "h3-Q048",
+ "h3-Q046", "h3-Q043"));
SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
expected_parsed_versions.insert(
@@ -82,6 +93,9 @@
manager.GetSupportedVersions());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-27", "h3-25", "h3-T050", "h3-Q050", "h3-Q049",
+ "h3-Q048", "h3-Q046", "h3-Q043"));
}
} // namespace