Handle HTTP/3 SETTINGS on 0-RTT client connection.
In IETF QUIC, if 0-RTT is enabled, the client will receive 2 SETTINGS, one from cache and one from the fresh server sent SETTINGS.
If 0-RTT is accepted, the server shouldn't change dynamic table capacity according to https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#name-maximum-dynamic-table-capac. For other settings, https://www.google.com/url?sa=D&q=https%3A%2F%2Fquicwg.org%2Fbase-drafts%2Fdraft-ietf-quic-http.html%23name-initialization specifies they shouldn't be decreased.
When 0-RTT is rejected, our current approach is to retransmit 0-RTT packets. If the server changes SETTINGS, our implementation doesn't have an easy way to comply with the new SETTINGS, thus we close the connection too.
Protected by quic_enable_zero_rtt_for_tls
PiperOrigin-RevId: 316128955
Change-Id: I84b277b3c57d6a8009aec5a547c6416542122ec6
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index db7ec79..67adf12 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -378,9 +378,10 @@
return SecondPassEncode(std::move(instructions), required_insert_count);
}
-void QpackEncoder::SetMaximumDynamicTableCapacity(
+bool QpackEncoder::SetMaximumDynamicTableCapacity(
uint64_t maximum_dynamic_table_capacity) {
- header_table_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
+ return header_table_.SetMaximumDynamicTableCapacity(
+ maximum_dynamic_table_capacity);
}
void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) {
@@ -392,8 +393,12 @@
DCHECK(success);
}
-void QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) {
+bool QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) {
+ if (maximum_blocked_streams < maximum_blocked_streams_) {
+ return false;
+ }
maximum_blocked_streams_ = maximum_blocked_streams;
+ return true;
}
void QpackEncoder::OnInsertCountIncrement(uint64_t increment) {
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h
index 0f1d14c..8b75097 100644
--- a/quic/core/qpack/qpack_encoder.h
+++ b/quic/core/qpack/qpack_encoder.h
@@ -63,7 +63,10 @@
// measured in bytes. Called when SETTINGS_QPACK_MAX_TABLE_CAPACITY is
// received. Encoder needs to know this value so that it can calculate
// MaxEntries, used as a modulus to encode Required Insert Count.
- void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
+ // Returns true if |maximum_dynamic_table_capacity| is set for the first time
+ // or if it doesn't change current value. The setting is not changed when
+ // returning false.
+ bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
// Set dynamic table capacity to |dynamic_table_capacity|.
// |dynamic_table_capacity| must not exceed maximum dynamic table capacity.
@@ -72,7 +75,9 @@
// Set maximum number of blocked streams.
// Called when SETTINGS_QPACK_BLOCKED_STREAMS is received.
- void SetMaximumBlockedStreams(uint64_t maximum_blocked_streams);
+ // Returns true if |maximum_blocked_streams| doesn't decrease current value.
+ // The setting is not changed when returning false.
+ bool SetMaximumBlockedStreams(uint64_t maximum_blocked_streams);
// QpackDecoderStreamReceiver::Delegate implementation
void OnInsertCountIncrement(uint64_t increment) override;
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index 472db89..29e7148 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -186,16 +186,15 @@
return true;
}
-void QpackHeaderTable::SetMaximumDynamicTableCapacity(
+bool QpackHeaderTable::SetMaximumDynamicTableCapacity(
uint64_t maximum_dynamic_table_capacity) {
- // This method can only be called once: in the decoding context, shortly after
- // construction; in the encoding context, upon receiving the SETTINGS frame.
- DCHECK_EQ(0u, dynamic_table_capacity_);
- DCHECK_EQ(0u, maximum_dynamic_table_capacity_);
- DCHECK_EQ(0u, max_entries_);
-
- maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity;
- max_entries_ = maximum_dynamic_table_capacity / 32;
+ if (maximum_dynamic_table_capacity_ == 0) {
+ maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity;
+ max_entries_ = maximum_dynamic_table_capacity / 32;
+ return true;
+ }
+ // If the value is already set, it should not be changed.
+ return maximum_dynamic_table_capacity == maximum_dynamic_table_capacity_;
}
void QpackHeaderTable::RegisterObserver(uint64_t required_insert_count,
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index e3fb975..bed1cc8 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -97,7 +97,10 @@
// value can be set upon connection establishment, whereas in the encoding
// context it can be set when the SETTINGS frame is received.
// This method must only be called at most once.
- void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
+ // Returns true if |maximum_dynamic_table_capacity| is set for the first time
+ // or if it doesn't change current value. The setting is not changed when
+ // returning false.
+ bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
// Get |maximum_dynamic_table_capacity_|.
uint64_t maximum_dynamic_table_capacity() const {