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
diff --git a/quic/test_tools/quic_dispatcher_peer.cc b/quic/test_tools/quic_dispatcher_peer.cc index b460165..467c689 100644 --- a/quic/test_tools/quic_dispatcher_peer.cc +++ b/quic/test_tools/quic_dispatcher_peer.cc
@@ -112,5 +112,12 @@ dispatcher->RestorePerPacketContext(std::move(context)); } +// static +std::string QuicDispatcherPeer::SelectAlpn( + QuicDispatcher* dispatcher, + const std::vector<std::string>& alpns) { + return dispatcher->SelectAlpn(alpns); +} + } // namespace test } // namespace quic
diff --git a/quic/test_tools/quic_dispatcher_peer.h b/quic/test_tools/quic_dispatcher_peer.h index 7cb4c92..ec22f94 100644 --- a/quic/test_tools/quic_dispatcher_peer.h +++ b/quic/test_tools/quic_dispatcher_peer.h
@@ -66,6 +66,9 @@ static void RestorePerPacketContext(QuicDispatcher* dispatcher, std::unique_ptr<QuicPerPacketContext>); + + static std::string SelectAlpn(QuicDispatcher* dispatcher, + const std::vector<std::string>& alpns); }; } // namespace test