Upon receiving SETTINGS for a QuicSpdyClientSession, serialize the frame and cache it in tls_client_handshaker.

gfe-relnote: unused code. not protected.
PiperOrigin-RevId: 306897017
Change-Id: I94fbf706b7c9846befb80b1363a79dc022e95828
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h
index 3ae19dd..b4675de 100644
--- a/quic/core/crypto/quic_crypto_client_config.h
+++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -71,7 +71,7 @@
   virtual void Insert(const QuicServerId& server_id,
                       bssl::UniquePtr<SSL_SESSION> session,
                       TransportParameters* params,
-                      std::vector<uint8_t>* application_states) = 0;
+                      ApplicationState* application_states) = 0;
 
   // Lookup is called once at the beginning of each TLS handshake to potentially
   // provide the saved state both for the TLS handshake and for sending 0-RTT
diff --git a/quic/core/http/quic_spdy_client_session_base.cc b/quic/core/http/quic_spdy_client_session_base.cc
index a0c70dd..2655259 100644
--- a/quic/core/http/quic_spdy_client_session_base.cc
+++ b/quic/core/http/quic_spdy_client_session_base.cc
@@ -222,4 +222,15 @@
   return !HasActiveRequestStreams() && promised_by_id_.empty();
 }
 
+void QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) {
+  QuicSpdySession::OnSettingsFrame(frame);
+  std::unique_ptr<char[]> buffer;
+  QuicByteCount frame_length =
+      HttpEncoder::SerializeSettingsFrame(frame, &buffer);
+  auto serialized_data = std::make_unique<ApplicationState>(
+      buffer.get(), buffer.get() + frame_length);
+  static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream())
+      ->OnApplicationState(std::move(serialized_data));
+}
+
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_client_session_base.h b/quic/core/http/quic_spdy_client_session_base.h
index 7d4ba01..9d702e3 100644
--- a/quic/core/http/quic_spdy_client_session_base.h
+++ b/quic/core/http/quic_spdy_client_session_base.h
@@ -117,6 +117,9 @@
     return push_promise_index_;
   }
 
+  // Override to serialize the settings and pass it down to the handshaker.
+  void OnSettingsFrame(const SettingsFrame& frame) override;
+
  private:
   // For QuicSpdyClientStream to detect that a response corresponds to a
   // promise.
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index f702671..65dd43a 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -11,9 +11,12 @@
 
 #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
 #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/http/http_frames.h"
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
 #include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -27,6 +30,7 @@
 #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -81,11 +85,14 @@
 class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
  protected:
   QuicSpdyClientSessionTest()
-      : crypto_config_(crypto_test_utils::ProofVerifierForTesting()),
-        promised_stream_id_(
+      : promised_stream_id_(
             QuicUtils::GetInvalidStreamId(GetParam().transport_version)),
         associated_stream_id_(
             QuicUtils::GetInvalidStreamId(GetParam().transport_version)) {
+    auto client_cache = std::make_unique<test::SimpleSessionCache>();
+    client_session_cache_ = client_cache.get();
+    crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
+        crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache));
     Initialize();
     // Advance the time, because timers do not like uninitialized times.
     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -103,7 +110,7 @@
                                              SupportedVersions(GetParam()));
     session_ = std::make_unique<TestQuicSpdyClientSession>(
         DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
-        QuicServerId(kServerHostname, kPort, false), &crypto_config_,
+        QuicServerId(kServerHostname, kPort, false), crypto_config_.get(),
         &push_promise_index_);
     session_->Initialize();
     push_promise_[":path"] = "/bar";
@@ -171,7 +178,7 @@
         stream, AlpnForVersion(connection_->version()));
   }
 
-  QuicCryptoClientConfig crypto_config_;
+  std::unique_ptr<QuicCryptoClientConfig> crypto_config_;
   MockQuicConnectionHelper helper_;
   MockAlarmFactory alarm_factory_;
   PacketSavingConnection* connection_;
@@ -181,6 +188,7 @@
   std::string promise_url_;
   QuicStreamId promised_stream_id_;
   QuicStreamId associated_stream_id_;
+  test::SimpleSessionCache* client_session_cache_;
 };
 
 INSTANTIATE_TEST_SUITE_P(Tests,
@@ -940,6 +948,43 @@
   }
 }
 
