In TlsClientHandshaker, only insert data into cache if all required states are present.

ApplicationState is now  optional to TlsClientHandshaker because not all applications have it.

gfe-relnote: unused code. not protected.
PiperOrigin-RevId: 307719344
Change-Id: Ib4e359c6a13c9b7b805dca7a1cfd3b1bf89af6ef
diff --git a/quic/core/http/quic_spdy_client_session.cc b/quic/core/http/quic_spdy_client_session.cc
index 07b9c7a..65751b9 100644
--- a/quic/core/http/quic_spdy_client_session.cc
+++ b/quic/core/http/quic_spdy_client_session.cc
@@ -191,7 +191,7 @@
   return std::make_unique<QuicCryptoClientStream>(
       server_id_, this,
       crypto_config_->proof_verifier()->CreateDefaultContext(), crypto_config_,
-      this);
+      this, /*has_application_state = */ true);
 }
 
 bool QuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) {
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index dc72a73..eea081c 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -173,6 +173,9 @@
     }
     std::unique_ptr<QuicCryptoServerConfig> crypto_config =
         crypto_test_utils::CryptoServerConfigForTesting();
+    if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3) {
+      SSL_CTX_clear_options(crypto_config->ssl_ctx(), SSL_OP_NO_TICKET);
+    }
     crypto_test_utils::HandshakeWithFakeServer(
         &config, crypto_config.get(), &helper_, &alarm_factory_, connection_,
         stream, AlpnForVersion(connection_->version()));
diff --git a/quic/core/quic_crypto_client_handshaker_test.cc b/quic/core/quic_crypto_client_handshaker_test.cc
index 92de76f..7e941c2 100644
--- a/quic/core/quic_crypto_client_handshaker_test.cc
+++ b/quic/core/quic_crypto_client_handshaker_test.cc
@@ -136,11 +136,13 @@
                                                  {version_})),
         session_(connection_, false),
         crypto_client_config_(std::make_unique<InsecureProofVerifier>()),
-        client_stream_(new QuicCryptoClientStream(server_id_,
-                                                  &session_,
-                                                  nullptr,
-                                                  &crypto_client_config_,
-                                                  &proof_handler_)),
+        client_stream_(
+            new QuicCryptoClientStream(server_id_,
+                                       &session_,
+                                       nullptr,
+                                       &crypto_client_config_,
+                                       &proof_handler_,
+                                       /*has_application_state = */ false)),
         handshaker_(server_id_,
                     client_stream_,
                     &session_,
diff --git a/quic/core/quic_crypto_client_stream.cc b/quic/core/quic_crypto_client_stream.cc
index 538d828..6f2ffcf 100644
--- a/quic/core/quic_crypto_client_stream.cc
+++ b/quic/core/quic_crypto_client_stream.cc
@@ -32,7 +32,8 @@
     QuicSession* session,
     std::unique_ptr<ProofVerifyContext> verify_context,
     QuicCryptoClientConfig* crypto_config,
-    ProofHandler* proof_handler)
+    ProofHandler* proof_handler,
+    bool has_application_state)
     : QuicCryptoClientStreamBase(session) {
   DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective());
   switch (session->connection()->version().handshake_protocol) {
@@ -44,7 +45,7 @@
     case PROTOCOL_TLS1_3:
       handshaker_ = std::make_unique<TlsClientHandshaker>(
           server_id, this, session, std::move(verify_context), crypto_config,
-          proof_handler);
+          proof_handler, has_application_state);
       break;
     case PROTOCOL_UNSUPPORTED:
       QUIC_BUG << "Attempting to create QuicCryptoClientStream for unknown "
diff --git a/quic/core/quic_crypto_client_stream.h b/quic/core/quic_crypto_client_stream.h
index 5ec1b01..d095deb 100644
--- a/quic/core/quic_crypto_client_stream.h
+++ b/quic/core/quic_crypto_client_stream.h
@@ -187,7 +187,8 @@
                          QuicSession* session,
                          std::unique_ptr<ProofVerifyContext> verify_context,
                          QuicCryptoClientConfig* crypto_config,
-                         ProofHandler* proof_handler);
+                         ProofHandler* proof_handler,
+                         bool has_application_state);
   QuicCryptoClientStream(const QuicCryptoClientStream&) = delete;
   QuicCryptoClientStream& operator=(const QuicCryptoClientStream&) = delete;
 
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index 4b6c2af..f16fdd5 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -52,7 +52,8 @@
     QuicSession* session,
     std::unique_ptr<ProofVerifyContext> verify_context,
     QuicCryptoClientConfig* crypto_config,
