Implement QUIC ALPN selection on the server side.

This also fixes the bugs in client side found by a full custom ALPN test, and removes a tautological check from server-side ALPN parser.

gfe-relnote: n/a (protected by disabled quic_tls flag)
PiperOrigin-RevId: 266319592
Change-Id: I9e06b383abe187286f31d3cbce8be99e9370c9f2
diff --git a/quic/core/tls_handshaker_test.cc b/quic/core/tls_handshaker_test.cc
index ef7f31b..a298089 100644
--- a/quic/core/tls_handshaker_test.cc
+++ b/quic/core/tls_handshaker_test.cc
@@ -23,6 +23,7 @@
 namespace {
 
 using ::testing::_;
+using ::testing::ElementsAreArray;
 using ::testing::Return;
 
 class FakeProofVerifier : public ProofVerifier {
@@ -305,9 +306,15 @@
     EXPECT_FALSE(client_stream_->handshake_confirmed());
     EXPECT_FALSE(server_stream_->encryption_established());
     EXPECT_FALSE(server_stream_->handshake_confirmed());
+    const std::string default_alpn =
+        AlpnForVersion(client_session_.connection()->version());
     ON_CALL(client_session_, GetAlpnsToOffer())
-        .WillByDefault(Return(std::vector<std::string>(
-            {AlpnForVersion(client_session_.connection()->version())})));
+        .WillByDefault(Return(std::vector<std::string>({default_alpn})));
+    ON_CALL(server_session_, SelectAlpn(_))
+        .WillByDefault(
+            [default_alpn](const std::vector<QuicStringPiece>& alpns) {
+              return std::find(alpns.begin(), alpns.end(), default_alpn);
+            });
   }
 
   MockQuicConnectionHelper conn_helper_;
@@ -499,6 +506,59 @@
   EXPECT_QUIC_BUG(client_stream_->CryptoConnect(), "Failed to set ALPN");
 }
 
+TEST_F(TlsHandshakerTest, ServerRequiresCustomALPN) {
+  static const std::string kTestAlpn = "An ALPN That Client Did Not Offer";
+  EXPECT_CALL(server_session_, SelectAlpn(_))
+      .WillOnce([](const std::vector<QuicStringPiece>& alpns) {
+        return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
+      });
+  EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
+                                             "Server did not select ALPN", _));
+  EXPECT_CALL(*server_conn_,
+              CloseConnection(QUIC_HANDSHAKE_FAILED,
+                              "Server did not receive a known ALPN", _));
+  client_stream_->CryptoConnect();
+  ExchangeHandshakeMessages(client_stream_, server_stream_);
+
+  EXPECT_FALSE(client_stream_->handshake_confirmed());
+  EXPECT_FALSE(client_stream_->encryption_established());
+  EXPECT_FALSE(server_stream_->handshake_confirmed());
+  EXPECT_FALSE(server_stream_->encryption_established());
+}
+
+TEST_F(TlsHandshakerTest, CustomALPNNegotiation) {
+  EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
+  EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
+  EXPECT_CALL(client_session_,
+              OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED));
+  EXPECT_CALL(client_session_,
+              OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED));
+  EXPECT_CALL(server_session_,
+              OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED));
+
+  static const std::string kTestAlpn = "A Custom ALPN Value";
+  static const std::vector<std::string> kTestAlpns(
+      {"foo", "bar", kTestAlpn, "something else"});
+  EXPECT_CALL(client_session_, GetAlpnsToOffer())
+      .WillRepeatedly(Return(kTestAlpns));
+  EXPECT_CALL(server_session_, SelectAlpn(_))
+      .WillOnce([](const std::vector<QuicStringPiece>& alpns) {
+        EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns));
+        return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
+      });
+  EXPECT_CALL(client_session_, OnAlpnSelected(QuicStringPiece(kTestAlpn)));
+  EXPECT_CALL(server_session_, OnAlpnSelected(QuicStringPiece(kTestAlpn)));
+  client_stream_->CryptoConnect();
+  ExchangeHandshakeMessages(client_stream_, server_stream_);
+
+  EXPECT_TRUE(client_stream_->handshake_confirmed());
+  EXPECT_TRUE(client_stream_->encryption_established());
+  EXPECT_TRUE(server_stream_->handshake_confirmed());
+  EXPECT_TRUE(server_stream_->encryption_established());
+  EXPECT_TRUE(client_conn_->IsHandshakeConfirmed());
+  EXPECT_FALSE(server_conn_->IsHandshakeConfirmed());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic