Support 0-RTT TLS in QuicSpdySession
Protected by disabled flag quic_enable_zero_rtt_for_tls
PiperOrigin-RevId: 317031026
Change-Id: Ib65fbe5b34c63dd06c032c0a4171864ab988159e
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index e8c1643..9185bf5 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -204,6 +204,8 @@
SetQuicReloadableFlag(quic_fix_server_pto_timeout, true);
SetQuicReloadableFlag(quic_support_handshake_done_in_t050, true);
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
}
~EndToEndTest() override { QuicRecyclePort(server_address_.port()); }
@@ -1358,10 +1360,6 @@
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
client_->Disconnect();
- if (version_.UsesTls()) {
- // TODO(b/152551499): remove this when TLS supports 0-RTT.
- return;
- }
// The 0-RTT handshake should succeed.
client_->Connect();
@@ -1376,6 +1374,11 @@
client_->Disconnect();
// Restart the server so that the 0-RTT handshake will take 1 RTT.
+ if (version_.UsesTls()) {
+ // TODO(b/159168475): 0-RTT rejection in TLS currently doesn't work - stream
+ // data attempts to get retransmitted under ENCRYPTION_HANDSHAKE keys.
+ return;
+ }
StopServer();
server_writer_ = new PacketDroppingTestWriter();
StartServer();
diff --git a/quic/core/http/quic_send_control_stream.cc b/quic/core/http/quic_send_control_stream.cc
index 64c306a..59574a1 100644
--- a/quic/core/http/quic_send_control_stream.cc
+++ b/quic/core/http/quic_send_control_stream.cc
@@ -18,18 +18,12 @@
namespace quic {
-QuicSendControlStream::QuicSendControlStream(
- QuicStreamId id,
- QuicSpdySession* spdy_session,
- uint64_t qpack_maximum_dynamic_table_capacity,
- uint64_t qpack_maximum_blocked_streams,
- uint64_t max_inbound_header_list_size)
+QuicSendControlStream::QuicSendControlStream(QuicStreamId id,
+ QuicSpdySession* spdy_session,
+ const SettingsFrame& settings)
: QuicStream(id, spdy_session, /*is_static = */ true, WRITE_UNIDIRECTIONAL),
settings_sent_(false),
- qpack_maximum_dynamic_table_capacity_(
- qpack_maximum_dynamic_table_capacity),
- qpack_maximum_blocked_streams_(qpack_maximum_blocked_streams),
- max_inbound_header_list_size_(max_inbound_header_list_size),
+ settings_(settings),
spdy_session_(spdy_session) {}
void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
@@ -56,13 +50,7 @@
WriteOrBufferData(quiche::QuicheStringPiece(writer.data(), writer.length()),
false, nullptr);
- SettingsFrame settings;
- settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
- qpack_maximum_dynamic_table_capacity_;
- settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
- qpack_maximum_blocked_streams_;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
- max_inbound_header_list_size_;
+ SettingsFrame settings = settings_;
// https://tools.ietf.org/html/draft-ietf-quic-http-25#section-7.2.4.1
// specifies that setting identifiers of 0x1f * N + 0x21 are reserved and
// greasing should be attempted.
diff --git a/quic/core/http/quic_send_control_stream.h b/quic/core/http/quic_send_control_stream.h
index 03bd1f7..c14254f 100644
--- a/quic/core/http/quic_send_control_stream.h
+++ b/quic/core/http/quic_send_control_stream.h
@@ -23,9 +23,7 @@
// only be accessed through the session.
QuicSendControlStream(QuicStreamId id,
QuicSpdySession* session,
- uint64_t qpack_maximum_dynamic_table_capacity,
- uint64_t qpack_maximum_blocked_streams,
- uint64_t max_inbound_header_list_size);
+ const SettingsFrame& settings);
QuicSendControlStream(const QuicSendControlStream&) = delete;
QuicSendControlStream& operator=(const QuicSendControlStream&) = delete;
~QuicSendControlStream() override = default;
@@ -59,12 +57,8 @@
// Track if a settings frame is already sent.
bool settings_sent_;
- // SETTINGS_QPACK_MAX_TABLE_CAPACITY value to send.
- const uint64_t qpack_maximum_dynamic_table_capacity_;
- // SETTINGS_QPACK_BLOCKED_STREAMS value to send.
- const uint64_t qpack_maximum_blocked_streams_;
- // SETTINGS_MAX_HEADER_LIST_SIZE value to send.
- const uint64_t max_inbound_header_list_size_;
+ // SETTINGS values to send.
+ const SettingsFrame settings_;
QuicSpdySession* const spdy_session_;
};
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc
index 27db719..ef367d9 100644
--- a/quic/core/http/quic_server_session_base.cc
+++ b/quic/core/http/quic_server_session_base.cc
@@ -39,6 +39,9 @@
crypto_stream_ =
CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_);
QuicSpdySession::Initialize();
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)) {
+ SendSettingsToCryptoStream();
+ }
}
void QuicServerSessionBase::OnConfigNegotiated() {
@@ -260,4 +263,19 @@
bandwidth.ToBytesPerSecond(), std::numeric_limits<uint32_t>::max()));
}
+void QuicServerSessionBase::SendSettingsToCryptoStream() {
+ if (!version().UsesTls()) {
+ return;
+ }
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount buffer_size =
+ HttpEncoder::SerializeSettingsFrame(settings(), &buffer);
+
+ std::unique_ptr<ApplicationState> serialized_settings =
+ std::make_unique<ApplicationState>(buffer.get(),
+ buffer.get() + buffer_size);
+ GetMutableCryptoStream()->SetServerApplicationStateForResumption(
+ std::move(serialized_settings));
+}
+
} // namespace quic
diff --git a/quic/core/http/quic_server_session_base.h b/quic/core/http/quic_server_session_base.h
index bf7a5bb..b4a467f 100644
--- a/quic/core/http/quic_server_session_base.h
+++ b/quic/core/http/quic_server_session_base.h
@@ -99,6 +99,11 @@
friend class test::QuicServerSessionBasePeer;
friend class test::QuicSimpleServerSessionPeer;
+ // Informs the QuicCryptoStream of the SETTINGS that will be used on this
+ // connection, so that the server crypto stream knows whether to accept 0-RTT
+ // data.
+ void SendSettingsToCryptoStream();
+
const QuicCryptoServerConfig* crypto_config_;
// The cache which contains most recently compressed certs.
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index ddc9f74..e69a051 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -434,6 +434,7 @@
void QuicSpdySession::Initialize() {
QuicSession::Initialize();
+ FillSettingsFrame();
if (!VersionUsesHttp3(transport_version())) {
if (perspective() == Perspective::IS_SERVER) {
set_largest_peer_created_stream_id(
@@ -464,6 +465,15 @@
2 * max_inbound_header_list_size_);
}
+void QuicSpdySession::FillSettingsFrame() {
+ settings_.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
+ qpack_maximum_dynamic_table_capacity_;
+ settings_.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
+ qpack_maximum_blocked_streams_;
+ settings_.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
+ max_inbound_header_list_size_;
+}
+
void QuicSpdySession::OnDecoderStreamError(
quiche::QuicheStringPiece error_message) {
DCHECK(VersionUsesHttp3(transport_version()));
@@ -1204,9 +1214,7 @@
DCHECK(VersionUsesHttp3(transport_version()));
if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) {
auto send_control = std::make_unique<QuicSendControlStream>(
- GetNextOutgoingUnidirectionalStreamId(), this,
- qpack_maximum_dynamic_table_capacity_, qpack_maximum_blocked_streams_,
- max_inbound_header_list_size_);
+ GetNextOutgoingUnidirectionalStreamId(), this, settings_);
send_control_stream_ = send_control.get();
ActivateStream(std::move(send_control));
if (debug_visitor_) {
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index b948002..4d6ee63 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -447,6 +447,8 @@
return receive_control_stream_;
}
+ const SettingsFrame& settings() const { return settings_; }
+
// Initializes HTTP/3 unidirectional streams if not yet initialzed.
virtual void MaybeInitializeHttp3UnidirectionalStreams();
@@ -480,6 +482,8 @@
// Send a MAX_PUSH_ID frame. Used in IETF QUIC only.
void SendMaxPushId();
+ void FillSettingsFrame();
+
std::unique_ptr<QpackEncoder> qpack_encoder_;
std::unique_ptr<QpackDecoder> qpack_decoder_;
@@ -497,6 +501,8 @@
QpackSendStream* qpack_encoder_send_stream_;
QpackSendStream* qpack_decoder_send_stream_;
+ SettingsFrame settings_;
+
// Maximum dynamic table capacity as defined at
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#maximum-dynamic-table-capacity
// for the decoding context. Value will be sent via