+// Test that upon receiving HTTP/3 SETTINGS, the settings are serialized and
+// stored into client session cache.
+TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) {
+  // This feature is HTTP/3 only
+  if (!VersionUsesHttp3(session_->transport_version())) {
+    return;
+  }
+  CompleteCryptoHandshake();
+  SettingsFrame settings;
+  settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
+  settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+  settings.values[256] = 4;   // unknown setting
+  char application_state[] = {// type (SETTINGS)
+                              0x04,
+                              // length
+                              0x07,
+                              // identifier (SETTINGS_QPACK_MAX_TABLE_CAPACITY)
+                              0x01,
+                              // content
+                              0x02,
+                              // identifier (SETTINGS_MAX_HEADER_LIST_SIZE)
+                              0x06,
+                              // content
+                              0x05,
+                              // identifier (256 in variable length integer)
+                              0x40 + 0x01, 0x00,
+                              // content
+                              0x04};
+  ApplicationState expected(std::begin(application_state),
+                            std::end(application_state));
+  session_->OnSettingsFrame(settings);
+  EXPECT_EQ(expected,
+            *client_session_cache_
+                 ->Lookup(QuicServerId(kServerHostname, kPort, false), nullptr)
+                 ->application_state);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index f6dd0a7..2ab8637 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -873,6 +873,7 @@
 }
 
 void QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) {
+  DCHECK(VersionUsesHttp3(transport_version()));
   if (debug_visitor_ != nullptr) {
     debug_visitor_->OnSettingsFrameReceived(frame);
   }
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 29eca32..d641d51 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -247,7 +247,7 @@
   bool server_push_enabled() const;
 
   // Called when the control stream receives HTTP/3 SETTINGS.
-  void OnSettingsFrame(const SettingsFrame& frame);
+  virtual void OnSettingsFrame(const SettingsFrame& frame);
 
   // Called when a setting is parsed from an incoming SETTINGS frame.
   void OnSetting(uint64_t id, uint64_t value);
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index baac324..9e9e214 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -520,6 +520,11 @@
 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,
+                           received_application_state_.get());
+  }
 }
 
 }  // namespace quic
diff --git a/quic/test_tools/simple_session_cache.cc b/quic/test_tools/simple_session_cache.cc
index 32f8436..bbb5f28 100644
--- a/quic/test_tools/simple_session_cache.cc
+++ b/quic/test_tools/simple_session_cache.cc
@@ -11,11 +11,22 @@
 
 void SimpleSessionCache::Insert(const QuicServerId& server_id,
                                 bssl::UniquePtr<SSL_SESSION> session,
-                                TransportParameters* /*params*/,
-                                std::vector<uint8_t>* /*application_states*/) {
-  auto state = std::make_unique<QuicResumptionState>();
-  state->tls_session = std::move(session);
-  cache_entries_.insert(std::make_pair(server_id, std::move(state)));
+                                TransportParameters* params,
+                                ApplicationState* application_state) {
+  auto it = cache_entries_.find(server_id);
+  if (it == cache_entries_.end()) {
+    it = cache_entries_.insert(std::make_pair(server_id, Entry())).first;
+  }
+  if (session != nullptr) {
+    it->second.session = std::move(session);
+  }
+  if (application_state != nullptr) {
+    it->second.application_state =
+        std::make_unique<ApplicationState>(*application_state);
+  }
+  if (params != nullptr) {
+    it->second.params = std::make_unique<TransportParameters>(*params);
+  }
 }
 
 std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup(
@@ -25,8 +36,10 @@
   if (it == cache_entries_.end()) {
     return nullptr;
   }
-  std::unique_ptr<QuicResumptionState> state = std::move(it->second);
-  cache_entries_.erase(it);
+  auto state = std::make_unique<QuicResumptionState>();
+  state->tls_session = std::move(it->second.session);
+  state->application_state = it->second.application_state.get();
+  state->transport_params = it->second.params.get();
   return state;
 }
 
diff --git a/quic/test_tools/simple_session_cache.h b/quic/test_tools/simple_session_cache.h
index 62dbd6f..0bb23e0 100644
--- a/quic/test_tools/simple_session_cache.h
+++ b/quic/test_tools/simple_session_cache.h
@@ -5,7 +5,9 @@
 #ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_
 #define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_
 
+#include <memory>
 #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
 
 namespace quic {
 namespace test {
@@ -23,12 +25,17 @@
   void Insert(const QuicServerId& server_id,
               bssl::UniquePtr<SSL_SESSION> session,
               TransportParameters* params,
-              std::vector<uint8_t>* application_states) override;
+              ApplicationState* application_state) override;
   std::unique_ptr<QuicResumptionState> Lookup(const QuicServerId& server_id,
                                               const SSL_CTX* ctx) override;
 
  private:
-  std::map<QuicServerId, std::unique_ptr<QuicResumptionState>> cache_entries_;
+  struct Entry {
+    bssl::UniquePtr<SSL_SESSION> session;
+    std::unique_ptr<TransportParameters> params;
+    std::unique_ptr<ApplicationState> application_state;
+  };
+  std::map<QuicServerId, Entry> cache_entries_;
 };
 
 }  // namespace test