-    QuicCryptoClientStream::ProofHandler* proof_handler)
+    QuicCryptoClientStream::ProofHandler* proof_handler,
+    bool has_application_state)
     : TlsHandshaker(stream, session),
       session_(session),
       server_id_(server_id),
@@ -63,6 +64,7 @@
       user_agent_id_(crypto_config->user_agent_id()),
       pre_shared_key_(crypto_config->pre_shared_key()),
       crypto_negotiated_params_(new QuicCryptoNegotiatedParameters),
+      has_application_state_(has_application_state),
       tls_connection_(crypto_config->ssl_ctx(), this) {}
 
 TlsClientHandshaker::~TlsClientHandshaker() {
@@ -501,11 +503,25 @@
 }
 
 void TlsClientHandshaker::InsertSession(bssl::UniquePtr<SSL_SESSION> session) {
+  if (!received_transport_params_) {
+    QUIC_BUG << "Transport parameters isn't received";
+    return;
+  }
   if (session_cache_ == nullptr) {
     QUIC_DVLOG(1) << "No session cache, not inserting a session";
     return;
   }
-  session_cache_->Insert(server_id_, std::move(session), nullptr, nullptr);
+  if (has_application_state_ && !received_application_state_) {
+    // Application state is not received yet. cache the sessions.
+    if (cached_tls_sessions_[0] != nullptr) {
+      cached_tls_sessions_[1] = std::move(cached_tls_sessions_[0]);
+    }
+    cached_tls_sessions_[0] = std::move(session);
+    return;
+  }
+  session_cache_->Insert(server_id_, std::move(session),
+                         received_transport_params_.get(),
+                         received_application_state_.get());
 }
 
 void TlsClientHandshaker::WriteMessage(EncryptionLevel level,
@@ -522,9 +538,17 @@
 void TlsClientHandshaker::OnApplicationState(
     std::unique_ptr<ApplicationState> application_state) {
   received_application_state_ = std::move(application_state);
-  if (session_cache_ != nullptr) {
-    // TODO(renjietang): cache the TLS session ticket and insert them together.
-    session_cache_->Insert(server_id_, nullptr, nullptr,
+  // At least one tls session is cached before application state is received. So
+  // insert now.
+  if (session_cache_ != nullptr && cached_tls_sessions_[0] != nullptr) {
+    if (cached_tls_sessions_[1] != nullptr) {
+      // Insert the older session first.
+      session_cache_->Insert(server_id_, std::move(cached_tls_sessions_[1]),
+                             received_transport_params_.get(),
+                             received_application_state_.get());
+    }
+    session_cache_->Insert(server_id_, std::move(cached_tls_sessions_[0]),
+                           received_transport_params_.get(),
                            received_application_state_.get());
   }
 }
diff --git a/quic/core/tls_client_handshaker.h b/quic/core/tls_client_handshaker.h
index 0128c8b..7acec4f 100644
--- a/quic/core/tls_client_handshaker.h
+++ b/quic/core/tls_client_handshaker.h
@@ -34,7 +34,8 @@
                       QuicSession* session,
                       std::unique_ptr<ProofVerifyContext> verify_context,
                       QuicCryptoClientConfig* crypto_config,
-                      QuicCryptoClientStream::ProofHandler* proof_handler);
+                      QuicCryptoClientStream::ProofHandler* proof_handler,
+                      bool has_application_state);
   TlsClientHandshaker(const TlsClientHandshaker&) = delete;
   TlsClientHandshaker& operator=(const TlsClientHandshaker&) = delete;
 
@@ -165,8 +166,14 @@
 
   bool allow_empty_alpn_for_tests_ = false;
 
+  const bool has_application_state_;
+
   TlsClientConnection tls_connection_;
 
+  // If |has_application_state_|, stores the tls session tickets before
+  // application state is received. The latest one is put in the front.
+  bssl::UniquePtr<SSL_SESSION> cached_tls_sessions_[2] = {};
+
   std::unique_ptr<TransportParameters> received_transport_params_ = nullptr;
   std::unique_ptr<ApplicationState> received_application_state_ = nullptr;
 };
diff --git a/quic/core/tls_handshaker_test.cc b/quic/core/tls_handshaker_test.cc
index 6103743..f774e28 100644
--- a/quic/core/tls_handshaker_test.cc
+++ b/quic/core/tls_handshaker_test.cc
@@ -250,7 +250,8 @@
             session,
             crypto_test_utils::ProofVerifyContextForTesting(),
             &crypto_config_,
-            &proof_handler_)) {}
+            &proof_handler_,
+            /*has_application_state = */ false)) {}
 
   ~TestQuicCryptoClientStream() override = default;