summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-09-03 13:32:17 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-01 14:31:55 +0200
commit21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (patch)
tree91be119f694044dfc1ff9fdc054459e925de9df0 /chromium/net/third_party/quiche/src/quic/core
parent03c549e0392f92c02536d3f86d5e1d8dfa3435ac (diff)
downloadqtwebengine-chromium-21ba0c5d4bf8fba15dddd97cd693bad2358b77fd.tar.gz
BASELINE: Update Chromium to 92.0.4515.166
Change-Id: I42a050486714e9e54fc271f2a8939223a02ae364
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core')
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc177
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc55
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc1036
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc100
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc336
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_frames.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc85
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc33
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc73
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc295
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h355
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc598
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc229
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h99
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc207
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h757
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc796
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.cc933
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.h177
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc47
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc911
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc390
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h178
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc349
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h51
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc163
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.cc69
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_tag.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc328
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h47
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc72
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc15
147 files changed, 5548 insertions, 4278 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc
index 8b4a27f0866..173c8d30488 100644
--- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc
@@ -23,8 +23,20 @@ WriteResult QuicBatchWriterBase::WritePacket(
PerPacketOptions* options) {
const WriteResult result =
InternalWritePacket(buffer, buf_len, self_address, peer_address, options);
- if (result.status == WRITE_STATUS_BLOCKED) {
- write_blocked_ = true;
+
+ if (GetQuicReloadableFlag(quic_batch_writer_fix_write_blocked)) {
+ if (IsWriteBlockedStatus(result.status)) {
+ if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
+ QUIC_CODE_COUNT(quic_batch_writer_fix_write_blocked_data_buffered);
+ } else {
+ QUIC_CODE_COUNT(quic_batch_writer_fix_write_blocked_data_not_buffered);
+ }
+ write_blocked_ = true;
+ }
+ } else {
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ write_blocked_ = true;
+ }
}
return result;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h
index ff924d0481c..e7d1f129684 100644
--- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h
@@ -60,7 +60,7 @@ class QUIC_EXPORT_PRIVATE QuicBatchWriterBase : public QuicPacketWriter {
const QuicBatchWriterBuffer& batch_buffer() const { return *batch_buffer_; }
QuicBatchWriterBuffer& batch_buffer() { return *batch_buffer_; }
- const QuicCircularDeque<BufferedWrite>& buffered_writes() const {
+ const quiche::QuicheCircularDeque<BufferedWrite>& buffered_writes() const {
return batch_buffer_->buffered_writes();
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h
index 007c2834cc5..4faa3cba4e7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h
@@ -6,11 +6,11 @@
#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
#include "absl/base/optimization.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_linux_socket_utils.h"
#include "quic/core/quic_packet_writer.h"
#include "quic/platform/api/quic_ip_address.h"
#include "quic/platform/api/quic_socket_address.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -61,7 +61,7 @@ class QUIC_EXPORT_PRIVATE QuicBatchWriterBuffer {
};
PopResult PopBufferedWrite(int32_t num_buffered_writes);
- const QuicCircularDeque<BufferedWrite>& buffered_writes() const {
+ const quiche::QuicheCircularDeque<BufferedWrite>& buffered_writes() const {
return buffered_writes_;
}
@@ -87,7 +87,7 @@ class QUIC_EXPORT_PRIVATE QuicBatchWriterBuffer {
bool Invariants() const;
const char* buffer_end() const { return buffer_ + sizeof(buffer_); }
ABSL_CACHELINE_ALIGNED char buffer_[kBufferSize];
- QuicCircularDeque<BufferedWrite> buffered_writes_;
+ quiche::QuicheCircularDeque<BufferedWrite> buffered_writes_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc
index ec08164e529..8a1b93fc723 100644
--- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc
@@ -322,6 +322,11 @@ TEST_F(QuicGsoBatchWriterTest, WriteBlockDataBuffered) {
}));
ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED_DATA_BUFFERED, EWOULDBLOCK),
WritePacket(&writer, 50));
+ if (GetQuicReloadableFlag(quic_batch_writer_fix_write_blocked)) {
+ EXPECT_TRUE(writer.IsWriteBlocked());
+ } else {
+ EXPECT_FALSE(writer.IsWriteBlocked());
+ }
ASSERT_EQ(250u, writer.batch_buffer().SizeInUse());
ASSERT_EQ(3u, writer.buffered_writes().size());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
index 48fe9a82c05..29a43a605e0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
@@ -17,7 +17,6 @@
#include "quic/core/quic_framer.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
index 7a34097fd54..6738f49ab05 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
@@ -9,13 +9,13 @@
#include "quic/core/congestion_control/windowed_filter.h"
#include "quic/core/packet_number_indexed_queue.h"
#include "quic/core/quic_bandwidth.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_time.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_unacked_packet_map.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_flags.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -540,7 +540,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_;
RecentAckPoints recent_ack_points_;
- QuicCircularDeque<AckPoint> a0_candidates_;
+ quiche::QuicheCircularDeque<AckPoint> a0_candidates_;
// Maximum number of tracked packets.
const QuicPacketCount max_tracked_packets_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
index d24e50efdbc..8d4a49350b5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
@@ -116,9 +116,9 @@ void Bbr2NetworkModel::OnCongestionEventStart(
<< total_bytes_acked() - prior_bytes_acked << " bytes from "
<< acked_packets.size()
<< " packets have been acked, but sample_max_bandwidth is zero.";
+ congestion_event->sample_max_bandwidth = sample.sample_max_bandwidth;
if (!sample.sample_is_app_limited ||
sample.sample_max_bandwidth > MaxBandwidth()) {
- congestion_event->sample_max_bandwidth = sample.sample_max_bandwidth;
max_bandwidth_filter_.Update(congestion_event->sample_max_bandwidth);
}
}
@@ -188,99 +188,112 @@ void Bbr2NetworkModel::OnCongestionEventStart(
void Bbr2NetworkModel::AdaptLowerBounds(
const Bbr2CongestionEvent& congestion_event) {
- if (Params().bw_lo_mode_ != Bbr2Params::DEFAULT) {
- if (congestion_event.bytes_lost == 0) {
+ if (Params().bw_lo_mode_ == Bbr2Params::DEFAULT) {
+ if (!congestion_event.end_of_round_trip ||
+ congestion_event.is_probing_for_bandwidth) {
return;
}
- // Ignore losses from packets sent when probing for more bandwidth in
- // STARTUP or PROBE_UP when they're lost in DRAIN or PROBE_DOWN.
- if (pacing_gain_ < 1) {
- return;
- }
- // Decrease bandwidth_lo whenever there is loss.
- // Set bandwidth_lo_ if it is not yet set.
- if (bandwidth_lo_.IsInfinite()) {
- bandwidth_lo_ = MaxBandwidth();
- }
- // Save bandwidth_lo_ if it hasn't already been saved.
- if (prior_bandwidth_lo_.IsZero()) {
- prior_bandwidth_lo_ = bandwidth_lo_;
- }
- switch (Params().bw_lo_mode_) {
- case Bbr2Params::MIN_RTT_REDUCTION:
- bandwidth_lo_ =
- bandwidth_lo_ - QuicBandwidth::FromBytesAndTimeDelta(
- congestion_event.bytes_lost, MinRtt());
- break;
- case Bbr2Params::INFLIGHT_REDUCTION: {
- // Use a max of BDP and inflight to avoid starving app-limited flows.
- const QuicByteCount effective_inflight =
- std::max(BDP(), congestion_event.prior_bytes_in_flight);
- // This could use bytes_lost_in_round if the bandwidth_lo_ was saved
- // when entering 'recovery', but this BBRv2 implementation doesn't have
- // recovery defined.
- bandwidth_lo_ = bandwidth_lo_ *
- ((effective_inflight - congestion_event.bytes_lost) /
- static_cast<double>(effective_inflight));
- break;
+
+ if (bytes_lost_in_round_ > 0) {
+ if (bandwidth_lo_.IsInfinite()) {
+ bandwidth_lo_ = MaxBandwidth();
}
- case Bbr2Params::CWND_REDUCTION:
- bandwidth_lo_ =
- bandwidth_lo_ *
- ((congestion_event.prior_cwnd - congestion_event.bytes_lost) /
- static_cast<double>(congestion_event.prior_cwnd));
- break;
- case Bbr2Params::DEFAULT:
- QUIC_BUG(quic_bug_10466_1) << "Unreachable case DEFAULT.";
- }
- if (pacing_gain_ > Params().startup_full_bw_threshold) {
- // In STARTUP, pacing_gain_ is applied to bandwidth_lo_ in
- // UpdatePacingRate, so this backs that multiplication out to allow the
- // pacing rate to decrease, but not below
- // bandwidth_latest_ * startup_full_bw_threshold.
- bandwidth_lo_ =
- std::max(bandwidth_lo_,
- bandwidth_latest_ *
- (Params().startup_full_bw_threshold / pacing_gain_));
- } else {
- // Ensure bandwidth_lo isn't lower than bandwidth_latest_.
- bandwidth_lo_ = std::max(bandwidth_lo_, bandwidth_latest_);
- }
- // If it's the end of the round, ensure bandwidth_lo doesn't decrease more
- // than beta.
- if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode) &&
- congestion_event.end_of_round_trip) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode, 2, 2);
bandwidth_lo_ =
- std::max(bandwidth_lo_, prior_bandwidth_lo_ * (1.0 - Params().beta));
- prior_bandwidth_lo_ = QuicBandwidth::Zero();
+ std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta));
+ QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_
+ << ", bandwidth_latest_ is " << bandwidth_latest_;
+
+ if (Params().ignore_inflight_lo) {
+ return;
+ }
+ if (inflight_lo_ == inflight_lo_default()) {
+ inflight_lo_ = congestion_event.prior_cwnd;
+ }
+ inflight_lo_ = std::max<QuicByteCount>(
+ inflight_latest_, inflight_lo_ * (1.0 - Params().beta));
}
- // This early return ignores inflight_lo as well.
return;
}
- if (!congestion_event.end_of_round_trip ||
- congestion_event.is_probing_for_bandwidth) {
+
+ // Params().bw_lo_mode_ != Bbr2Params::DEFAULT
+ if (congestion_event.bytes_lost == 0) {
return;
}
-
- if (bytes_lost_in_round_ > 0) {
- if (bandwidth_lo_.IsInfinite()) {
- bandwidth_lo_ = MaxBandwidth();
+ // Ignore losses from packets sent when probing for more bandwidth in
+ // STARTUP or PROBE_UP when they're lost in DRAIN or PROBE_DOWN.
+ if (pacing_gain_ < 1) {
+ return;
+ }
+ // Decrease bandwidth_lo whenever there is loss.
+ // Set bandwidth_lo_ if it is not yet set.
+ if (bandwidth_lo_.IsInfinite()) {
+ bandwidth_lo_ = MaxBandwidth();
+ }
+ // Save bandwidth_lo_ if it hasn't already been saved.
+ if (prior_bandwidth_lo_.IsZero()) {
+ prior_bandwidth_lo_ = bandwidth_lo_;
+ }
+ switch (Params().bw_lo_mode_) {
+ case Bbr2Params::MIN_RTT_REDUCTION:
+ bandwidth_lo_ =
+ bandwidth_lo_ - QuicBandwidth::FromBytesAndTimeDelta(
+ congestion_event.bytes_lost, MinRtt());
+ break;
+ case Bbr2Params::INFLIGHT_REDUCTION: {
+ // Use a max of BDP and inflight to avoid starving app-limited flows.
+ const QuicByteCount effective_inflight =
+ std::max(BDP(), congestion_event.prior_bytes_in_flight);
+ // This could use bytes_lost_in_round if the bandwidth_lo_ was saved
+ // when entering 'recovery', but this BBRv2 implementation doesn't have
+ // recovery defined.
+ bandwidth_lo_ =
+ bandwidth_lo_ * ((effective_inflight - congestion_event.bytes_lost) /
+ static_cast<double>(effective_inflight));
+ break;
}
+ case Bbr2Params::CWND_REDUCTION:
+ bandwidth_lo_ =
+ bandwidth_lo_ *
+ ((congestion_event.prior_cwnd - congestion_event.bytes_lost) /
+ static_cast<double>(congestion_event.prior_cwnd));
+ break;
+ case Bbr2Params::DEFAULT:
+ QUIC_BUG(quic_bug_10466_1) << "Unreachable case DEFAULT.";
+ }
+ QuicBandwidth last_bandwidth = bandwidth_latest_;
+ // sample_max_bandwidth will be Zero() if the loss is triggered by a timer
+ // expiring. Ideally we'd use the most recent bandwidth sample,
+ // but bandwidth_latest is safer than Zero().
+ if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode2) &&
+ !congestion_event.sample_max_bandwidth.IsZero()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode2, 1, 2);
+ // bandwidth_latest_ is the max bandwidth for the round, but to allow
+ // fast, conservation style response to loss, use the last sample.
+ last_bandwidth = congestion_event.sample_max_bandwidth;
+ }
+ if (pacing_gain_ > Params().startup_full_bw_threshold) {
+ // In STARTUP, pacing_gain_ is applied to bandwidth_lo_ in
+ // UpdatePacingRate, so this backs that multiplication out to allow the
+ // pacing rate to decrease, but not below
+ // last_bandwidth * startup_full_bw_threshold.
+ // TODO(ianswett): Consider altering pacing_gain_ when in STARTUP instead.
+ bandwidth_lo_ = std::max(
+ bandwidth_lo_,
+ last_bandwidth * (Params().startup_full_bw_threshold / pacing_gain_));
+ } else {
+ // Ensure bandwidth_lo isn't lower than last_bandwidth.
+ bandwidth_lo_ = std::max(bandwidth_lo_, last_bandwidth);
+ }
+ // If it's the end of the round, ensure bandwidth_lo doesn't decrease more
+ // than beta.
+ if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode) &&
+ congestion_event.end_of_round_trip) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode, 2, 2);
bandwidth_lo_ =
- std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta));
- QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_
- << ", bandwidth_latest_ is " << bandwidth_latest_;
-
- if (Params().ignore_inflight_lo) {
- return;
- }
- if (inflight_lo_ == inflight_lo_default()) {
- inflight_lo_ = congestion_event.prior_cwnd;
- }
- inflight_lo_ = std::max<QuicByteCount>(
- inflight_latest_, inflight_lo_ * (1.0 - Params().beta));
+ std::max(bandwidth_lo_, prior_bandwidth_lo_ * (1.0 - Params().beta));
+ prior_bandwidth_lo_ = QuicBandwidth::Zero();
}
+ // These modes ignore inflight_lo as well.
}
void Bbr2NetworkModel::OnCongestionEventFinish(
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h
index 8f5d4185dfc..b7007f55705 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h
@@ -92,7 +92,7 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
// If true, always exit STARTUP on loss, even if bandwidth exceeds threshold.
// If false, exit STARTUP on loss only if bandwidth is below threshold.
- bool always_exit_startup_on_excess_loss = true;
+ bool always_exit_startup_on_excess_loss = false;
/*
* DRAIN parameters.
@@ -313,6 +313,8 @@ struct QUIC_EXPORT_PRIVATE Bbr2CongestionEvent {
QuicTime::Delta sample_min_rtt = QuicTime::Delta::Infinite();
// Maximum bandwidth of all bandwidth samples from acked_packets.
+ // This sample may be app-limited, and will be Zero() if there are no newly
+ // acknowledged inflight packets.
QuicBandwidth sample_max_bandwidth = QuicBandwidth::Zero();
// The send state of the largest packet in acked_packets, unless it is empty.
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
index 9045d7e034b..af0f00fee80 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
@@ -500,6 +500,15 @@ void Bbr2ProbeBwMode::EnterProbeDown(bool probed_too_high,
cycle_.rounds_in_phase = 0;
cycle_.phase_start_time = now;
++sender_->connection_stats_->bbr_num_cycles;
+ if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode2) &&
+ Params().bw_lo_mode_ != Bbr2Params::QuicBandwidthLoMode::DEFAULT) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode2, 2, 2);
+ // Clear bandwidth lo if it was set in PROBE_UP, because losses in PROBE_UP
+ // should not permanently change bandwidth_lo.
+ // It's possible for bandwidth_lo to be set during REFILL, but if that was
+ // a valid value, it'll quickly be rediscovered.
+ model_->clear_bandwidth_lo();
+ }
// Pick probe wait time.
cycle_.rounds_since_probe =
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc
index d0f61277283..b69a7952afa 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc
@@ -132,7 +132,7 @@ void Bbr2Sender::ApplyConnectionOptions(
params_.ignore_inflight_lo = true;
}
if (ContainsQuicTag(connection_options, kB2NE)) {
- params_.always_exit_startup_on_excess_loss = false;
+ params_.always_exit_startup_on_excess_loss = true;
}
if (ContainsQuicTag(connection_options, kB2SL)) {
params_.startup_loss_exit_use_max_delivered_for_inflight_hi = false;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc
index e26760e0bf9..99acf2c3e21 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -417,25 +417,6 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer) {
EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->smoothed_rtt(), 1.0f);
}
-TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2NE) {
- SetConnectionOption(kB2NE);
- DefaultTopologyParams params;
- CreateNetwork(params);
-
- // Transfer 12MB.
- DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
- EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
-
- EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
- sender_->ExportDebugState().bandwidth_hi, 0.01f);
-
- EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
- // The margin here is high, because the aggregation greatly increases
- // smoothed rtt.
- EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
- EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
-}
-
TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2RC) {
SetConnectionOption(kB2RC);
DefaultTopologyParams params;
@@ -859,6 +840,42 @@ TEST_F(Bbr2DefaultTopologyTest, ExitStartupDueToLossB2SL) {
EXPECT_APPROX_EQ(sender_->ExportDebugState().inflight_hi, params.BDP(), 0.1f);
}
+// Verifies that in STARTUP, if we exceed loss threshold in a round, we exit
+// STARTUP at the end of the round even if there's enough bandwidth growth.
+TEST_F(Bbr2DefaultTopologyTest, ExitStartupDueToLossB2NE) {
+ // Set up flags such that any loss will be considered "too high".
+ SetQuicFlag(FLAGS_quic_bbr2_default_startup_full_loss_count, 0);
+ SetQuicFlag(FLAGS_quic_bbr2_default_loss_threshold, 0.0);
+
+ sender_ = SetupBbr2Sender(&sender_endpoint_, /*old_sender=*/nullptr);
+
+ SetConnectionOption(kB2NE);
+ DefaultTopologyParams params;
+ params.switch_queue_capacity_in_bdp = 0.5;
+ CreateNetwork(params);
+
+ // Run until the full bandwidth is reached and check how many rounds it was.
+ sender_endpoint_.AddBytesToTransfer(12 * 1024 * 1024);
+ QuicRoundTripCount max_bw_round = 0;
+ QuicBandwidth max_bw(QuicBandwidth::Zero());
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this, &max_bw, &max_bw_round]() {
+ if (max_bw < sender_->ExportDebugState().bandwidth_hi) {
+ max_bw = sender_->ExportDebugState().bandwidth_hi;
+ max_bw_round = sender_->ExportDebugState().round_trip_count;
+ }
+ return sender_->ExportDebugState().startup.full_bandwidth_reached;
+ },
+ QuicTime::Delta::FromSeconds(5));
+ ASSERT_TRUE(simulator_result);
+ EXPECT_EQ(Bbr2Mode::DRAIN, sender_->ExportDebugState().mode);
+ EXPECT_EQ(sender_->ExportDebugState().round_trip_count, max_bw_round);
+ EXPECT_EQ(
+ 0u,
+ sender_->ExportDebugState().startup.round_trips_without_bandwidth_growth);
+ EXPECT_NE(0u, sender_connection_stats().packets_lost);
+}
+
TEST_F(Bbr2DefaultTopologyTest, SenderPoliced) {
DefaultTopologyParams params;
params.sender_policer_params = TrafficPolicerParams();
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc
index 5a9a532e688..1bd89c6024f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc
@@ -112,8 +112,9 @@ void Bbr2StartupMode::CheckExcessiveLosses(
new_inflight_hi = model_->max_bytes_delivered_in_round();
}
}
- QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss. inflight_hi:"
- << new_inflight_hi;
+ QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss at round "
+ << model_->RoundTripCount()
+ << ". inflight_hi:" << new_inflight_hi;
// TODO(ianswett): Add a shared method to set inflight_hi in the model.
model_->set_inflight_hi(new_inflight_hi);
model_->set_full_bandwidth_reached();
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
index c16668b2fdd..dccd7dfa48d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -13,7 +13,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc
index 5c093ad4ee0..67e35ed8934 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc
@@ -13,7 +13,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc
index 6877d9de48f..25abd716576 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc
@@ -12,7 +12,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc
index d51c5deb0ea..7e5fb25a937 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -12,7 +12,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc
index bfafd2cb513..c63a589a3d8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc
@@ -13,7 +13,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc
index 8d4c1de8e16..a2f8066717c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc
@@ -13,7 +13,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc
index b76ee7bf8d4..a024d131c2a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc
@@ -12,7 +12,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/crypto_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace test {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
index c21dd202b2d..4024a78e952 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
@@ -30,9 +30,9 @@
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_ip_address.h"
#include "quic/platform/api/quic_logging.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/platform/api/quiche_time_utils.h"
#include "common/quiche_data_reader.h"
+#include "common/quiche_text_utils.h"
namespace quic {
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
index 42d8899a781..93e48d257d0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -12,7 +12,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
index 8c403fede35..7fc32822f7e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -8,12 +8,12 @@
#include <string>
#include "absl/base/macros.h"
+#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "quic/core/crypto/chacha20_poly1305_decrypter.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
index 4b0f10bcd0d..b71bcf127f8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
@@ -12,7 +12,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
index 7bca425a708..61aaac73d17 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -14,7 +14,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc
index 3109924d59e..68e3d9cbe19 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc
@@ -13,7 +13,6 @@
#include "absl/strings/escaping.h"
#include "quic/core/crypto/crypto_framer.h"
#include "quic/core/quic_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using std::cerr;
using std::cout;
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
index e08d90b1c08..af62865b653 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
@@ -28,7 +28,7 @@ using ServerConfigID = std::string;
// The following tags have been deprecated and should not be reused:
// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL",
-// "QNZR", "B2HI", "H2PR", "FIFO", "LIFO", "RRWS"
+// "QNZR", "B2HI", "H2PR", "FIFO", "LIFO", "RRWS", "QNSP"
// clang-format off
const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello
@@ -127,9 +127,10 @@ const QuicTag kIW50 = TAG('I', 'W', '5', '0'); // Force ICWND to 50
const QuicTag kB2ON = TAG('B', '2', 'O', 'N'); // Enable BBRv2
const QuicTag kB2NA = TAG('B', '2', 'N', 'A'); // For BBRv2, do not add ack
// height to queueing threshold
-const QuicTag kB2NE = TAG('B', '2', 'N', 'E'); // For BBRv2, do not exit
- // STARTUP if there's enough
- // bandwidth growth
+const QuicTag kB2NE = TAG('B', '2', 'N', 'E'); // For BBRv2, always exit
+ // STARTUP on loss, even if
+ // bandwidth growth exceeds
+ // threshold.
const QuicTag kB2RP = TAG('B', '2', 'R', 'P'); // For BBRv2, run PROBE_RTT on
// the regular schedule
const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW
@@ -342,6 +343,7 @@ const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
const QuicTag kNSLC = TAG('N', 'S', 'L', 'C'); // Always send connection close
// for idle timeout.
+const QuicTag kCHSP = TAG('C', 'H', 'S', 'P'); // Chaos protection.
// Proof types (i.e. certificate types)
// NOTE: although it would be silly to do so, specifying both kX509 and kX59R
@@ -401,9 +403,6 @@ const QuicTag kPDP5 = TAG('P', 'D', 'P', '5'); // Path degrading triggered
const QuicTag kQNZ2 = TAG('Q', 'N', 'Z', '2'); // Turn off QUIC crypto 0-RTT.
-const QuicTag kQNSP = TAG('Q', 'N', 'S', 'P'); // Turn off server push in
- // gQUIC.
-
const QuicTag kMAD = TAG('M', 'A', 'D', 0); // Max Ack Delay (IETF QUIC)
const QuicTag kIGNP = TAG('I', 'G', 'N', 'P'); // Do not use PING only packet
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
index 7414eda8692..7fadbbdcef7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
@@ -33,7 +33,6 @@
#include "quic/test_tools/mock_random.h"
#include "quic/test_tools/quic_crypto_server_config_peer.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/quiche_endian.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
index 2c8435035c9..67527d45826 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
@@ -762,4 +762,21 @@ std::string CryptoUtils::HashHandshakeMessage(
}
#undef RETURN_STRING_LITERAL // undef for jumbo builds
+
+// static
+bool CryptoUtils::GetSSLCapabilities(const SSL* ssl,
+ bssl::UniquePtr<uint8_t>* capabilities,
+ size_t* capabilities_len) {
+ uint8_t* buffer;
+ CBB cbb;
+
+ if (!CBB_init(&cbb, 128) || !SSL_serialize_capabilities(ssl, &cbb) ||
+ !CBB_finish(&cbb, &buffer, capabilities_len)) {
+ return false;
+ }
+
+ *capabilities = bssl::UniquePtr<uint8_t>(buffer);
+ return true;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
index ec68c6580f4..7aa32e1445a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
@@ -237,6 +237,11 @@ class QUIC_EXPORT_PRIVATE CryptoUtils {
// Returns a hash of the serialized |message|.
static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message,
Perspective perspective);
+
+ // Wraps SSL_serialize_capabilities. Return nullptr if failed.
+ static bool GetSSLCapabilities(const SSL* ssl,
+ bssl::UniquePtr<uint8_t>* capabilities,
+ size_t* capabilities_len);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc
index 4586b9bbb4a..0f2df3a7f90 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc
@@ -11,7 +11,6 @@
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h
index cee94f2e4af..31cbfd66114 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h
@@ -229,12 +229,15 @@ class QUIC_EXPORT_PRIVATE ProofSourceHandleCallback {
// whether it is completed before ProofSourceHandle::SelectCertificate
// returned.
// |chain| the certificate chain in leaf-first order.
+ // |handshake_hints| (optional) handshake hints that can be used by
+ // SSL_set_handshake_hints.
//
// When called asynchronously(is_sync=false), this method will be responsible
// to continue the handshake from where it left off.
virtual void OnSelectCertificateDone(bool ok,
bool is_sync,
- const ProofSource::Chain* chain) = 0;
+ const ProofSource::Chain* chain,
+ absl::string_view handshake_hints) = 0;
// Called when a ProofSourceHandle::ComputeSignature operation completes.
virtual void OnComputeSignatureDone(
@@ -280,9 +283,11 @@ class QUIC_EXPORT_PRIVATE ProofSourceHandle {
virtual QuicAsyncStatus SelectCertificate(
const QuicSocketAddress& server_address,
const QuicSocketAddress& client_address,
+ absl::string_view ssl_capabilities,
const std::string& hostname,
absl::string_view client_hello,
const std::string& alpn,
+ absl::optional<std::string> alps,
const std::vector<uint8_t>& quic_transport_params,
const absl::optional<std::vector<uint8_t>>& early_data_context) = 0;
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc
index c886cbe989e..3f94e7cda60 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc
@@ -34,7 +34,6 @@
#include "quic/platform/api/quic_hostname_utils.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_map_util.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
index 4f19533b008..f2a88095aac 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
@@ -51,7 +51,6 @@
#include "quic/platform/api/quic_reference_counted.h"
#include "quic/platform/api/quic_socket_address.h"
#include "quic/platform/api/quic_testvalue.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
@@ -745,9 +744,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
<< context->connection_id() << " which is invalid with version "
<< context->version();
- if (context->validate_chlo_result()->postpone_cert_validate_for_server &&
- context->info().reject_reasons.empty()) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_crypto_postpone_cert_validate_for_server);
+ if (context->info().reject_reasons.empty()) {
if (!context->signed_config() || !context->signed_config()->chain) {
// No chain.
context->validate_chlo_result()->info.reject_reasons.push_back(
@@ -1224,8 +1221,8 @@ void QuicCryptoServerConfig::SelectNewPrimaryConfig(
}
void QuicCryptoServerConfig::EvaluateClientHello(
- const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
+ const QuicSocketAddress& /*server_address*/,
+ const QuicSocketAddress& /*client_address*/,
QuicTransportVersion /*version*/,
const Configs& configs,
QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
@@ -1294,17 +1291,6 @@ void QuicCryptoServerConfig::EvaluateClientHello(
// No valid source address token.
}
- if (!client_hello_state->postpone_cert_validate_for_server) {
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- proof_source_->GetCertChain(server_address, client_address,
- std::string(info->sni));
- if (!chain) {
- info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
- } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
- info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
- }
- }
-
if (info->client_nonce.size() != kNonceSize) {
info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
// Invalid client nonce.
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h
index 464f2bbfc36..4f3ad0819e4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h
@@ -98,9 +98,6 @@ class QUIC_EXPORT_PRIVATE ValidateClientHelloResultCallback {
// Populated if the CHLO STK contained a CachedNetworkParameters proto.
CachedNetworkParameters cached_network_params;
- const bool postpone_cert_validate_for_server =
- GetQuicReloadableFlag(quic_crypto_postpone_cert_validate_for_server);
-
protected:
~Result() override;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc
index 9f70c355237..484e46eee6a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -25,7 +25,6 @@
#include "quic/test_tools/mock_clock.h"
#include "quic/test_tools/quic_crypto_server_config_peer.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace test {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc
index 73f850ed68a..e23d3f2a1e9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc
@@ -9,7 +9,6 @@
#include "absl/base/macros.h"
#include "absl/strings/escaping.h"
#include "quic/platform/api/quic_test.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace test {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc
index 8926909cd78..6e9901b995e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc
@@ -30,16 +30,12 @@ bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx(
QUIC_CODE_COUNT(quic_session_tickets_enabled);
SSL_CTX_set_ticket_aead_method(ssl_ctx.get(),
&TlsServerConnection::kSessionTicketMethod);
- } else if (!GetQuicRestartFlag(quic_session_tickets_always_enabled)) {
- QUIC_CODE_COUNT(quic_session_tickets_disabled_by_flag);
- SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET);
} else {
QUIC_CODE_COUNT(quic_session_tickets_disabled);
}
- if (proof_source->GetTicketCrypter() ||
- GetQuicRestartFlag(quic_session_tickets_always_enabled)) {
- SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
- }
+
+ SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
+
SSL_CTX_set_select_certificate_cb(
ssl_ctx.get(), &TlsServerConnection::EarlySelectCertCallback);
SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc
index 8ad442fc694..8642fd93265 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc
@@ -6,7 +6,6 @@
#include "absl/strings/escaping.h"
#include "quic/platform/api/quic_logging.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc
index 857ca19291f..0f88bb83160 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc
@@ -6,7 +6,6 @@
#include "absl/strings/escaping.h"
#include "quic/platform/api/quic_bug_tracker.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc
index ade4156b8ab..f802b131b30 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc
@@ -6,7 +6,6 @@
#include "absl/strings/escaping.h"
#include "quic/platform/api/quic_bug_tracker.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h
index ae291b7826f..1e47d16a5f1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h
+++ b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h
@@ -74,6 +74,9 @@ class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface {
// Called at the end of an handshake operation callback.
virtual void OnHandshakeCallbackDone() = 0;
+
+ // Whether a packet flusher is currently attached.
+ virtual bool PacketFlusherAttached() const = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
index aceebe1b33b..8efba8869bf 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
@@ -17,6 +17,7 @@
#include "quic/core/http/http_constants.h"
#include "quic/core/http/quic_spdy_client_stream.h"
#include "quic/core/http/web_transport_http3.h"
+#include "quic/core/quic_connection.h"
#include "quic/core/quic_data_writer.h"
#include "quic/core/quic_epoll_connection_helper.h"
#include "quic/core/quic_error_codes.h"
@@ -43,7 +44,6 @@
#include "quic/test_tools/packet_reordering_writer.h"
#include "quic/test_tools/qpack/qpack_encoder_peer.h"
#include "quic/test_tools/qpack/qpack_encoder_test_utils.h"
-#include "quic/test_tools/qpack/qpack_header_table_peer.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
#include "quic/test_tools/quic_client_peer.h"
#include "quic/test_tools/quic_config_peer.h"
@@ -80,6 +80,7 @@ using ::testing::_;
using ::testing::Assign;
using ::testing::Invoke;
using ::testing::NiceMock;
+using testing::NotNull;
namespace quic {
namespace test {
@@ -750,6 +751,18 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
}
}
+ void WaitForNewConnectionIds() {
+ // Wait until a new server CID is available for another migration.
+ const auto* client_connection = GetClientConnection();
+ while (!QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(
+ client_connection) ||
+ (!client_connection->client_connection_id().IsEmpty() &&
+ !QuicConnectionPeer::HasSelfIssuedConnectionIdToConsume(
+ client_connection))) {
+ client_->client()->WaitForEvents();
+ }
+ }
+
ScopedEnvironmentForThreads environment_;
bool initialized_;
// If true, the Initialize() function will create |client_| and starts to
@@ -1552,17 +1565,11 @@ TEST_P(EndToEndTest, AddressToken) {
server_thread_->Pause();
QuicConnection* server_connection = GetServerConnection();
if (server_connection != nullptr) {
- if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) {
- // Verify address is validated via validating token received in INITIAL
- // packet.
- EXPECT_FALSE(server_connection->GetStats()
- .address_validated_via_decrypting_packet);
- EXPECT_TRUE(server_connection->GetStats().address_validated_via_token);
- } else {
- EXPECT_TRUE(server_connection->GetStats()
- .address_validated_via_decrypting_packet);
- EXPECT_FALSE(server_connection->GetStats().address_validated_via_token);
- }
+ // Verify address is validated via validating token received in INITIAL
+ // packet.
+ EXPECT_FALSE(
+ server_connection->GetStats().address_validated_via_decrypting_packet);
+ EXPECT_TRUE(server_connection->GetStats().address_validated_via_token);
} else {
ADD_FAILURE() << "Missing server connection";
}
@@ -2477,10 +2484,7 @@ TEST_P(
HalfRttResponseBlocksShloRetransmissionWithoutTokenBasedAddressValidation) {
// Turn off token based address validation to make the server get constrained
// by amplification factor during handshake.
- // TODO(fayang): Keep this test while deprecating
- // quic_enable_token_based_address_validation. For example, consider always
- // rejecting the received address token.
- SetQuicReloadableFlag(quic_enable_token_based_address_validation, false);
+ SetQuicFlag(FLAGS_quic_reject_retry_token_in_initial_packet, true);
ASSERT_TRUE(Initialize());
if (!version_.SupportsAntiAmplificationLimit()) {
return;
@@ -2502,17 +2506,8 @@ TEST_P(
// Large response (100KB) for 0-RTT request.
std::string large_body(102400, 'a');
AddToCache("/large_response", 200, large_body);
- if (GetQuicReloadableFlag(quic_preempt_stream_data_with_handshake_packet)) {
- SendSynchronousRequestAndCheckResponse(client_.get(), "/large_response",
- large_body);
- } else {
- // Server consistently gets constrained by amplification factor, hence PTO
- // never gets armed. The CHLO retransmission would trigger the
- // retransmission of SHLO, however, the ENCRYPTION_HANDSHAKE packet NEVER
- // gets retransmitted since half RTT data consumes the remaining space in
- // the coalescer.
- EXPECT_EQ("", client_->SendSynchronousRequest("/large_response"));
- }
+ SendSynchronousRequestAndCheckResponse(client_.get(), "/large_response",
+ large_body);
}
TEST_P(EndToEndTest, MaxStreamsUberTest) {
@@ -2620,6 +2615,253 @@ TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) {
server_thread_->Resume();
}
+TEST_P(EndToEndTest, IetfConnectionMigrationClientIPChangedMultipleTimes) {
+ ASSERT_TRUE(Initialize());
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
+ return;
+ }
+ SendSynchronousFooRequestAndCheckResponse();
+
+ // Store the client IP address which was used to send the first request.
+ QuicIpAddress host0 =
+ client_->client()->network_helper()->GetLatestClientAddress().host();
+ QuicConnection* client_connection = GetClientConnection();
+ ASSERT_TRUE(client_connection != nullptr);
+
+ // Migrate socket to a new IP address.
+ QuicIpAddress host1 = TestLoopback(2);
+ EXPECT_NE(host0, host1);
+ ASSERT_TRUE(
+ QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection));
+ QuicConnectionId server_cid0 = client_connection->connection_id();
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(client_->client()->MigrateSocket(host1));
+ QuicConnectionId server_cid1 = client_connection->connection_id();
+ EXPECT_FALSE(server_cid1.IsEmpty());
+ EXPECT_NE(server_cid0, server_cid1);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send a request using the new socket.
+ SendSynchronousBarRequestAndCheckResponse();
+ EXPECT_EQ(1u,
+ client_connection->GetStats().num_connectivity_probing_received);
+
+ // Send another request and wait for response making sure path response is
+ // received at server.
+ SendSynchronousBarRequestAndCheckResponse();
+
+ // Migrate socket to a new IP address.
+ WaitForNewConnectionIds();
+ EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent);
+ QuicIpAddress host2 = TestLoopback(3);
+ EXPECT_NE(host0, host2);
+ EXPECT_NE(host1, host2);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(client_->client()->MigrateSocket(host2));
+ QuicConnectionId server_cid2 = client_connection->connection_id();
+ EXPECT_FALSE(server_cid2.IsEmpty());
+ EXPECT_NE(server_cid0, server_cid2);
+ EXPECT_NE(server_cid1, server_cid2);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send another request using the new socket and wait for response making sure
+ // path response is received at server.
+ SendSynchronousBarRequestAndCheckResponse();
+ EXPECT_EQ(2u,
+ client_connection->GetStats().num_connectivity_probing_received);
+
+ // Migrate socket back to an old IP address.
+ WaitForNewConnectionIds();
+ EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(client_->client()->MigrateSocket(host1));
+ QuicConnectionId server_cid3 = client_connection->connection_id();
+ EXPECT_FALSE(server_cid3.IsEmpty());
+ EXPECT_NE(server_cid0, server_cid3);
+ EXPECT_NE(server_cid1, server_cid3);
+ EXPECT_NE(server_cid2, server_cid3);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ const auto* client_packet_creator =
+ QuicConnectionPeer::GetPacketCreator(client_connection);
+ EXPECT_TRUE(client_packet_creator->GetClientConnectionId().IsEmpty());
+ EXPECT_EQ(server_cid3, client_packet_creator->GetServerConnectionId());
+
+ // Send another request using the new socket and wait for response making sure
+ // path response is received at server.
+ SendSynchronousBarRequestAndCheckResponse();
+ // Even this is an old path, server has forgotten about it and thus needs to
+ // validate the path again.
+ EXPECT_EQ(3u,
+ client_connection->GetStats().num_connectivity_probing_received);
+
+ WaitForNewConnectionIds();
+ EXPECT_EQ(3u, client_connection->GetStats().num_retire_connection_id_sent);
+
+ server_thread_->Pause();
+ QuicConnection* server_connection = GetServerConnection();
+ // By the time the 2nd request is completed, the PATH_RESPONSE must have been
+ // received by the server.
+ EXPECT_FALSE(server_connection->HasPendingPathValidation());
+ EXPECT_EQ(3u, server_connection->GetStats().num_validated_peer_migration);
+ EXPECT_EQ(server_cid3, server_connection->connection_id());
+ const auto* server_packet_creator =
+ QuicConnectionPeer::GetPacketCreator(server_connection);
+ EXPECT_EQ(server_cid3, server_packet_creator->GetServerConnectionId());
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ server_connection)
+ .IsEmpty());
+ EXPECT_EQ(4u, server_connection->GetStats().num_new_connection_id_sent);
+ server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest,
+ ConnectionMigrationWithNonZeroConnectionIDClientIPChangedMultipleTimes) {
+ if (!version_.SupportsClientConnectionIds()) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ override_client_connection_id_length_ = kQuicDefaultConnectionIdLength;
+ ASSERT_TRUE(Initialize());
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
+ return;
+ }
+ SendSynchronousFooRequestAndCheckResponse();
+
+ // Store the client IP address which was used to send the first request.
+ QuicIpAddress host0 =
+ client_->client()->network_helper()->GetLatestClientAddress().host();
+ QuicConnection* client_connection = GetClientConnection();
+ ASSERT_TRUE(client_connection != nullptr);
+
+ // Migrate socket to a new IP address.
+ QuicIpAddress host1 = TestLoopback(2);
+ EXPECT_NE(host0, host1);
+ ASSERT_TRUE(
+ QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection));
+ QuicConnectionId server_cid0 = client_connection->connection_id();
+ QuicConnectionId client_cid0 = client_connection->client_connection_id();
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(client_->client()->MigrateSocket(host1));
+ QuicConnectionId server_cid1 = client_connection->connection_id();
+ QuicConnectionId client_cid1 = client_connection->client_connection_id();
+ EXPECT_FALSE(server_cid1.IsEmpty());
+ EXPECT_FALSE(client_cid1.IsEmpty());
+ EXPECT_NE(server_cid0, server_cid1);
+ EXPECT_NE(client_cid0, client_cid1);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send another request to ensure that the server will have time to finish the
+ // reverse path validation and send address token.
+ SendSynchronousBarRequestAndCheckResponse();
+ EXPECT_EQ(1u,
+ client_connection->GetStats().num_connectivity_probing_received);
+
+ // Migrate socket to a new IP address.
+ WaitForNewConnectionIds();
+ EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(2u, client_connection->GetStats().num_new_connection_id_sent);
+ QuicIpAddress host2 = TestLoopback(3);
+ EXPECT_NE(host0, host2);
+ EXPECT_NE(host1, host2);
+ EXPECT_TRUE(client_->client()->MigrateSocket(host2));
+ QuicConnectionId server_cid2 = client_connection->connection_id();
+ QuicConnectionId client_cid2 = client_connection->client_connection_id();
+ EXPECT_FALSE(server_cid2.IsEmpty());
+ EXPECT_NE(server_cid0, server_cid2);
+ EXPECT_NE(server_cid1, server_cid2);
+ EXPECT_FALSE(client_cid2.IsEmpty());
+ EXPECT_NE(client_cid0, client_cid2);
+ EXPECT_NE(client_cid1, client_cid2);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_TRUE(QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send another request to ensure that the server will have time to finish the
+ // reverse path validation and send address token.
+ SendSynchronousBarRequestAndCheckResponse();
+ EXPECT_EQ(2u,
+ client_connection->GetStats().num_connectivity_probing_received);
+
+ // Migrate socket back to an old IP address.
+ WaitForNewConnectionIds();
+ EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(3u, client_connection->GetStats().num_new_connection_id_sent);
+ EXPECT_TRUE(client_->client()->MigrateSocket(host1));
+ QuicConnectionId server_cid3 = client_connection->connection_id();
+ QuicConnectionId client_cid3 = client_connection->client_connection_id();
+ EXPECT_FALSE(server_cid3.IsEmpty());
+ EXPECT_NE(server_cid0, server_cid3);
+ EXPECT_NE(server_cid1, server_cid3);
+ EXPECT_NE(server_cid2, server_cid3);
+ EXPECT_FALSE(client_cid3.IsEmpty());
+ EXPECT_NE(client_cid0, client_cid3);
+ EXPECT_NE(client_cid1, client_cid3);
+ EXPECT_NE(client_cid2, client_cid3);
+ const auto* client_packet_creator =
+ QuicConnectionPeer::GetPacketCreator(client_connection);
+ EXPECT_EQ(client_cid3, client_packet_creator->GetClientConnectionId());
+ EXPECT_EQ(server_cid3, client_packet_creator->GetServerConnectionId());
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send another request to ensure that the server will have time to finish the
+ // reverse path validation and send address token.
+ SendSynchronousBarRequestAndCheckResponse();
+ // Even this is an old path, server has forgotten about it and thus needs to
+ // validate the path again.
+ EXPECT_EQ(3u,
+ client_connection->GetStats().num_connectivity_probing_received);
+
+ WaitForNewConnectionIds();
+ EXPECT_EQ(3u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(4u, client_connection->GetStats().num_new_connection_id_sent);
+
+ server_thread_->Pause();
+ // By the time the 2nd request is completed, the PATH_RESPONSE must have been
+ // received by the server.
+ QuicConnection* server_connection = GetServerConnection();
+ EXPECT_FALSE(server_connection->HasPendingPathValidation());
+ EXPECT_EQ(3u, server_connection->GetStats().num_validated_peer_migration);
+ EXPECT_EQ(server_cid3, server_connection->connection_id());
+ EXPECT_EQ(client_cid3, server_connection->client_connection_id());
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ server_connection)
+ .IsEmpty());
+ const auto* server_packet_creator =
+ QuicConnectionPeer::GetPacketCreator(server_connection);
+ EXPECT_EQ(client_cid3, server_packet_creator->GetClientConnectionId());
+ EXPECT_EQ(server_cid3, server_packet_creator->GetServerConnectionId());
+ EXPECT_EQ(3u, server_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(4u, server_connection->GetStats().num_new_connection_id_sent);
+ server_thread_->Resume();
+}
+
TEST_P(EndToEndTest, ConnectionMigrationNewTokenForNewIp) {
ASSERT_TRUE(Initialize());
if (!version_.HasIetfQuicFrames() ||
@@ -2644,7 +2886,7 @@ TEST_P(EndToEndTest, ConnectionMigrationNewTokenForNewIp) {
EXPECT_EQ(1u,
client_connection->GetStats().num_connectivity_probing_received);
- // Send another request to ensure that the server will time to finish the
+ // Send another request to ensure that the server will have time to finish the
// reverse path validation and send address token.
SendSynchronousBarRequestAndCheckResponse();
@@ -2661,17 +2903,11 @@ TEST_P(EndToEndTest, ConnectionMigrationNewTokenForNewIp) {
server_thread_->Pause();
QuicConnection* server_connection = GetServerConnection();
if (server_connection != nullptr) {
- if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) {
- // Verify address is validated via validating token received in INITIAL
- // packet.
- EXPECT_FALSE(server_connection->GetStats()
- .address_validated_via_decrypting_packet);
- EXPECT_TRUE(server_connection->GetStats().address_validated_via_token);
- } else {
- EXPECT_TRUE(server_connection->GetStats()
- .address_validated_via_decrypting_packet);
- EXPECT_FALSE(server_connection->GetStats().address_validated_via_token);
- }
+ // Verify address is validated via validating token received in INITIAL
+ // packet.
+ EXPECT_FALSE(
+ server_connection->GetStats().address_validated_via_decrypting_packet);
+ EXPECT_TRUE(server_connection->GetStats().address_validated_via_token);
} else {
ADD_FAILURE() << "Missing server connection";
}
@@ -2709,14 +2945,19 @@ class DuplicatePacketWithSpoofedSelfAddressWriter
TEST_P(EndToEndTest, ClientAddressSpoofedForSomePeriod) {
ASSERT_TRUE(Initialize());
- if (!version_.HasIetfQuicFrames() ||
- !client_->client()->session()->connection()->validate_client_address()) {
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
return;
}
auto writer = new DuplicatePacketWithSpoofedSelfAddressWriter();
client_.reset(CreateQuicClient(writer));
+
+ // Make sure client has unused peer connection ID before migration.
+ SendSynchronousFooRequestAndCheckResponse();
+ ASSERT_TRUE(QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(
+ GetClientConnection()));
+
QuicIpAddress real_host = TestLoopback(1);
- client_->MigrateSocket(real_host);
+ ASSERT_TRUE(client_->MigrateSocket(real_host));
SendSynchronousFooRequestAndCheckResponse();
EXPECT_EQ(
0u, GetClientConnection()->GetStats().num_connectivity_probing_received);
@@ -2755,10 +2996,107 @@ TEST_P(EndToEndTest, ClientAddressSpoofedForSomePeriod) {
EXPECT_EQ(large_body, client_->response_body());
}
-TEST_P(EndToEndTest, AsynchronousConnectionMigrationClientIPChanged) {
+TEST_P(EndToEndTest,
+ AsynchronousConnectionMigrationClientIPChangedMultipleTimes) {
ASSERT_TRUE(Initialize());
- if (!version_.HasIetfQuicFrames() ||
- !client_->client()->session()->connection()->use_path_validator()) {
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
+ return;
+ }
+ client_.reset(CreateQuicClient(nullptr));
+
+ SendSynchronousFooRequestAndCheckResponse();
+
+ // Store the client IP address which was used to send the first request.
+ QuicIpAddress host0 =
+ client_->client()->network_helper()->GetLatestClientAddress().host();
+ QuicConnection* client_connection = GetClientConnection();
+ QuicConnectionId server_cid0 = client_connection->connection_id();
+ // Server should have one new connection ID upon handshake completion.
+ ASSERT_TRUE(
+ QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection));
+
+ // Migrate socket to new IP address #1.
+ QuicIpAddress host1 = TestLoopback(2);
+ EXPECT_NE(host0, host1);
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host1));
+ while (client_->client()->HasPendingPathValidation()) {
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(host1, client_->client()->session()->self_address().host());
+ EXPECT_EQ(1u,
+ client_connection->GetStats().num_connectivity_probing_received);
+ QuicConnectionId server_cid1 = client_connection->connection_id();
+ EXPECT_NE(server_cid0, server_cid1);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send a request using the new socket.
+ SendSynchronousBarRequestAndCheckResponse();
+
+ // Migrate socket to new IP address #2.
+ WaitForNewConnectionIds();
+ QuicIpAddress host2 = TestLoopback(3);
+ EXPECT_NE(host0, host1);
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host2));
+
+ while (client_->client()->HasPendingPathValidation()) {
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(host2, client_->client()->session()->self_address().host());
+ EXPECT_EQ(2u,
+ client_connection->GetStats().num_connectivity_probing_received);
+ QuicConnectionId server_cid2 = client_connection->connection_id();
+ EXPECT_NE(server_cid0, server_cid2);
+ EXPECT_NE(server_cid1, server_cid2);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send a request using the new socket.
+ SendSynchronousBarRequestAndCheckResponse();
+
+ // Migrate socket back to IP address #1.
+ WaitForNewConnectionIds();
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host1));
+
+ while (client_->client()->HasPendingPathValidation()) {
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(host1, client_->client()->session()->self_address().host());
+ EXPECT_EQ(3u,
+ client_connection->GetStats().num_connectivity_probing_received);
+ QuicConnectionId server_cid3 = client_connection->connection_id();
+ EXPECT_NE(server_cid0, server_cid3);
+ EXPECT_NE(server_cid1, server_cid3);
+ EXPECT_NE(server_cid2, server_cid3);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+
+ // Send a request using the new socket.
+ SendSynchronousBarRequestAndCheckResponse();
+ server_thread_->Pause();
+ const QuicConnection* server_connection = GetServerConnection();
+ EXPECT_EQ(server_connection->connection_id(), server_cid3);
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ server_connection)
+ .IsEmpty());
+ server_thread_->Resume();
+
+ // There should be 1 new connection ID issued by the server.
+ WaitForNewConnectionIds();
+}
+
+TEST_P(EndToEndTest,
+ AsynchronousConnectionMigrationClientIPChangedWithNonEmptyClientCID) {
+ if (!version_.SupportsClientConnectionIds()) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ override_client_connection_id_length_ = kQuicDefaultConnectionIdLength;
+ ASSERT_TRUE(Initialize());
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
return;
}
client_.reset(CreateQuicClient(nullptr));
@@ -2768,6 +3106,9 @@ TEST_P(EndToEndTest, AsynchronousConnectionMigrationClientIPChanged) {
// Store the client IP address which was used to send the first request.
QuicIpAddress old_host =
client_->client()->network_helper()->GetLatestClientAddress().host();
+ auto* client_connection = GetClientConnection();
+ QuicConnectionId client_cid0 = client_connection->client_connection_id();
+ QuicConnectionId server_cid0 = client_connection->connection_id();
// Migrate socket to the new IP address.
QuicIpAddress new_host = TestLoopback(2);
@@ -2778,12 +3119,26 @@ TEST_P(EndToEndTest, AsynchronousConnectionMigrationClientIPChanged) {
client_->client()->WaitForEvents();
}
EXPECT_EQ(new_host, client_->client()->session()->self_address().host());
- QuicConnection* client_connection = GetClientConnection();
- ASSERT_TRUE(client_connection);
- EXPECT_EQ(client_connection->validate_client_address() ? 1u : 0,
+ EXPECT_EQ(1u,
client_connection->GetStats().num_connectivity_probing_received);
+ QuicConnectionId client_cid1 = client_connection->client_connection_id();
+ QuicConnectionId server_cid1 = client_connection->connection_id();
+ const auto* client_packet_creator =
+ QuicConnectionPeer::GetPacketCreator(client_connection);
+ EXPECT_EQ(client_cid1, client_packet_creator->GetClientConnectionId());
+ EXPECT_EQ(server_cid1, client_packet_creator->GetServerConnectionId());
// Send a request using the new socket.
SendSynchronousBarRequestAndCheckResponse();
+
+ server_thread_->Pause();
+ QuicConnection* server_connection = GetServerConnection();
+ EXPECT_EQ(client_cid1, server_connection->client_connection_id());
+ EXPECT_EQ(server_cid1, server_connection->connection_id());
+ const auto* server_packet_creator =
+ QuicConnectionPeer::GetPacketCreator(server_connection);
+ EXPECT_EQ(client_cid1, server_packet_creator->GetClientConnectionId());
+ EXPECT_EQ(server_cid1, server_packet_creator->GetServerConnectionId());
+ server_thread_->Resume();
}
TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) {
@@ -3257,13 +3612,13 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) {
ADD_FAILURE() << "Missing QPACK encoder";
return;
}
- QpackHeaderTable* header_table =
+ QpackEncoderHeaderTable* header_table =
QpackEncoderPeer::header_table(qpack_encoder);
if (header_table == nullptr) {
ADD_FAILURE() << "Missing header table";
return;
}
- if (QpackHeaderTablePeer::dynamic_table_capacity(header_table) > 0) {
+ if (header_table->dynamic_table_capacity() > 0) {
break;
}
}
@@ -3880,312 +4235,6 @@ TEST_P(EndToEndTest, Trailers) {
EXPECT_EQ(trailers, client_->response_trailers());
}
-class EndToEndTestServerPush : public EndToEndTest {
- protected:
- const size_t kNumMaxStreams = 10;
-
- EndToEndTestServerPush() : EndToEndTest() {
- client_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams);
- server_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams);
- client_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams);
- server_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams);
- }
-
- // Add a request with its response and |num_resources| push resources into
- // cache.
- // If |resource_size| == 0, response body of push resources use default string
- // concatenating with resource url. Otherwise, generate a string of
- // |resource_size| as body.
- void AddRequestAndResponseWithServerPush(std::string host,
- std::string path,
- std::string response_body,
- std::string* push_urls,
- const size_t num_resources,
- const size_t resource_size) {
- bool use_large_response = resource_size != 0;
- std::string large_resource;
- if (use_large_response) {
- // Generate a response common body larger than flow control window for
- // push response.
- large_resource = std::string(resource_size, 'a');
- }
- std::list<QuicBackendResponse::ServerPushInfo> push_resources;
- for (size_t i = 0; i < num_resources; ++i) {
- std::string url = push_urls[i];
- QuicUrl resource_url(url);
- std::string body =
- use_large_response
- ? large_resource
- : absl::StrCat("This is server push response body for ", url);
- SpdyHeaderBlock response_headers;
- response_headers[":status"] = "200";
- response_headers["content-length"] = absl::StrCat(body.size());
- push_resources.push_back(QuicBackendResponse::ServerPushInfo(
- resource_url, std::move(response_headers), kV3LowestPriority, body));
- }
-
- memory_cache_backend_.AddSimpleResponseWithServerPushResources(
- host, path, 200, response_body, push_resources);
- }
-};
-
-// Run all server push end to end tests with all supported versions.
-INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush,
- EndToEndTestServerPush,
- ::testing::ValuesIn(GetTestParams()),
- ::testing::PrintToStringParamName());
-
-TEST_P(EndToEndTestServerPush, ServerPush) {
- ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
-
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
- size_t kNumResources = 4;
- std::string push_urls[] = {"https://example.com/font.woff",
- "https://example.com/script.js",
- "https://fonts.example.com/font.woff",
- "https://example.com/logo-hires.jpg"};
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, 0);
-
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- QUIC_DVLOG(1) << "send request for /push_example";
- EXPECT_EQ(kBody, client_->SendSynchronousRequest(
- "https://example.com/push_example"));
- QuicStreamSequencer* sequencer = nullptr;
- if (!version_.UsesHttp3()) {
- QuicSpdyClientSession* client_session = GetClientSession();
- ASSERT_TRUE(client_session);
- QuicHeadersStream* headers_stream =
- QuicSpdySessionPeer::GetHeadersStream(client_session);
- ASSERT_TRUE(headers_stream);
- sequencer = QuicStreamPeer::sequencer(headers_stream);
- ASSERT_TRUE(sequencer);
- // Headers stream's sequencer buffer shouldn't be released because server
- // push hasn't finished yet.
- EXPECT_TRUE(
- QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
- }
-
- for (const std::string& url : push_urls) {
- QUIC_DVLOG(1) << "send request for pushed stream on url " << url;
- std::string expected_body =
- absl::StrCat("This is server push response body for ", url);
- std::string response_body = client_->SendSynchronousRequest(url);
- QUIC_DVLOG(1) << "response body " << response_body;
- EXPECT_EQ(expected_body, response_body);
- }
- if (!version_.UsesHttp3()) {
- ASSERT_TRUE(sequencer);
- EXPECT_FALSE(
- QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
- }
-}
-
-TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
- // Tests that sending a request which has 4 push resources will trigger server
- // to push those 4 resources and client can handle pushed resources and match
- // them with requests later.
- ASSERT_TRUE(Initialize());
-
- if (version_.UsesHttp3()) {
- return;
- }
-
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
- size_t const kNumResources = 4;
- std::string push_urls[] = {
- "https://example.com/font.woff",
- "https://example.com/script.js",
- "https://fonts.example.com/font.woff",
- "https://example.com/logo-hires.jpg",
- };
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, 0);
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- // Send the first request: this will trigger the server to send all the push
- // resources associated with this request, and these will be cached by the
- // client.
- EXPECT_EQ(kBody, client_->SendSynchronousRequest(
- "https://example.com/push_example"));
-
- for (const std::string& url : push_urls) {
- // Sending subsequent requesets will not actually send anything on the wire,
- // as the responses are already in the client's cache.
- QUIC_DVLOG(1) << "send request for pushed stream on url " << url;
- std::string expected_body =
- absl::StrCat("This is server push response body for ", url);
- std::string response_body = client_->SendSynchronousRequest(url);
- QUIC_DVLOG(1) << "response body " << response_body;
- EXPECT_EQ(expected_body, response_body);
- }
- // Expect only original request has been sent and push responses have been
- // received as normal response.
- EXPECT_EQ(1u, client_->num_requests());
- EXPECT_EQ(1u + kNumResources, client_->num_responses());
-}
-
-TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
- if (version_.UsesHttp3()) {
- ASSERT_TRUE(Initialize());
- return;
- }
- // Tests that when streams are not blocked by flow control or congestion
- // control, pushing even more resources than max number of open outgoing
- // streams should still work because all response streams get closed
- // immediately after pushing resources.
- ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
-
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
-
- // One more resource than max number of outgoing stream of this session.
- const size_t kNumResources = 1 + kNumMaxStreams; // 11.
- std::string push_urls[11];
- for (size_t i = 0; i < kNumResources; ++i) {
- push_urls[i] = absl::StrCat("https://example.com/push_resources", i);
- }
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, 0);
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- // Send the first request: this will trigger the server to send all the push
- // resources associated with this request, and these will be cached by the
- // client.
- EXPECT_EQ(kBody, client_->SendSynchronousRequest(
- "https://example.com/push_example"));
-
- for (const std::string& url : push_urls) {
- // Sending subsequent requesets will not actually send anything on the wire,
- // as the responses are already in the client's cache.
- EXPECT_EQ(absl::StrCat("This is server push response body for ", url),
- client_->SendSynchronousRequest(url));
- }
-
- // Only 1 request should have been sent.
- EXPECT_EQ(1u, client_->num_requests());
- // The responses to the original request and all the promised resources
- // should have been received.
- EXPECT_EQ(12u, client_->num_responses());
-}
-
-TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
- if (version_.UsesHttp3()) {
- ASSERT_TRUE(Initialize());
- return;
- }
-
- // Tests that when server tries to send more large resources(large enough to
- // be blocked by flow control window or congestion control window) than max
- // open outgoing streams , server can open upto max number of outgoing
- // streams for them, and the rest will be queued up.
-
- // Reset flow control windows.
- size_t kFlowControlWnd = 20 * 1024; // 20KB.
- // Response body is larger than 1 flow controlblock window.
- size_t kBodySize = kFlowControlWnd * 2;
- set_client_initial_stream_flow_control_receive_window(kFlowControlWnd);
- // Make sure conntection level flow control window is large enough not to
- // block data being sent out though they will be blocked by stream level one.
- set_client_initial_session_flow_control_receive_window(
- kBodySize * kNumMaxStreams + 1024);
-
- ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
-
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
-
- const size_t kNumResources = kNumMaxStreams + 1;
- std::string push_urls[11];
- for (size_t i = 0; i < kNumResources; ++i) {
- push_urls[i] = absl::StrCat("http://example.com/push_resources", i);
- }
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, kBodySize);
-
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- client_->SendRequest("https://example.com/push_example");
-
- // Pause after the first response arrives.
- while (!client_->response_complete()) {
- // Because of priority, the first response arrived should be to original
- // request.
- client_->WaitForResponse();
- ASSERT_TRUE(client_->connected());
- }
-
- // Check server session to see if it has max number of outgoing streams opened
- // though more resources need to be pushed.
- if (!version_.HasIetfQuicFrames()) {
- server_thread_->Pause();
- QuicSession* server_session = GetServerSession();
- if (server_session != nullptr) {
- EXPECT_EQ(kNumMaxStreams,
- QuicSessionPeer::GetStreamIdManager(server_session)
- ->num_open_outgoing_streams());
- } else {
- ADD_FAILURE() << "Missing server session";
- }
- server_thread_->Resume();
- }
-
- EXPECT_EQ(1u, client_->num_requests());
- EXPECT_EQ(1u, client_->num_responses());
- EXPECT_EQ(kBody, client_->response_body());
-
- // "Send" request for a promised resources will not really send out it because
- // its response is being pushed(but blocked). And the following ack and
- // flow control behavior of SendSynchronousRequests()
- // will unblock the stream to finish receiving response.
- client_->SendSynchronousRequest(push_urls[0]);
- EXPECT_EQ(1u, client_->num_requests());
- EXPECT_EQ(2u, client_->num_responses());
-
- // Do same thing for the rest 10 resources.
- for (size_t i = 1; i < kNumResources; ++i) {
- client_->SendSynchronousRequest(push_urls[i]);
- }
-
- // Because of server push, client gets all pushed resources without actually
- // sending requests for them.
- EXPECT_EQ(1u, client_->num_requests());
- // Including response to original request, 12 responses in total were
- // received.
- EXPECT_EQ(12u, client_->num_responses());
-}
-
// TODO(fayang): this test seems to cause net_unittests timeouts :|
TEST_P(EndToEndTest, DISABLED_TestHugePostWithPacketLoss) {
// This test tests a huge post with introduced packet loss from client to
@@ -4440,11 +4489,7 @@ TEST_P(EndToEndTest,
client_.reset(CreateQuicClient(client_writer_));
EXPECT_EQ("", client_->SendSynchronousRequest("/foo"));
- if (GetQuicReloadableFlag(quic_fix_dispatcher_sent_error_code)) {
- EXPECT_THAT(client_->connection_error(), IsError(QUIC_PACKET_WRITE_ERROR));
- } else {
- EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_FAILED));
- }
+ EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_FAILED));
}
// Regression test for b/116200989.
@@ -5007,6 +5052,207 @@ TEST_P(EndToEndPacketReorderingTest, PathValidationFailure) {
server_thread_->Resume();
}
+TEST_P(EndToEndPacketReorderingTest, MigrateAgainAfterPathValidationFailure) {
+ ASSERT_TRUE(Initialize());
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
+ return;
+ }
+
+ client_.reset(CreateQuicClient(nullptr));
+ // Finish one request to make sure handshake established.
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+
+ // Wait for the connection to become idle, to make sure the packet gets
+ // delayed is the connectivity probing packet.
+ client_->WaitForDelayedAcks();
+
+ QuicSocketAddress addr1 = client_->client()->session()->self_address();
+ QuicConnection* client_connection = GetClientConnection();
+ QuicConnectionId server_cid1 = client_connection->connection_id();
+
+ // Migrate socket to the new IP address.
+ QuicIpAddress host2 = TestLoopback(2);
+ EXPECT_NE(addr1.host(), host2);
+
+ // Drop PATH_RESPONSE packets to timeout the path validation.
+ server_writer_->set_fake_packet_loss_percentage(100);
+ ASSERT_TRUE(
+ QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection));
+
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host2));
+
+ QuicConnectionId server_cid2 =
+ QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection);
+ EXPECT_FALSE(server_cid2.IsEmpty());
+ EXPECT_NE(server_cid2, server_cid1);
+ // Wait until path validation fails at the client.
+ while (client_->client()->HasPendingPathValidation()) {
+ EXPECT_EQ(server_cid2,
+ QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection));
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(addr1, client_->client()->session()->self_address());
+ EXPECT_EQ(server_cid1, GetClientConnection()->connection_id());
+
+ server_writer_->set_fake_packet_loss_percentage(0);
+ EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
+
+ WaitForNewConnectionIds();
+ EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(0u, client_connection->GetStats().num_new_connection_id_sent);
+
+ server_thread_->Pause();
+ QuicConnection* server_connection = GetServerConnection();
+ // Server has received 3 path challenges.
+ EXPECT_EQ(3u,
+ server_connection->GetStats().num_connectivity_probing_received);
+ EXPECT_EQ(server_cid1, server_connection->connection_id());
+ EXPECT_EQ(0u, server_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(2u, server_connection->GetStats().num_new_connection_id_sent);
+ server_thread_->Resume();
+
+ // Migrate socket to a new IP address again.
+ QuicIpAddress host3 = TestLoopback(3);
+ EXPECT_NE(addr1.host(), host3);
+ EXPECT_NE(host2, host3);
+
+ WaitForNewConnectionIds();
+ EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(0u, client_connection->GetStats().num_new_connection_id_sent);
+
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host3));
+ QuicConnectionId server_cid3 =
+ QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection);
+ EXPECT_FALSE(server_cid3.IsEmpty());
+ EXPECT_NE(server_cid1, server_cid3);
+ EXPECT_NE(server_cid2, server_cid3);
+ while (client_->client()->HasPendingPathValidation()) {
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(host3, client_->client()->session()->self_address().host());
+ EXPECT_EQ(server_cid3, GetClientConnection()->connection_id());
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
+
+ // Server should send a new connection ID to client.
+ WaitForNewConnectionIds();
+ EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(0u, client_connection->GetStats().num_new_connection_id_sent);
+}
+
+TEST_P(EndToEndPacketReorderingTest,
+ MigrateAgainAfterPathValidationFailureWithNonZeroClientConnectionId) {
+ if (!version_.SupportsClientConnectionIds()) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ override_client_connection_id_length_ = kQuicDefaultConnectionIdLength;
+ ASSERT_TRUE(Initialize());
+ if (!GetClientConnection()->connection_migration_use_new_cid()) {
+ return;
+ }
+
+ client_.reset(CreateQuicClient(nullptr));
+ // Finish one request to make sure handshake established.
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+
+ // Wait for the connection to become idle, to make sure the packet gets
+ // delayed is the connectivity probing packet.
+ client_->WaitForDelayedAcks();
+
+ QuicSocketAddress addr1 = client_->client()->session()->self_address();
+ QuicConnection* client_connection = GetClientConnection();
+ QuicConnectionId server_cid1 = client_connection->connection_id();
+ QuicConnectionId client_cid1 = client_connection->client_connection_id();
+
+ // Migrate socket to the new IP address.
+ QuicIpAddress host2 = TestLoopback(2);
+ EXPECT_NE(addr1.host(), host2);
+
+ // Drop PATH_RESPONSE packets to timeout the path validation.
+ server_writer_->set_fake_packet_loss_percentage(100);
+ ASSERT_TRUE(
+ QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection));
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host2));
+ QuicConnectionId server_cid2 =
+ QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection);
+ EXPECT_FALSE(server_cid2.IsEmpty());
+ EXPECT_NE(server_cid2, server_cid1);
+ QuicConnectionId client_cid2 =
+ QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(
+ client_connection);
+ EXPECT_FALSE(client_cid2.IsEmpty());
+ EXPECT_NE(client_cid2, client_cid1);
+ while (client_->client()->HasPendingPathValidation()) {
+ EXPECT_EQ(server_cid2,
+ QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection));
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(addr1, client_->client()->session()->self_address());
+ EXPECT_EQ(server_cid1, GetClientConnection()->connection_id());
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ server_writer_->set_fake_packet_loss_percentage(0);
+ EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
+ WaitForNewConnectionIds();
+ EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(2u, client_connection->GetStats().num_new_connection_id_sent);
+
+ server_thread_->Pause();
+ QuicConnection* server_connection = GetServerConnection();
+ if (server_connection != nullptr) {
+ EXPECT_EQ(3u,
+ server_connection->GetStats().num_connectivity_probing_received);
+ EXPECT_EQ(server_cid1, server_connection->connection_id());
+ } else {
+ ADD_FAILURE() << "Missing server connection";
+ }
+ EXPECT_EQ(1u, server_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(2u, server_connection->GetStats().num_new_connection_id_sent);
+ server_thread_->Resume();
+
+ // Migrate socket to a new IP address again.
+ QuicIpAddress host3 = TestLoopback(3);
+ EXPECT_NE(addr1.host(), host3);
+ EXPECT_NE(host2, host3);
+ ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host3));
+
+ QuicConnectionId server_cid3 =
+ QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection);
+ EXPECT_FALSE(server_cid3.IsEmpty());
+ EXPECT_NE(server_cid1, server_cid3);
+ EXPECT_NE(server_cid2, server_cid3);
+ QuicConnectionId client_cid3 =
+ QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(
+ client_connection);
+ EXPECT_NE(client_cid1, client_cid3);
+ EXPECT_NE(client_cid2, client_cid3);
+ while (client_->client()->HasPendingPathValidation()) {
+ client_->client()->WaitForEvents();
+ }
+ EXPECT_EQ(host3, client_->client()->session()->self_address().host());
+ EXPECT_EQ(server_cid3, GetClientConnection()->connection_id());
+ EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath(
+ client_connection)
+ .IsEmpty());
+ EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
+
+ // Server should send new server connection ID to client and retires old
+ // client connection ID.
+ WaitForNewConnectionIds();
+ EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent);
+ EXPECT_EQ(3u, client_connection->GetStats().num_new_connection_id_sent);
+}
+
TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
ASSERT_TRUE(Initialize());
// Finish one request to make sure handshake established.
@@ -5384,6 +5630,74 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithLoss) {
0u);
}
+// Testing packet writer that makes a copy of the first sent packets before
+// sending them. Useful for tests that need access to sent packets.
+class CopyingPacketWriter : public PacketDroppingTestWriter {
+ public:
+ explicit CopyingPacketWriter(int num_packets_to_copy)
+ : num_packets_to_copy_(num_packets_to_copy) {}
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) override {
+ if (num_packets_to_copy_ > 0) {
+ num_packets_to_copy_--;
+ packets_.push_back(
+ QuicEncryptedPacket(buffer, buf_len, /*owns_buffer=*/false).Clone());
+ }
+ return PacketDroppingTestWriter::WritePacket(buffer, buf_len, self_address,
+ peer_address, options);
+ }
+
+ std::vector<std::unique_ptr<QuicEncryptedPacket>>& packets() {
+ return packets_;
+ }
+
+ private:
+ int num_packets_to_copy_;
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_;
+};
+
+TEST_P(EndToEndTest, ChaosProtection) {
+ if (!version_.UsesCryptoFrames()) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ // Replace the client's writer with one that'll save the first packet.
+ auto copying_writer = new CopyingPacketWriter(1);
+ delete client_writer_;
+ client_writer_ = copying_writer;
+ // Enable chaos protection and perform an HTTP request.
+ client_config_.SetClientConnectionOptions(QuicTagVector{kCHSP});
+ ASSERT_TRUE(Initialize());
+ SendSynchronousFooRequestAndCheckResponse();
+ // Parse the saved packet to make sure it's valid.
+ SimpleQuicFramer validation_framer({version_});
+ validation_framer.framer()->SetInitialObfuscators(
+ GetClientConnection()->connection_id());
+ ASSERT_GT(copying_writer->packets().size(), 0u);
+ EXPECT_TRUE(validation_framer.ProcessPacket(*copying_writer->packets()[0]));
+ // TODO(dschinazi) figure out a way to use a MockRandom in this test so we
+ // can inspect the contents of this packet.
+}
+
+TEST_P(EndToEndTest, ChaosProtectionWithMultiPacketChlo) {
+ if (!version_.UsesCryptoFrames()) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ // Enable chaos protection.
+ client_config_.SetClientConnectionOptions(QuicTagVector{kCHSP});
+ // Add a transport parameter to make the client hello span multiple packets.
+ constexpr auto kCustomParameter =
+ static_cast<TransportParameters::TransportParameterId>(0xff34);
+ client_config_.custom_transport_parameters_to_send()[kCustomParameter] =
+ std::string(2000, '?');
+ ASSERT_TRUE(Initialize());
+ SendSynchronousFooRequestAndCheckResponse();
+}
+
TEST_P(EndToEndTest, KeyUpdateInitiatedByClient) {
if (!version_.UsesTls()) {
// Key Update is only supported in TLS handshake.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc
index 3544cfddf9a..6d9290a12c1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc
@@ -36,8 +36,17 @@ HttpDecoder::HttpDecoder(Visitor* visitor, Options options)
current_push_id_length_(0),
remaining_push_id_length_(0),
error_(QUIC_NO_ERROR),
- error_detail_("") {
+ error_detail_(""),
+ ignore_old_priority_update_(
+ GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)),
+ error_on_http3_push_(GetQuicReloadableFlag(quic_error_on_http3_push)) {
QUICHE_DCHECK(visitor_);
+ if (ignore_old_priority_update_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_ignore_old_priority_update_frame);
+ }
+ if (error_on_http3_push_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_error_on_http3_push);
+ }
}
HttpDecoder::~HttpDecoder() {}
@@ -172,6 +181,20 @@ bool HttpDecoder::ReadFrameType(QuicDataReader* reader) {
current_frame_type_));
return false;
}
+
+ if (error_on_http3_push_) {
+ if (current_frame_type_ ==
+ static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH)) {
+ RaiseError(QUIC_HTTP_FRAME_ERROR, "CANCEL_PUSH frame received.");
+ return false;
+ }
+ if (current_frame_type_ ==
+ static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE)) {
+ RaiseError(QUIC_HTTP_FRAME_ERROR, "PUSH_PROMISE frame received.");
+ return false;
+ }
+ }
+
state_ = STATE_READING_FRAME_LENGTH;
return true;
}
@@ -238,11 +261,19 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
visitor_->OnHeadersFrameStart(header_length, current_frame_length_);
break;
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH):
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ break;
+ }
break;
case static_cast<uint64_t>(HttpFrameType::SETTINGS):
continue_processing = visitor_->OnSettingsFrameStart(header_length);
break;
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE):
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ break;
+ }
// This edge case needs to be handled here, because ReadFramePayload()
// does not get called if |current_frame_length_| is zero.
if (current_frame_length_ == 0) {
@@ -257,7 +288,13 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID):
break;
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE):
- continue_processing = visitor_->OnPriorityUpdateFrameStart(header_length);
+ if (ignore_old_priority_update_) {
+ continue_processing = visitor_->OnUnknownFrameStart(
+ current_frame_type_, header_length, current_frame_length_);
+ } else {
+ continue_processing =
+ visitor_->OnPriorityUpdateFrameStart(header_length);
+ }
break;
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM):
continue_processing = visitor_->OnPriorityUpdateFrameStart(header_length);
@@ -307,7 +344,11 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): {
- continue_processing = BufferOrParsePayload(reader);
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ } else {
+ continue_processing = BufferOrParsePayload(reader);
+ }
break;
}
case static_cast<uint64_t>(HttpFrameType::SETTINGS): {
@@ -315,6 +356,10 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): {
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ break;
+ }
PushId push_id;
if (current_frame_length_ == remaining_frame_length_) {
// A new Push Promise frame just arrived.
@@ -388,7 +433,11 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): {
- continue_processing = BufferOrParsePayload(reader);
+ if (ignore_old_priority_update_) {
+ continue_processing = HandleUnknownFramePayload(reader);
+ } else {
+ continue_processing = BufferOrParsePayload(reader);
+ }
break;
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): {
@@ -428,9 +477,13 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ } else {
+ // If frame payload is not empty, FinishParsing() is skipped.
+ QUICHE_DCHECK_EQ(0u, current_frame_length_);
+ continue_processing = BufferOrParsePayload(reader);
+ }
break;
}
case static_cast<uint64_t>(HttpFrameType::SETTINGS): {
@@ -440,7 +493,11 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): {
- continue_processing = visitor_->OnPushPromiseFrameEnd();
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ } else {
+ continue_processing = visitor_->OnPushPromiseFrameEnd();
+ }
break;
}
case static_cast<uint64_t>(HttpFrameType::GOAWAY): {
@@ -456,9 +513,13 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ if (ignore_old_priority_update_) {
+ continue_processing = visitor_->OnUnknownFrameEnd();
+ } else {
+ // If frame payload is not empty, FinishParsing() is skipped.
+ QUICHE_DCHECK_EQ(0u, current_frame_length_);
+ continue_processing = BufferOrParsePayload(reader);
+ }
break;
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): {
@@ -559,6 +620,10 @@ bool HttpDecoder::ParseEntirePayload(QuicDataReader* reader) {
switch (current_frame_type_) {
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): {
+ if (error_on_http3_push_) {
+ QUICHE_NOTREACHED();
+ return false;
+ }
CancelPushFrame frame;
if (!reader->ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_HTTP_FRAME_ERROR,
@@ -606,11 +671,16 @@ bool HttpDecoder::ParseEntirePayload(QuicDataReader* reader) {
return visitor_->OnMaxPushIdFrame(frame);
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): {
- PriorityUpdateFrame frame;
- if (!ParsePriorityUpdateFrame(reader, &frame)) {
+ if (ignore_old_priority_update_) {
+ QUICHE_NOTREACHED();
return false;
+ } else {
+ PriorityUpdateFrame frame;
+ if (!ParsePriorityUpdateFrame(reader, &frame)) {
+ return false;
+ }
+ return visitor_->OnPriorityUpdateFrame(frame);
}
- return visitor_->OnPriorityUpdateFrame(frame);
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): {
PriorityUpdateFrame frame;
@@ -767,6 +837,7 @@ bool HttpDecoder::ParseAcceptChFrame(QuicDataReader* reader,
QuicByteCount HttpDecoder::MaxFrameLength(uint64_t frame_type) {
switch (frame_type) {
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH):
+ // TODO(b/171463363): Remove.
return sizeof(PushId);
case static_cast<uint64_t>(HttpFrameType::SETTINGS):
// This limit is arbitrary.
@@ -774,6 +845,7 @@ QuicByteCount HttpDecoder::MaxFrameLength(uint64_t frame_type) {
case static_cast<uint64_t>(HttpFrameType::GOAWAY):
return VARIABLE_LENGTH_INTEGER_LENGTH_8;
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID):
+ // TODO(b/171463363): Remove.
return sizeof(PushId);
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE):
// This limit is arbitrary.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h
index a351415e964..3a970fb63b1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h
@@ -45,6 +45,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// processed. At that point it is safe to consume |header_length| bytes.
// Called when a CANCEL_PUSH frame has been successfully parsed.
+ // TODO(b/171463363): Remove.
virtual bool OnCancelPushFrame(const CancelPushFrame& frame) = 0;
// Called when a MAX_PUSH_ID frame has been successfully parsed.
@@ -83,6 +84,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Called when a HEADERS frame has been completely processed.
virtual bool OnHeadersFrameEnd() = 0;
+ // TODO(b/171463363): Remove all.
// Called when a PUSH_PROMISE frame has been received.
virtual bool OnPushPromiseFrameStart(QuicByteCount header_length) = 0;
// Called when the Push ID field of a PUSH_PROMISE frame has been parsed.
@@ -230,7 +232,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
void BufferFrameType(QuicDataReader* reader);
// Buffers at most |remaining_push_id_length_| from |reader| to
- // |push_id_buffer_|.
+ // |push_id_buffer_|. TODO(b/171463363): Remove.
void BufferPushId(QuicDataReader* reader);
// Sets |error_| and |error_detail_| accordingly.
@@ -241,11 +243,13 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Parses the payload of a PRIORITY_UPDATE frame (draft-01, type 0x0f)
// from |reader| into |frame|.
+ // TODO(b/147306124): Remove.
bool ParsePriorityUpdateFrame(QuicDataReader* reader,
PriorityUpdateFrame* frame);
// Parses the payload of a PRIORITY_UPDATE frame (draft-02, type 0xf0700)
// from |reader| into |frame|.
+ // TODO(b/147306124): Rename to ParsePriorityUpdateFrame().
bool ParseNewPriorityUpdateFrame(QuicDataReader* reader,
PriorityUpdateFrame* frame);
@@ -276,8 +280,10 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Remaining length that's needed for the frame's type field.
QuicByteCount remaining_type_field_length_;
// Length of PUSH_PROMISE frame's push id.
+ // TODO(b/171463363): Remove.
QuicByteCount current_push_id_length_;
// Remaining length that's needed for PUSH_PROMISE frame's push id field.
+ // TODO(b/171463363): Remove.
QuicByteCount remaining_push_id_length_;
// Last error.
QuicErrorCode error_;
@@ -290,7 +296,16 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Remaining unparsed type field data.
std::array<char, sizeof(uint64_t)> type_buffer_;
// Remaining unparsed push id data.
+ // TODO(b/171463363): Remove.
std::array<char, sizeof(uint64_t)> push_id_buffer_;
+
+ // Latched value of
+ // gfe2_reloadable_flag_quic_ignore_old_priority_update_frame.
+ const bool ignore_old_priority_update_;
+
+ // Latched value of
+ // gfe2_reloadable_flag_quic_error_on_http3_push.
+ const bool error_on_http3_push_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc
index aac020a97a7..05d580e20e1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc
@@ -19,7 +19,6 @@
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using ::testing::_;
using ::testing::AnyNumber;
@@ -249,6 +248,14 @@ TEST_F(HttpDecoderTest, CancelPush) {
"01" // length
"01"); // Push Id
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ EXPECT_CALL(visitor_, OnError(&decoder_));
+ EXPECT_EQ(1u, ProcessInput(input));
+ EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR));
+ EXPECT_EQ("CANCEL_PUSH frame received.", decoder_.error_detail());
+ return;
+ }
+
// Visitor pauses processing.
EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1})))
.WillOnce(Return(false));
@@ -277,6 +284,14 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) {
"C000000000000101"), // push id 257
"Headers"); // headers
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ EXPECT_CALL(visitor_, OnError(&decoder_));
+ EXPECT_EQ(1u, ProcessInput(input));
+ EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR));
+ EXPECT_EQ("PUSH_PROMISE frame received.", decoder_.error_detail());
+ return;
+ }
+
// Visitor pauses processing.
EXPECT_CALL(visitor_, OnPushPromiseFrameStart(2)).WillOnce(Return(false));
EXPECT_CALL(visitor_, OnPushPromiseFramePushId(257, 8, 7))
@@ -338,6 +353,10 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) {
}
TEST_F(HttpDecoderTest, CorruptPushPromiseFrame) {
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
+
InSequence s;
std::string input = absl::HexStringToBytes(
@@ -733,6 +752,10 @@ TEST_F(HttpDecoderTest, EmptyHeadersFrame) {
}
TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) {
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
+
InSequence s;
std::string input = absl::HexStringToBytes(
"05" // type (PUSH_PROMISE)
@@ -768,6 +791,10 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) {
}
TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) {
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
+
std::string input = absl::HexStringToBytes(
"03" // type (CANCEL_PUSH)
"10" // length
@@ -841,97 +868,183 @@ TEST_F(HttpDecoderTest, HeadersPausedThenData) {
}
TEST_F(HttpDecoderTest, CorruptFrame) {
- InSequence s;
-
- struct {
- const char* const input;
- const char* const error_message;
- } kTestData[] = {{"\x03" // type (CANCEL_PUSH)
- "\x01" // length
- "\x40", // first byte of two-byte varint push id
- "Unable to read CANCEL_PUSH push_id."},
- {"\x03" // type (CANCEL_PUSH)
- "\x04" // length
- "\x05" // valid push id
- "foo", // superfluous data
- "Superfluous data in CANCEL_PUSH frame."},
- {"\x0D" // type (MAX_PUSH_ID)
- "\x01" // length
- "\x40", // first byte of two-byte varint push id
- "Unable to read MAX_PUSH_ID push_id."},
- {"\x0D" // type (MAX_PUSH_ID)
- "\x04" // length
- "\x05" // valid push id
- "foo", // superfluous data
- "Superfluous data in MAX_PUSH_ID frame."},
- {"\x07" // type (GOAWAY)
- "\x01" // length
- "\x40", // first byte of two-byte varint stream id
- "Unable to read GOAWAY ID."},
- {"\x07" // type (GOAWAY)
- "\x04" // length
- "\x05" // valid stream id
- "foo", // superfluous data
- "Superfluous data in GOAWAY frame."},
- {"\x40\x89" // type (ACCEPT_CH)
- "\x01" // length
- "\x40", // first byte of two-byte varint origin length
- "Unable to read ACCEPT_CH origin."},
- {"\x40\x89" // type (ACCEPT_CH)
- "\x01" // length
- "\x05", // valid origin length but no origin string
- "Unable to read ACCEPT_CH origin."},
- {"\x40\x89" // type (ACCEPT_CH)
- "\x04" // length
- "\x05" // valid origin length
- "foo", // payload ends before origin ends
- "Unable to read ACCEPT_CH origin."},
- {"\x40\x89" // type (ACCEPT_CH)
- "\x04" // length
- "\x03" // valid origin length
- "foo", // payload ends at end of origin: no value
- "Unable to read ACCEPT_CH value."},
- {"\x40\x89" // type (ACCEPT_CH)
- "\x05" // length
- "\x03" // valid origin length
- "foo" // payload ends at end of origin: no value
- "\x40", // first byte of two-byte varint value length
- "Unable to read ACCEPT_CH value."},
- {"\x40\x89" // type (ACCEPT_CH)
- "\x08" // length
- "\x03" // valid origin length
- "foo" // origin
- "\x05" // valid value length
- "bar", // payload ends before value ends
- "Unable to read ACCEPT_CH value."}};
-
- for (const auto& test_data : kTestData) {
- {
- HttpDecoder decoder(&visitor_);
- EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber());
- EXPECT_CALL(visitor_, OnError(&decoder));
-
- absl::string_view input(test_data.input);
- decoder.ProcessInput(input.data(), input.size());
- EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR));
- EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ InSequence s;
+
+ struct {
+ const char* const input;
+ const char* const error_message;
+ } kTestData[] = {{"\x0D" // type (MAX_PUSH_ID)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "Unable to read MAX_PUSH_ID push_id."},
+ {"\x0D" // type (MAX_PUSH_ID)
+ "\x04" // length
+ "\x05" // valid push id
+ "foo", // superfluous data
+ "Superfluous data in MAX_PUSH_ID frame."},
+ {"\x07" // type (GOAWAY)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint stream id
+ "Unable to read GOAWAY ID."},
+ {"\x07" // type (GOAWAY)
+ "\x04" // length
+ "\x05" // valid stream id
+ "foo", // superfluous data
+ "Superfluous data in GOAWAY frame."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint origin length
+ "Unable to read ACCEPT_CH origin."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x01" // length
+ "\x05", // valid origin length but no origin string
+ "Unable to read ACCEPT_CH origin."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x04" // length
+ "\x05" // valid origin length
+ "foo", // payload ends before origin ends
+ "Unable to read ACCEPT_CH origin."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x04" // length
+ "\x03" // valid origin length
+ "foo", // payload ends at end of origin: no value
+ "Unable to read ACCEPT_CH value."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x05" // length
+ "\x03" // valid origin length
+ "foo" // payload ends at end of origin: no value
+ "\x40", // first byte of two-byte varint value length
+ "Unable to read ACCEPT_CH value."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x08" // length
+ "\x03" // valid origin length
+ "foo" // origin
+ "\x05" // valid value length
+ "bar", // payload ends before value ends
+ "Unable to read ACCEPT_CH value."}};
+
+ for (const auto& test_data : kTestData) {
+ {
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ absl::string_view input(test_data.input);
+ decoder.ProcessInput(input.data(), input.size());
+ EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR));
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
+ {
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ absl::string_view input(test_data.input);
+ for (auto c : input) {
+ decoder.ProcessInput(&c, 1);
+ }
+ EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR));
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
}
- {
- HttpDecoder decoder(&visitor_);
- EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber());
- EXPECT_CALL(visitor_, OnError(&decoder));
-
- absl::string_view input(test_data.input);
- for (auto c : input) {
- decoder.ProcessInput(&c, 1);
+ } else {
+ InSequence s;
+
+ struct {
+ const char* const input;
+ const char* const error_message;
+ } kTestData[] = {{"\x03" // type (CANCEL_PUSH)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "Unable to read CANCEL_PUSH push_id."},
+ {"\x03" // type (CANCEL_PUSH)
+ "\x04" // length
+ "\x05" // valid push id
+ "foo", // superfluous data
+ "Superfluous data in CANCEL_PUSH frame."},
+ {"\x0D" // type (MAX_PUSH_ID)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "Unable to read MAX_PUSH_ID push_id."},
+ {"\x0D" // type (MAX_PUSH_ID)
+ "\x04" // length
+ "\x05" // valid push id
+ "foo", // superfluous data
+ "Superfluous data in MAX_PUSH_ID frame."},
+ {"\x07" // type (GOAWAY)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint stream id
+ "Unable to read GOAWAY ID."},
+ {"\x07" // type (GOAWAY)
+ "\x04" // length
+ "\x05" // valid stream id
+ "foo", // superfluous data
+ "Superfluous data in GOAWAY frame."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint origin length
+ "Unable to read ACCEPT_CH origin."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x01" // length
+ "\x05", // valid origin length but no origin string
+ "Unable to read ACCEPT_CH origin."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x04" // length
+ "\x05" // valid origin length
+ "foo", // payload ends before origin ends
+ "Unable to read ACCEPT_CH origin."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x04" // length
+ "\x03" // valid origin length
+ "foo", // payload ends at end of origin: no value
+ "Unable to read ACCEPT_CH value."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x05" // length
+ "\x03" // valid origin length
+ "foo" // payload ends at end of origin: no value
+ "\x40", // first byte of two-byte varint value length
+ "Unable to read ACCEPT_CH value."},
+ {"\x40\x89" // type (ACCEPT_CH)
+ "\x08" // length
+ "\x03" // valid origin length
+ "foo" // origin
+ "\x05" // valid value length
+ "bar", // payload ends before value ends
+ "Unable to read ACCEPT_CH value."}};
+
+ for (const auto& test_data : kTestData) {
+ {
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ absl::string_view input(test_data.input);
+ decoder.ProcessInput(input.data(), input.size());
+ EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR));
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
+ {
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ absl::string_view input(test_data.input);
+ for (auto c : input) {
+ decoder.ProcessInput(&c, 1);
+ }
+ EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR));
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
}
- EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR));
- EXPECT_EQ(test_data.error_message, decoder.error_detail());
}
}
}
TEST_F(HttpDecoderTest, EmptyCancelPushFrame) {
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
+
std::string input = absl::HexStringToBytes(
"03" // type (CANCEL_PUSH)
"00"); // frame length
@@ -959,6 +1072,10 @@ TEST_F(HttpDecoderTest, EmptySettingsFrame) {
// Regression test for https://crbug.com/1001823.
TEST_F(HttpDecoderTest, EmptyPushPromiseFrame) {
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
+
std::string input = absl::HexStringToBytes(
"05" // type (PUSH_PROMISE)
"00"); // frame length
@@ -1003,7 +1120,11 @@ TEST_F(HttpDecoderTest, LargeStreamIdInGoAway) {
EXPECT_EQ("", decoder_.error_detail());
}
-TEST_F(HttpDecoderTest, PriorityUpdateFrame) {
+TEST_F(HttpDecoderTest, OldPriorityUpdateFrame) {
+ if (GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)) {
+ return;
+ }
+
InSequence s;
std::string input1 = absl::HexStringToBytes(
"0f" // type (PRIORITY_UPDATE)
@@ -1085,7 +1206,44 @@ TEST_F(HttpDecoderTest, PriorityUpdateFrame) {
EXPECT_EQ("", decoder_.error_detail());
}
-TEST_F(HttpDecoderTest, NewPriorityUpdateFrame) {
+TEST_F(HttpDecoderTest, ObsoletePriorityUpdateFrame) {
+ if (!GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)) {
+ return;
+ }
+
+ const QuicByteCount header_length = 2;
+ const QuicByteCount payload_length = 3;
+ InSequence s;
+ std::string input = absl::HexStringToBytes(
+ "0f" // type (obsolete PRIORITY_UPDATE)
+ "03" // length
+ "666f6f"); // payload "foo"
+
+ // Process frame as a whole.
+ EXPECT_CALL(visitor_,
+ OnUnknownFrameStart(0x0f, header_length, payload_length));
+ EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("foo")));
+ EXPECT_CALL(visitor_, OnUnknownFrameEnd()).WillOnce(Return(false));
+
+ EXPECT_EQ(header_length + payload_length,
+ ProcessInputWithGarbageAppended(input));
+ EXPECT_THAT(decoder_.error(), IsQuicNoError());
+ EXPECT_EQ("", decoder_.error_detail());
+
+ // Process frame byte by byte.
+ EXPECT_CALL(visitor_,
+ OnUnknownFrameStart(0x0f, header_length, payload_length));
+ EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("f")));
+ EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("o")));
+ EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("o")));
+ EXPECT_CALL(visitor_, OnUnknownFrameEnd());
+
+ ProcessInputCharByChar(input);
+ EXPECT_THAT(decoder_.error(), IsQuicNoError());
+ EXPECT_EQ("", decoder_.error_detail());
+}
+
+TEST_F(HttpDecoderTest, PriorityUpdateFrame) {
InSequence s;
std::string input1 = absl::HexStringToBytes(
"800f0700" // type (PRIORITY_UPDATE)
@@ -1166,6 +1324,10 @@ TEST_F(HttpDecoderTest, NewPriorityUpdateFrame) {
}
TEST_F(HttpDecoderTest, CorruptPriorityUpdateFrame) {
+ if (GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)) {
+ return;
+ }
+
std::string payload1 = absl::HexStringToBytes(
"80" // prioritized element type: PUSH_STREAM
"4005"); // prioritized element id
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h
index 56e53487b24..b14ebe5a91b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h
@@ -29,6 +29,7 @@ enum class HttpFrameType {
GOAWAY = 0x7,
MAX_PUSH_ID = 0xD,
// https://tools.ietf.org/html/draft-ietf-httpbis-priority-01
+ // TODO(b/147306124): Remove.
PRIORITY_UPDATE = 0XF,
// https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02
ACCEPT_CH = 0x89,
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h
index 9ddf6de8a84..01c861d5905 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h
@@ -11,9 +11,9 @@
#include <utility>
#include "absl/strings/string_view.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_export.h"
+#include "common/quiche_circular_deque.h"
#include "spdy/core/spdy_header_block.h"
#include "spdy/core/spdy_headers_handler_interface.h"
@@ -23,7 +23,8 @@ namespace quic {
class QUIC_EXPORT_PRIVATE QuicHeaderList
: public spdy::SpdyHeadersHandlerInterface {
public:
- using ListType = QuicCircularDeque<std::pair<std::string, std::string>>;
+ using ListType =
+ quiche::QuicheCircularDeque<std::pair<std::string, std::string>>;
using value_type = ListType::value_type;
using const_iterator = ListType::const_iterator;
@@ -59,7 +60,7 @@ class QUIC_EXPORT_PRIVATE QuicHeaderList
std::string DebugString() const;
private:
- QuicCircularDeque<std::pair<std::string, std::string>> header_list_;
+ quiche::QuicheCircularDeque<std::pair<std::string, std::string>> header_list_;
// The limit on the size of the header list (defined by spec as name + value +
// overhead for each header field). Headers over this limit will not be
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h
index ae9e2afe0d1..153575be1de 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h
@@ -91,7 +91,7 @@ class QUIC_EXPORT_PRIVATE QuicHeadersStream : public QuicStream {
QuicSpdySession* spdy_session_;
// Headers that have not been fully acked.
- QuicCircularDeque<CompressedHeaderInfo> unacked_headers_;
+ quiche::QuicheCircularDeque<CompressedHeaderInfo> unacked_headers_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc
index 55dafac3756..42fef63c978 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc
@@ -563,6 +563,10 @@ TEST_P(QuicHeadersStreamTest, ProcessPriorityFrame) {
}
TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) {
+ if (perspective() != Perspective::IS_CLIENT) {
+ return;
+ }
+
session_.OnConfigNegotiated();
SpdySettingsIR data;
// Respect supported settings frames SETTINGS_ENABLE_PUSH.
@@ -570,15 +574,11 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) {
SpdySerializedFrame frame(framer_->SerializeFrame(data));
stream_frame_.data_buffer = frame.data();
stream_frame_.data_length = frame.size();
- if (perspective() == Perspective::IS_CLIENT) {
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Unsupported field of HTTP/2 SETTINGS frame: 2", _));
- }
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: 2", _));
headers_stream_->OnStreamFrame(stream_frame_);
- EXPECT_EQ(session_.server_push_enabled(),
- perspective() == Perspective::IS_CLIENT);
}
TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc
index fbd7b2eb18e..39d8b42a5a2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc
@@ -15,7 +15,7 @@
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
@@ -70,7 +70,6 @@ bool QuicReceiveControlStream::OnCancelPushFrame(const CancelPushFrame& frame) {
spdy_session()->debug_visitor()->OnCancelPushFrameReceived(frame);
}
- // TODO(b/151841240): Handle CANCEL_PUSH frames instead of ignoring them.
return ValidateFrameType(HttpFrameType::CANCEL_PUSH);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc
index c9133436e9f..03f21d8a70f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc
@@ -15,7 +15,6 @@
#include "quic/test_tools/quic_spdy_session_peer.h"
#include "quic/test_tools/quic_stream_peer.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
@@ -165,7 +164,7 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) {
QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data);
QpackEncoder* qpack_encoder = session_.qpack_encoder();
- QpackHeaderTable* header_table =
+ QpackEncoderHeaderTable* header_table =
QpackEncoderPeer::header_table(qpack_encoder);
EXPECT_EQ(std::numeric_limits<size_t>::max(),
session_.max_outbound_header_list_size());
@@ -311,7 +310,10 @@ TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) {
push_promise_frame);
EXPECT_CALL(
*connection_,
- CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _))
+ CloseConnection(GetQuicReloadableFlag(quic_error_on_http3_push)
+ ? QUIC_HTTP_FRAME_ERROR
+ : QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM,
+ _, _))
.WillOnce(
Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _));
@@ -382,13 +384,21 @@ TEST_P(QuicReceiveControlStreamTest, CancelPushFrameBeforeSettings) {
"01" // payload length
"01"); // push ID
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_HTTP_MISSING_SETTINGS_FRAME,
- "First frame received on control stream is type "
- "3, but it must be SETTINGS.",
- _))
- .WillOnce(
- Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR,
+ "CANCEL_PUSH frame received.", _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ } else {
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_MISSING_SETTINGS_FRAME,
+ "First frame received on control stream is type "
+ "3, but it must be SETTINGS.",
+ _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ }
EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _));
EXPECT_CALL(session_, OnConnectionClosed(_, _));
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc
index d1be0df27ca..c5af1dc4a90 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc
@@ -13,7 +13,6 @@
#include "quic/test_tools/quic_config_peer.h"
#include "quic/test_tools/quic_spdy_session_peer.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
index b955835e2b8..c78df58e18a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
@@ -50,12 +50,6 @@ void QuicServerSessionBase::OnConfigNegotiated() {
return;
}
- // Disable server push if peer sends the corresponding connection option.
- if (!version().UsesHttp3() &&
- ContainsQuicTag(config()->ReceivedConnectionOptions(), kQNSP)) {
- OnSetting(spdy::SETTINGS_ENABLE_PUSH, 0);
- }
-
// Enable bandwidth resumption if peer sent correct connection options.
const bool last_bandwidth_resumption =
ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc
index 29750f2e3cf..ac7fc1e59c8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc
@@ -10,7 +10,6 @@
#include <utility>
#include "absl/memory/memory.h"
-#include "absl/strings/string_view.h"
#include "quic/core/crypto/null_encrypter.h"
#include "quic/core/crypto/quic_crypto_server_config.h"
#include "quic/core/crypto/quic_random.h"
@@ -51,6 +50,12 @@ namespace quic {
namespace test {
namespace {
+// Data to be sent on a request stream. In Google QUIC, this is interpreted as
+// DATA payload (there is no framing on request streams). In IETF QUIC, this is
+// interpreted as HEADERS frame (type 0x1) with payload length 122 ('z'). Since
+// no payload is included, QPACK decoder will not be invoked.
+const char* const kStreamData = "\1z";
+
class TestServerSession : public QuicServerSessionBase {
public:
TestServerSession(const QuicConfig& config,
@@ -148,7 +153,7 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> {
config_.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
- ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam());
+ ParsedQuicVersionVector supported_versions = SupportedVersions(version());
connection_ = new StrictMock<MockQuicConnection>(
&helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions);
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -166,23 +171,24 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_->config(), kMinimumFlowControlSendWindow);
session_->OnConfigNegotiated();
- if (connection_->version().SupportsAntiAmplificationLimit()) {
+ if (version().SupportsAntiAmplificationLimit()) {
QuicConnectionPeer::SetAddressValidated(connection_);
}
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
- return GetNthClientInitiatedBidirectionalStreamId(
- connection_->transport_version(), n);
+ return GetNthClientInitiatedBidirectionalStreamId(transport_version(), n);
}
QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
return quic::test::GetNthServerInitiatedUnidirectionalStreamId(
- connection_->transport_version(), n);
+ transport_version(), n);
}
+ ParsedQuicVersion version() const { return GetParam(); }
+
QuicTransportVersion transport_version() const {
- return connection_->transport_version();
+ return version().transport_version;
}
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
@@ -242,10 +248,9 @@ INSTANTIATE_TEST_SUITE_P(Tests,
::testing::PrintToStringParamName());
TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
- // Open a stream, then reset it.
- // Send two bytes of payload to open it.
+ // Send some data open a stream, then reset it.
QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
- absl::string_view("HT"));
+ kStreamData);
session_->OnStreamFrame(data1);
EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
@@ -298,9 +303,9 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) {
InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0));
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
- // Send two bytes of payload.
+
QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
- absl::string_view("HT"));
+ kStreamData);
session_->OnStreamFrame(data1);
// The stream should never be opened, now that the reset is received.
@@ -309,11 +314,11 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) {
}
TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
- // Send (empty) compressed headers followed by two bytes of data.
+ // Send some data to open two streams.
QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0,
- absl::string_view("\1\0\0\0\0\0\0\0HT"));
+ kStreamData);
QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0,
- absl::string_view("\3\0\0\0\0\0\0\0HT"));
+ kStreamData);
session_->OnStreamFrame(frame1);
session_->OnStreamFrame(frame2);
EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
@@ -341,9 +346,9 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
// past the reset point of stream 3. As it's a closed stream we just drop the
// data on the floor, but accept the packet because it has data for stream 5.
QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, 2,
- absl::string_view("TP"));
+ kStreamData);
QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2,
- absl::string_view("TP"));
+ kStreamData);
session_->OnStreamFrame(frame3);
session_->OnStreamFrame(frame4);
// The stream should never be opened, now that the reset is received.
@@ -373,7 +378,7 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(session_.get(),
stream_id));
- stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
}
if (!VersionHasIetfQuicFrames(transport_version())) {
@@ -382,11 +387,11 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) {
EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(session_.get(),
stream_id));
- stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
}
}
// Now violate the server's internal stream limit.
- stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
if (!VersionHasIetfQuicFrames(transport_version())) {
// For non-version 99, QUIC responds to an attempt to exceed the stream
@@ -418,8 +423,7 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) {
session_.get(), GetNthClientInitiatedBidirectionalId(0)));
// Establish available streams up to the server's limit.
- QuicStreamId next_id =
- QuicUtils::StreamIdDelta(connection_->transport_version());
+ QuicStreamId next_id = QuicUtils::StreamIdDelta(transport_version());
const int kLimitingStreamId =
GetNthClientInitiatedBidirectionalId(kAvailableStreamLimit + 1);
if (!VersionHasIetfQuicFrames(transport_version())) {
@@ -456,7 +460,7 @@ TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) {
// EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
- if (GetParam() != AllSupportedVersions()[0]) {
+ if (version() != AllSupportedVersions()[0]) {
return;
}
@@ -527,14 +531,13 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
if (!VersionUsesHttp3(transport_version())) {
session_->UnregisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ QuicUtils::GetHeadersStreamId(transport_version()),
/*is_static=*/true);
}
QuicServerSessionBasePeer::SetCryptoStream(session_.get(), nullptr);
MockQuicCryptoServerStream* quic_crypto_stream = nullptr;
MockTlsServerHandshaker* tls_server_stream = nullptr;
- if (session_->connection()->version().handshake_protocol ==
- PROTOCOL_QUIC_CRYPTO) {
+ if (version().handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
quic_crypto_stream = new MockQuicCryptoServerStream(
&crypto_config_, &compressed_certs_cache_, session_.get(),
&stream_helper_);
@@ -548,7 +551,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
}
if (!VersionUsesHttp3(transport_version())) {
session_->RegisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ QuicUtils::GetHeadersStreamId(transport_version()),
/*is_static=*/true,
spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
}
@@ -571,11 +574,11 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
// Queue up some pending data.
if (!VersionUsesHttp3(transport_version())) {
session_->MarkConnectionLevelWriteBlocked(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()));
+ QuicUtils::GetHeadersStreamId(transport_version()));
} else {
session_->MarkConnectionLevelWriteBlocked(
- QuicUtils::GetFirstUnidirectionalStreamId(
- connection_->transport_version(), Perspective::IS_SERVER));
+ QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
+ Perspective::IS_SERVER));
}
EXPECT_TRUE(session_->HasDataToWrite());
@@ -643,7 +646,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
}
TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) {
- if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ if (version().handshake_protocol == PROTOCOL_TLS1_3) {
// This test relies on resumption, which is not currently supported by the
// TLS handshake.
// TODO(nharper): Add support for resumption to the TLS handshake.
@@ -720,20 +723,6 @@ TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) {
QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
}
-TEST_P(QuicServerSessionBaseTest, TurnOffServerPush) {
- if (session_->version().UsesHttp3()) {
- return;
- }
-
- EXPECT_TRUE(session_->server_push_enabled());
- QuicTagVector copt;
- copt.push_back(kQNSP);
- QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- session_->OnConfigNegotiated();
- EXPECT_FALSE(session_->server_push_enabled());
-}
-
// Tests which check the lifetime management of data members of
// QuicCryptoServerStream objects when async GetProof is in use.
class StreamMemberLifetimeTest : public QuicServerSessionBaseTest {
@@ -762,7 +751,7 @@ INSTANTIATE_TEST_SUITE_P(StreamMemberLifetimeTests,
// ProofSource::GetProof. Delay the completion of the operation until after the
// stream has been destroyed, and verify that there are no memory bugs.
TEST_P(StreamMemberLifetimeTest, Basic) {
- if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ if (version().handshake_protocol == PROTOCOL_TLS1_3) {
// This test depends on the QUIC crypto protocol, so it is disabled for the
// TLS handshake.
// TODO(nharper): Fix this test so it doesn't rely on QUIC crypto.
@@ -771,9 +760,9 @@ TEST_P(StreamMemberLifetimeTest, Basic) {
const QuicClock* clock = helper_.GetClock();
CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO(
- clock, GetParam().transport_version, &crypto_config_);
+ clock, transport_version(), &crypto_config_);
chlo.SetVector(kCOPT, QuicTagVector{kREJ});
- std::vector<ParsedQuicVersion> packet_version_list = {GetParam()};
+ std::vector<ParsedQuicVersion> packet_version_list = {version()};
std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
TestConnectionId(1), EmptyQuicConnectionId(), true, false, 1,
std::string(chlo.GetSerialized().AsStringPiece()), CONNECTION_ID_PRESENT,
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
index 7197c8ab7ed..af17b54ecff 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
@@ -278,10 +278,11 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
EXPECT_TRUE(session_->CreateOutgoingBidirectionalStream() == nullptr);
// Verify that no data may be send on existing streams.
char data[] = "hello world";
- EXPECT_QUIC_BUG(
+ QuicConsumedData consumed =
session_->WritevData(stream->id(), ABSL_ARRAYSIZE(data), 0, NO_FIN,
- NOT_RETRANSMISSION, ENCRYPTION_INITIAL),
- "Client: Try to send data of stream");
+ NOT_RETRANSMISSION, ENCRYPTION_INITIAL);
+ EXPECT_EQ(0u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
}
TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc
index 16948101c6c..276a7aff6b6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc
@@ -30,7 +30,6 @@
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_stack_trace.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "spdy/core/http2_frame_decoder_adapter.h"
using http2::Http2DecoderAdapter;
@@ -497,7 +496,6 @@ QuicSpdySession::QuicSpdySession(
spdy_framer_visitor_(new SpdyFramerVisitor(this)),
debug_visitor_(nullptr),
destruction_indicator_(123456789),
- server_push_enabled_(true),
next_available_datagram_flow_id_(perspective() == Perspective::IS_SERVER
? kFirstDatagramFlowIdServer
: kFirstDatagramFlowIdClient) {
@@ -798,15 +796,12 @@ void QuicSpdySession::SendHttp3GoAway(QuicErrorCode error_code,
const std::string& reason) {
QUICHE_DCHECK_EQ(perspective(), Perspective::IS_SERVER);
QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
- if (GetQuicReloadableFlag(quic_encrypted_goaway)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_encrypted_goaway, 2, 2);
- if (!IsEncryptionEstablished()) {
- QUIC_CODE_COUNT(quic_h3_goaway_before_encryption_established);
- connection()->CloseConnection(
- error_code, reason,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
+ if (!IsEncryptionEstablished()) {
+ QUIC_CODE_COUNT(quic_h3_goaway_before_encryption_established);
+ connection()->CloseConnection(
+ error_code, reason,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
}
QuicStreamId stream_id;
@@ -858,10 +853,6 @@ void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
absl::string_view(frame.data(), frame.size()), false, nullptr);
}
-bool QuicSpdySession::server_push_enabled() const {
- return VersionUsesHttp3(transport_version()) ? false : server_push_enabled_;
-}
-
void QuicSpdySession::SendInitialData() {
if (!VersionUsesHttp3(transport_version())) {
return;
@@ -1239,8 +1230,7 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
return true;
}
QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_ENABLE_PUSH received with value "
- << value;
- server_push_enabled_ = value;
+ << value << ", ignoring.";
break;
} else {
QUIC_DLOG(ERROR)
@@ -1458,14 +1448,7 @@ QuicStream* QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
default:
break;
}
- if (GetQuicReloadableFlag(quic_unify_stop_sending)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_unify_stop_sending);
- MaybeSendStopSendingFrame(pending->id(), QUIC_STREAM_STREAM_CREATION_ERROR);
- } else {
- // TODO(renjietang): deprecate SendStopSending() when the flag is
- // deprecated.
- SendStopSending(QUIC_STREAM_STREAM_CREATION_ERROR, pending->id());
- }
+ MaybeSendStopSendingFrame(pending->id(), QUIC_STREAM_STREAM_CREATION_ERROR);
pending->StopReading();
return nullptr;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h
index b2004845306..214d1da13e2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h
@@ -26,13 +26,13 @@
#include "quic/core/qpack/qpack_encoder_stream_sender.h"
#include "quic/core/qpack/qpack_receive_stream.h"
#include "quic/core/qpack/qpack_send_stream.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_session.h"
#include "quic/core/quic_time.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_containers.h"
#include "quic/platform/api/quic_export.h"
+#include "common/quiche_circular_deque.h"
#include "spdy/core/http2_frame_decoder_adapter.h"
namespace quic {
@@ -251,12 +251,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
const QuicHeadersStream* headers_stream() const { return headers_stream_; }
- // Returns whether server push is enabled.
- // For a Google QUIC client this always returns false.
- // For a Google QUIC server this is set by incoming SETTINGS_ENABLE_PUSH.
- // For an IETF QUIC client or server this returns false.
- bool server_push_enabled() const;
-
// Called when the control stream receives HTTP/3 SETTINGS.
// Returns false in case of 0-RTT if received settings are incompatible with
// cached values, true otherwise.
@@ -684,10 +678,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// an use-after-free.
int32_t destruction_indicator_;
- // Used in Google QUIC only. Set every time SETTINGS_ENABLE_PUSH is received.
- // Defaults to true.
- bool server_push_enabled_;
-
// The identifier in the most recently received GOAWAY frame. Unset if no
// GOAWAY frame has been received yet.
absl::optional<uint64_t> last_received_http3_goaway_id_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
index d8bfa782aa7..29e1f6b7bcd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
@@ -38,7 +38,6 @@
#include "quic/platform/api/quic_map_util.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_encoder_peer.h"
-#include "quic/test_tools/qpack/qpack_header_table_peer.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
#include "quic/test_tools/quic_config_peer.h"
#include "quic/test_tools/quic_connection_peer.h"
@@ -48,7 +47,6 @@
#include "quic/test_tools/quic_stream_peer.h"
#include "quic/test_tools/quic_stream_send_buffer_peer.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/quiche_endian.h"
#include "common/test_tools/quiche_test_utils.h"
#include "spdy/core/spdy_framer.h"
@@ -559,7 +557,6 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
}
void ReceiveWebTransportSession(WebTransportSessionId session_id) {
- SetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin, true);
QuicStreamFrame frame(session_id, /*fin=*/false, /*offset=*/0,
absl::string_view());
session_.OnStreamFrame(frame);
@@ -1178,7 +1175,6 @@ TEST_P(QuicSpdySessionTestServer, SendGoAway) {
}
TEST_P(QuicSpdySessionTestServer, SendGoAwayWithoutEncryption) {
- SetQuicReloadableFlag(quic_encrypted_goaway, true);
if (VersionHasIetfQuicFrames(transport_version())) {
// HTTP/3 GOAWAY has different semantic and thus has its own test.
return;
@@ -1220,7 +1216,6 @@ TEST_P(QuicSpdySessionTestServer, SendHttp3GoAway) {
}
TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayWithoutEncryption) {
- SetQuicReloadableFlag(quic_encrypted_goaway, true);
if (!VersionUsesHttp3(transport_version())) {
return;
}
@@ -1918,12 +1913,6 @@ TEST_P(QuicSpdySessionTestClient, BadStreamFramePendingStream) {
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
// A bad stream frame with no data and no fin.
QuicStreamFrame data1(stream_id1, false, 0, 0);
- if (!GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin)) {
- EXPECT_CALL(*connection_, CloseConnection(_, _, _))
- .WillOnce(
- Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
- EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _));
- }
session_.OnStreamFrame(data1);
}
@@ -2519,19 +2508,17 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) {
QuicStreamFrame frame(stream_id, false, 1, absl::string_view(data));
QpackEncoder* qpack_encoder = session_.qpack_encoder();
- QpackHeaderTable* header_table =
+ QpackEncoderHeaderTable* header_table =
QpackEncoderPeer::header_table(qpack_encoder);
- EXPECT_NE(512u,
- QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table));
+ EXPECT_NE(512u, header_table->maximum_dynamic_table_capacity());
EXPECT_NE(5u, session_.max_outbound_header_list_size());
EXPECT_NE(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings));
session_.OnStreamFrame(frame);
- EXPECT_EQ(512u,
- QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table));
+ EXPECT_EQ(512u, header_table->maximum_dynamic_table_capacity());
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
EXPECT_EQ(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
}
@@ -2618,10 +2605,10 @@ TEST_P(QuicSpdySessionTestServer, SessionDestroyedWhileHeaderDecodingBlocked) {
EXPECT_FALSE(stream->headers_decompressed());
// |session_| gets destoyed. That destroys QpackDecoder, a member of
- // QuicSpdySession (derived class), which destroys QpackHeaderTable.
+ // QuicSpdySession (derived class), which destroys QpackDecoderHeaderTable.
// Then |*stream|, owned by QuicSession (base class) get destroyed, which
- // destroys QpackProgessiveDecoder, a registered Observer of QpackHeaderTable.
- // This must not cause a crash.
+ // destroys QpackProgessiveDecoder, a registered Observer of
+ // QpackDecoderHeaderTable. This must not cause a crash.
}
TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) {
@@ -2897,10 +2884,7 @@ TEST_P(QuicSpdySessionTestClient, Http3GoAwayLargerIdThanBefore) {
session_.OnHttp3GoAway(stream_id2);
}
-// Test that receipt of CANCEL_PUSH frame does not result in closing the
-// connection.
-// TODO(b/151841240): Handle CANCEL_PUSH frames instead of ignoring them.
-TEST_P(QuicSpdySessionTestClient, IgnoreCancelPush) {
+TEST_P(QuicSpdySessionTestClient, CloseConnectionOnCancelPush) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
@@ -2937,16 +2921,19 @@ TEST_P(QuicSpdySessionTestClient, IgnoreCancelPush) {
"00"); // push ID
QuicStreamFrame data3(receive_control_stream_id, /* fin = */ false, offset,
cancel_push_frame);
- EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_));
- session_.OnStreamFrame(data3);
-}
-
-TEST_P(QuicSpdySessionTestServer, ServerPushEnabledDefaultValue) {
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_FALSE(session_.server_push_enabled());
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR,
+ "CANCEL_PUSH frame received.", _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ EXPECT_CALL(*connection_,
+ SendConnectionClosePacket(QUIC_HTTP_FRAME_ERROR, _,
+ "CANCEL_PUSH frame received."));
} else {
- EXPECT_TRUE(session_.server_push_enabled());
+ // CANCEL_PUSH is ignored.
+ EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_));
}
+ session_.OnStreamFrame(data3);
}
TEST_P(QuicSpdySessionTestServer, OnSetting) {
@@ -2964,7 +2951,7 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) {
session_.OnSetting(SETTINGS_QPACK_BLOCKED_STREAMS, 12);
EXPECT_EQ(12u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
- QpackHeaderTable* header_table =
+ QpackEncoderHeaderTable* header_table =
QpackEncoderPeer::header_table(qpack_encoder);
EXPECT_EQ(0u, header_table->maximum_dynamic_table_capacity());
session_.OnSetting(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 37);
@@ -2978,10 +2965,6 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) {
session_.OnSetting(SETTINGS_MAX_FIELD_SECTION_SIZE, 5);
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
- EXPECT_TRUE(session_.server_push_enabled());
- session_.OnSetting(spdy::SETTINGS_ENABLE_PUSH, 0);
- EXPECT_FALSE(session_.server_push_enabled());
-
spdy::HpackEncoder* hpack_encoder =
QuicSpdySessionPeer::GetSpdyFramer(&session_)->GetHpackEncoder();
EXPECT_EQ(4096u, hpack_encoder->CurrentHeaderTableSizeSetting());
@@ -3108,10 +3091,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
session_.OnStopSendingFrame(stop_sending_encoder_stream);
}
-// Test that receipt of CANCEL_PUSH frame does not result in closing the
-// connection.
-// TODO(b/151841240): Handle CANCEL_PUSH frames instead of ignoring them.
-TEST_P(QuicSpdySessionTestServer, IgnoreCancelPush) {
+TEST_P(QuicSpdySessionTestServer, CloseConnectionOnCancelPush) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
@@ -3148,7 +3128,18 @@ TEST_P(QuicSpdySessionTestServer, IgnoreCancelPush) {
"00"); // push ID
QuicStreamFrame data3(receive_control_stream_id, /* fin = */ false, offset,
cancel_push_frame);
- EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_));
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR,
+ "CANCEL_PUSH frame received.", _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ EXPECT_CALL(*connection_,
+ SendConnectionClosePacket(QUIC_HTTP_FRAME_ERROR, _,
+ "CANCEL_PUSH frame received."));
+ } else {
+ // CANCEL_PUSH is ignored.
+ EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_));
+ }
session_.OnStreamFrame(data3);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
index 4d4cc95f94d..6ec48ca5896 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
@@ -30,7 +30,7 @@
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_mem_slice_storage.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
#include "spdy/core/spdy_protocol.h"
using spdy::SpdyHeaderBlock;
@@ -434,7 +434,12 @@ QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices,
QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection());
// Write frame header.
+#if !defined(__ANDROID__)
struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length};
+#else
+ struct iovec header_iov = {static_cast<void*>(buffer.get()),
+ static_cast<__kernel_size_t>(header_length)};
+#endif
QuicMemSliceStorage storage(
&header_iov, 1,
spdy_session_->connection()->helper()->GetStreamSendBufferAllocator(),
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h
index 7b2d9f19186..f34801a383c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h
@@ -7,11 +7,11 @@
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_constants.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_iovec.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -84,7 +84,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyManager {
QuicByteCount trailing_non_body_byte_count;
};
// Queue of body fragments and trailing non-body byte counts.
- QuicCircularDeque<Fragment> fragments_;
+ quiche::QuicheCircularDeque<Fragment> fragments_;
// Total body bytes received.
QuicByteCount total_body_bytes_received_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc
index bb464bdb4d5..8b814b8400b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc
@@ -2772,6 +2772,9 @@ TEST_P(QuicSpdyStreamIncrementalConsumptionTest, UnknownFramesInterleaved) {
// TODO(b/171463363): Remove.
TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) {
Initialize(kShouldProcessData);
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
if (!UsesHttp3()) {
return;
}
@@ -2802,6 +2805,9 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) {
TEST_P(QuicSpdyStreamTest,
OnStreamHeaderBlockArgumentDoesNotIncludePushedHeaderBlock) {
Initialize(kShouldProcessData);
+ if (GetQuicReloadableFlag(quic_error_on_http3_push)) {
+ return;
+ }
if (!UsesHttp3()) {
return;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc
index d3a3c92d209..28b463afebe 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc
@@ -17,7 +17,7 @@
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_map_util.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
#include "spdy/core/spdy_protocol.h"
using spdy::SpdyHeaderBlock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc
index c7207f383b3..7307665da3d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc
@@ -9,7 +9,6 @@
#include "absl/strings/string_view.h"
#include "quic/core/http/spdy_utils.h"
#include "quic/platform/api/quic_test.h"
-#include "common/platform/api/quiche_text_utils.h"
using spdy::SpdyHeaderBlock;
using testing::Pair;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h
index 0c91c2b32a4..667256ea515 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h
@@ -75,8 +75,8 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3
bool ready_ = false;
std::unique_ptr<WebTransportVisitor> visitor_;
absl::flat_hash_set<QuicStreamId> streams_;
- QuicCircularDeque<QuicStreamId> incoming_bidirectional_streams_;
- QuicCircularDeque<QuicStreamId> incoming_unidirectional_streams_;
+ quiche::QuicheCircularDeque<QuicStreamId> incoming_bidirectional_streams_;
+ quiche::QuicheCircularDeque<QuicStreamId> incoming_unidirectional_streams_;
};
class QUIC_EXPORT_PRIVATE WebTransportHttp3UnidirectionalStream
diff --git a/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h b/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h
index b83916060e9..8e80c7de4b7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h
+++ b/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h
@@ -5,11 +5,11 @@
#ifndef QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
#define QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_constants.h"
#include "quic/core/quic_packet_number.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_bug_tracker.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -115,7 +115,7 @@ class QUIC_NO_EXPORT PacketNumberIndexedQueue {
return const_cast<EntryWrapper*>(const_this->GetEntryWrapper(offset));
}
- QuicCircularDeque<EntryWrapper> entries_;
+ quiche::QuicheCircularDeque<EntryWrapper> entries_;
// NOTE(wub): When --quic_bw_sampler_remove_packets_once_per_congestion_event
// is enabled, |number_of_present_entries_| only represents number of holes,
// which does not include number of acked or lost packets.
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
index 70870a60314..4188350e463 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
@@ -75,8 +75,8 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager {
// A stream typically has only one header block, except for the rare cases of
// 1xx responses, trailers, or push promises. Even if there are multiple
// header blocks sent on a single stream, they might not be blocked at the
- // same time. Use std::list instead of QuicCircularDeque because it has lower
- // memory footprint when holding few elements.
+ // same time. Use std::list instead of quiche::QuicheCircularDeque because it
+ // has lower memory footprint when holding few elements.
using HeaderBlocksForStream = std::list<IndexSet>;
using HeaderBlocks = absl::flat_hash_map<QuicStreamId, HeaderBlocksForStream>;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
index 9ba7f1c511f..217f866dce1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
@@ -12,7 +12,6 @@
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_decoder_test_utils.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using ::testing::_;
using ::testing::ElementsAre;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
index 32178bd9d7c..b947ce3cf0e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
@@ -111,7 +111,7 @@ class QUIC_EXPORT_PRIVATE QpackDecoder
EncoderStreamErrorDelegate* const encoder_stream_error_delegate_;
QpackEncoderStreamReceiver encoder_stream_receiver_;
QpackDecoderStreamSender decoder_stream_sender_;
- QpackHeaderTable header_table_;
+ QpackDecoderHeaderTable header_table_;
std::set<QuicStreamId> blocked_streams_;
const uint64_t maximum_blocked_streams_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
index 272597ac191..0a76a17450f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
@@ -7,7 +7,6 @@
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "quic/platform/api/quic_test.h"
-#include "common/platform/api/quiche_text_utils.h"
using testing::Eq;
using testing::StrictMock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index 275e76f3ca1..708e7a3d3f1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -7,7 +7,6 @@
#include "absl/strings/escaping.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using ::testing::Eq;
using ::testing::StrictMock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
index 3b57ca6f1c3..772b1d25480 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
@@ -13,7 +13,6 @@
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_decoder_test_utils.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "spdy/core/spdy_header_block.h"
using ::testing::_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
index 5e61ee7490b..3ae944152c0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
@@ -122,7 +122,7 @@ QpackEncoder::Representations QpackEncoder::FirstPassEncode(
header_table_.FindHeaderField(name, value, &is_static, &index);
switch (match_type) {
- case QpackHeaderTable::MatchType::kNameAndValue:
+ case QpackEncoderHeaderTable::MatchType::kNameAndValue:
if (is_static) {
// Refer to entry directly.
representations.push_back(
@@ -175,7 +175,7 @@ QpackEncoder::Representations QpackEncoder::FirstPassEncode(
break;
- case QpackHeaderTable::MatchType::kName:
+ case QpackEncoderHeaderTable::MatchType::kName:
if (is_static) {
if (blocking_allowed &&
QpackEntry::Size(name, value) <=
@@ -242,7 +242,7 @@ QpackEncoder::Representations QpackEncoder::FirstPassEncode(
break;
- case QpackHeaderTable::MatchType::kNoMatch:
+ case QpackEncoderHeaderTable::MatchType::kNoMatch:
// If allowed, insert entry and refer to it.
if (!blocking_allowed) {
blocked_stream_limit_exhausted = true;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
index 9d024417c93..c3d77fea061 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
@@ -153,7 +153,7 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
DecoderStreamErrorDelegate* const decoder_stream_error_delegate_;
QpackDecoderStreamReceiver decoder_stream_receiver_;
QpackEncoderStreamSender encoder_stream_sender_;
- QpackHeaderTable header_table_;
+ QpackEncoderHeaderTable header_table_;
uint64_t maximum_blocked_streams_;
QpackBlockingManager blocking_manager_;
int header_list_count_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
index efe5eb90b98..2fa440b51b4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
@@ -7,7 +7,6 @@
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "quic/platform/api/quic_test.h"
-#include "common/platform/api/quiche_text_utils.h"
using testing::Eq;
using testing::StrictMock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 5078c8f0d05..98e3e23030f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -7,7 +7,6 @@
#include "absl/strings/escaping.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using ::testing::Eq;
using ::testing::StrictMock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
index 5045c8fb350..21397ed8571 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
@@ -14,9 +14,7 @@
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_encoder_peer.h"
#include "quic/test_tools/qpack/qpack_encoder_test_utils.h"
-#include "quic/test_tools/qpack/qpack_header_table_peer.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using ::testing::_;
using ::testing::Eq;
@@ -186,7 +184,8 @@ TEST_F(QpackEncoderTest, TooLargeInsertCountIncrement) {
// Regression test for https://crbug.com/1014372.
TEST_F(QpackEncoderTest, InsertCountIncrementOverflow) {
- QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_);
+ QpackEncoderHeaderTable* header_table =
+ QpackEncoderPeer::header_table(&encoder_);
// Set dynamic table capacity large enough to hold one entry.
header_table->SetMaximumDynamicTableCapacity(4096);
@@ -461,11 +460,11 @@ TEST_F(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) {
encoder_.SetMaximumDynamicTableCapacity(1024);
encoder_.SetDynamicTableCapacity(30);
- QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_);
+ QpackEncoderHeaderTable* header_table =
+ QpackEncoderPeer::header_table(&encoder_);
- EXPECT_EQ(1024u,
- QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table));
- EXPECT_EQ(30u, QpackHeaderTablePeer::dynamic_table_capacity(header_table));
+ EXPECT_EQ(1024u, header_table->maximum_dynamic_table_capacity());
+ EXPECT_EQ(30u, header_table->dynamic_table_capacity());
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
index da3636db4e4..660727231d6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
@@ -10,47 +10,47 @@
namespace quic {
-QpackHeaderTable::QpackHeaderTable()
- : static_entries_(ObtainQpackStaticTable().GetStaticEntries()),
- static_index_(ObtainQpackStaticTable().GetStaticIndex()),
- static_name_index_(ObtainQpackStaticTable().GetStaticNameIndex()),
- dynamic_table_size_(0),
- dynamic_table_capacity_(0),
- maximum_dynamic_table_capacity_(0),
- max_entries_(0),
- dropped_entry_count_(0),
- dynamic_table_entry_referenced_(false) {}
-
-QpackHeaderTable::~QpackHeaderTable() {
- for (auto& entry : observers_) {
- entry.second->Cancel();
- }
-}
+QpackEncoderHeaderTable::QpackEncoderHeaderTable()
+ : static_index_(ObtainQpackStaticTable().GetStaticIndex()),
+ static_name_index_(ObtainQpackStaticTable().GetStaticNameIndex()) {}
-const QpackEntry* QpackHeaderTable::LookupEntry(bool is_static,
- uint64_t index) const {
- if (is_static) {
- if (index >= static_entries_.size()) {
- return nullptr;
- }
+uint64_t QpackEncoderHeaderTable::InsertEntry(absl::string_view name,
+ absl::string_view value) {
+ const uint64_t index =
+ QpackHeaderTableBase<QpackEncoderDynamicTable>::InsertEntry(name, value);
- return &static_entries_[index];
- }
+ // Make name and value point to the new entry.
+ name = dynamic_entries().back().name();
+ value = dynamic_entries().back().value();
- if (index < dropped_entry_count_) {
- return nullptr;
+ auto index_result = dynamic_index_.insert(
+ std::make_pair(QpackLookupEntry{name, value}, index));
+ if (!index_result.second) {
+ // An entry with the same name and value already exists. It needs to be
+ // replaced, because |dynamic_index_| tracks the most recent entry for a
+ // given name and value.
+ QUICHE_DCHECK_GT(index, index_result.first->second);
+ dynamic_index_.erase(index_result.first);
+ auto result = dynamic_index_.insert(
+ std::make_pair(QpackLookupEntry{name, value}, index));
+ QUICHE_CHECK(result.second);
}
- index -= dropped_entry_count_;
-
- if (index >= dynamic_entries_.size()) {
- return nullptr;
+ auto name_result = dynamic_name_index_.insert({name, index});
+ if (!name_result.second) {
+ // An entry with the same name already exists. It needs to be replaced,
+ // because |dynamic_name_index_| tracks the most recent entry for a given
+ // name.
+ QUICHE_DCHECK_GT(index, name_result.first->second);
+ dynamic_name_index_.erase(name_result.first);
+ auto result = dynamic_name_index_.insert({name, index});
+ QUICHE_CHECK(result.second);
}
- return &dynamic_entries_[index];
+ return index;
}
-QpackHeaderTable::MatchType QpackHeaderTable::FindHeaderField(
+QpackEncoderHeaderTable::MatchType QpackEncoderHeaderTable::FindHeaderField(
absl::string_view name,
absl::string_view value,
bool* is_static,
@@ -92,56 +92,92 @@ QpackHeaderTable::MatchType QpackHeaderTable::FindHeaderField(
return MatchType::kNoMatch;
}
-bool QpackHeaderTable::EntryFitsDynamicTableCapacity(
- absl::string_view name,
- absl::string_view value) const {
- return QpackEntry::Size(name, value) <= dynamic_table_capacity_;
+uint64_t QpackEncoderHeaderTable::MaxInsertSizeWithoutEvictingGivenEntry(
+ uint64_t index) const {
+ QUICHE_DCHECK_LE(dropped_entry_count(), index);
+
+ if (index > inserted_entry_count()) {
+ // All entries are allowed to be evicted.
+ return dynamic_table_capacity();
+ }
+
+ // Initialize to current available capacity.
+ uint64_t max_insert_size = dynamic_table_capacity() - dynamic_table_size();
+
+ uint64_t entry_index = dropped_entry_count();
+ for (const auto& entry : dynamic_entries()) {
+ if (entry_index >= index) {
+ break;
+ }
+ ++entry_index;
+ max_insert_size += entry.Size();
+ }
+
+ return max_insert_size;
}
-uint64_t QpackHeaderTable::InsertEntry(absl::string_view name,
- absl::string_view value) {
- QUICHE_DCHECK(EntryFitsDynamicTableCapacity(name, value));
+uint64_t QpackEncoderHeaderTable::draining_index(
+ float draining_fraction) const {
+ QUICHE_DCHECK_LE(0.0, draining_fraction);
+ QUICHE_DCHECK_LE(draining_fraction, 1.0);
- const uint64_t index = dropped_entry_count_ + dynamic_entries_.size();
+ const uint64_t required_space = draining_fraction * dynamic_table_capacity();
+ uint64_t space_above_draining_index =
+ dynamic_table_capacity() - dynamic_table_size();
- // Copy name and value before modifying the container, because evicting
- // entries or even inserting a new one might invalidate |name| or |value| if
- // they point to an entry.
- QpackEntry new_entry((std::string(name)), (std::string(value)));
- const size_t entry_size = new_entry.Size();
+ if (dynamic_entries().empty() ||
+ space_above_draining_index >= required_space) {
+ return dropped_entry_count();
+ }
- EvictDownToCapacity(dynamic_table_capacity_ - entry_size);
+ auto it = dynamic_entries().begin();
+ uint64_t entry_index = dropped_entry_count();
+ while (space_above_draining_index < required_space) {
+ space_above_draining_index += it->Size();
+ ++it;
+ ++entry_index;
+ if (it == dynamic_entries().end()) {
+ return inserted_entry_count();
+ }
+ }
- dynamic_table_size_ += entry_size;
- dynamic_entries_.push_back(std::move(new_entry));
+ return entry_index;
+}
- // Make name and value point to the new entry.
- name = dynamic_entries_.back().name();
- value = dynamic_entries_.back().value();
+void QpackEncoderHeaderTable::RemoveEntryFromEnd() {
+ const QpackEntry* const entry = &dynamic_entries().front();
+ const uint64_t index = dropped_entry_count();
- auto index_result = dynamic_index_.insert(
- std::make_pair(QpackLookupEntry{name, value}, index));
- if (!index_result.second) {
- // An entry with the same name and value already exists. It needs to be
- // replaced, because |dynamic_index_| tracks the most recent entry for a
- // given name and value.
- QUICHE_DCHECK_GT(index, index_result.first->second);
- dynamic_index_.erase(index_result.first);
- auto result = dynamic_index_.insert(
- std::make_pair(QpackLookupEntry{name, value}, index));
- QUICHE_CHECK(result.second);
+ auto index_it = dynamic_index_.find({entry->name(), entry->value()});
+ // Remove |dynamic_index_| entry only if it points to the same
+ // QpackEntry in dynamic_entries().
+ if (index_it != dynamic_index_.end() && index_it->second == index) {
+ dynamic_index_.erase(index_it);
}
- auto name_result = dynamic_name_index_.insert({name, index});
- if (!name_result.second) {
- // An entry with the same name already exists. It needs to be replaced,
- // because |dynamic_name_index_| tracks the most recent entry for a given
- // name.
- QUICHE_DCHECK_GT(index, name_result.first->second);
- dynamic_name_index_.erase(name_result.first);
- auto result = dynamic_name_index_.insert({name, index});
- QUICHE_CHECK(result.second);
+ auto name_it = dynamic_name_index_.find(entry->name());
+ // Remove |dynamic_name_index_| entry only if it points to the same
+ // QpackEntry in dynamic_entries().
+ if (name_it != dynamic_name_index_.end() && name_it->second == index) {
+ dynamic_name_index_.erase(name_it);
+ }
+
+ QpackHeaderTableBase<QpackEncoderDynamicTable>::RemoveEntryFromEnd();
+}
+
+QpackDecoderHeaderTable::QpackDecoderHeaderTable()
+ : static_entries_(ObtainQpackStaticTable().GetStaticEntries()) {}
+
+QpackDecoderHeaderTable::~QpackDecoderHeaderTable() {
+ for (auto& entry : observers_) {
+ entry.second->Cancel();
}
+}
+
+uint64_t QpackDecoderHeaderTable::InsertEntry(absl::string_view name,
+ absl::string_view value) {
+ const uint64_t index =
+ QpackHeaderTableBase<QpackDecoderDynamicTable>::InsertEntry(name, value);
// Notify and deregister observers whose threshold is met, if any.
while (!observers_.empty()) {
@@ -157,62 +193,37 @@ uint64_t QpackHeaderTable::InsertEntry(absl::string_view name,
return index;
}
-uint64_t QpackHeaderTable::MaxInsertSizeWithoutEvictingGivenEntry(
- uint64_t index) const {
- QUICHE_DCHECK_LE(dropped_entry_count_, index);
+const QpackEntry* QpackDecoderHeaderTable::LookupEntry(bool is_static,
+ uint64_t index) const {
+ if (is_static) {
+ if (index >= static_entries_.size()) {
+ return nullptr;
+ }
- if (index > inserted_entry_count()) {
- // All entries are allowed to be evicted.
- return dynamic_table_capacity_;
+ return &static_entries_[index];
}
- // Initialize to current available capacity.
- uint64_t max_insert_size = dynamic_table_capacity_ - dynamic_table_size_;
-
- uint64_t entry_index = dropped_entry_count_;
- for (const auto& entry : dynamic_entries_) {
- if (entry_index >= index) {
- break;
- }
- ++entry_index;
- max_insert_size += entry.Size();
+ if (index < dropped_entry_count()) {
+ return nullptr;
}
- return max_insert_size;
-}
+ index -= dropped_entry_count();
-bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) {
- if (capacity > maximum_dynamic_table_capacity_) {
- return false;
+ if (index >= dynamic_entries().size()) {
+ return nullptr;
}
- dynamic_table_capacity_ = capacity;
- EvictDownToCapacity(capacity);
-
- QUICHE_DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_);
-
- return true;
-}
-
-bool QpackHeaderTable::SetMaximumDynamicTableCapacity(
- uint64_t maximum_dynamic_table_capacity) {
- 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_;
+ return &dynamic_entries()[index];
}
-void QpackHeaderTable::RegisterObserver(uint64_t required_insert_count,
- Observer* observer) {
+void QpackDecoderHeaderTable::RegisterObserver(uint64_t required_insert_count,
+ Observer* observer) {
QUICHE_DCHECK_GT(required_insert_count, 0u);
observers_.insert({required_insert_count, observer});
}
-void QpackHeaderTable::UnregisterObserver(uint64_t required_insert_count,
- Observer* observer) {
+void QpackDecoderHeaderTable::UnregisterObserver(uint64_t required_insert_count,
+ Observer* observer) {
auto it = observers_.lower_bound(required_insert_count);
while (it != observers_.end() && it->first == required_insert_count) {
if (it->second == observer) {
@@ -226,62 +237,4 @@ void QpackHeaderTable::UnregisterObserver(uint64_t required_insert_count,
QUIC_NOTREACHED();
}
-uint64_t QpackHeaderTable::draining_index(float draining_fraction) const {
- QUICHE_DCHECK_LE(0.0, draining_fraction);
- QUICHE_DCHECK_LE(draining_fraction, 1.0);
-
- const uint64_t required_space = draining_fraction * dynamic_table_capacity_;
- uint64_t space_above_draining_index =
- dynamic_table_capacity_ - dynamic_table_size_;
-
- if (dynamic_entries_.empty() ||
- space_above_draining_index >= required_space) {
- return dropped_entry_count_;
- }
-
- auto it = dynamic_entries_.begin();
- uint64_t entry_index = dropped_entry_count_;
- while (space_above_draining_index < required_space) {
- space_above_draining_index += it->Size();
- ++it;
- ++entry_index;
- if (it == dynamic_entries_.end()) {
- return inserted_entry_count();
- }
- }
-
- return entry_index;
-}
-
-void QpackHeaderTable::EvictDownToCapacity(uint64_t capacity) {
- while (dynamic_table_size_ > capacity) {
- QUICHE_DCHECK(!dynamic_entries_.empty());
-
- QpackEntry* const entry = &dynamic_entries_.front();
-
- const uint64_t entry_size = entry->Size();
- QUICHE_DCHECK_GE(dynamic_table_size_, entry_size);
- dynamic_table_size_ -= entry_size;
-
- const uint64_t index = dropped_entry_count_;
-
- auto index_it = dynamic_index_.find({entry->name(), entry->value()});
- // Remove |dynamic_index_| entry only if it points to the same
- // QpackEntry in |dynamic_entries_|.
- if (index_it != dynamic_index_.end() && index_it->second == index) {
- dynamic_index_.erase(index_it);
- }
-
- auto name_it = dynamic_name_index_.find(entry->name());
- // Remove |dynamic_name_index_| entry only if it points to the same
- // QpackEntry in |dynamic_entries_|.
- if (name_it != dynamic_name_index_.end() && name_it->second == index) {
- dynamic_name_index_.erase(name_it);
- }
-
- dynamic_entries_.pop_front();
- ++dropped_entry_count_;
- }
-}
-
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
index a5d6c5d74b8..7193d102294 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
@@ -6,75 +6,41 @@
#define QUICHE_QUIC_CORE_QPACK_QPACK_HEADER_TABLE_H_
#include <cstdint>
-#include <functional>
-#include <queue>
-#include <vector>
+#include <deque>
#include "absl/strings/string_view.h"
#include "quic/platform/api/quic_export.h"
+#include "common/quiche_circular_deque.h"
#include "spdy/core/hpack/hpack_entry.h"
#include "spdy/core/hpack/hpack_header_table.h"
namespace quic {
-namespace test {
-
-class QpackHeaderTablePeer;
-
-} // namespace test
-
using QpackEntry = spdy::HpackEntry;
using QpackLookupEntry = spdy::HpackLookupEntry;
constexpr size_t kQpackEntrySizeOverhead = spdy::kHpackEntrySizeOverhead;
-// This class manages the QPACK static and dynamic tables. For dynamic entries,
-// it only has a concept of absolute indices. The caller needs to perform the
-// necessary transformations to and from relative indices and post-base indices.
-class QUIC_EXPORT_PRIVATE QpackHeaderTable {
+// Encoder needs pointer stability for |dynamic_index_| and
+// |dynamic_name_index_|. However, it does not need random access.
+// TODO(b/182349990): Change to a more memory efficient container.
+using QpackEncoderDynamicTable = std::deque<QpackEntry>;
+
+// Decoder needs random access for LookupEntry().
+// However, it does not need pointer stability.
+using QpackDecoderDynamicTable = quiche::QuicheCircularDeque<QpackEntry>;
+
+// This is a base class for encoder and decoder classes that manage the QPACK
+// static and dynamic tables. For dynamic entries, it only has a concept of
+// absolute indices. The caller needs to perform the necessary transformations
+// to and from relative indices and post-base indices.
+template <typename DynamicEntryTable>
+class QUIC_EXPORT_PRIVATE QpackHeaderTableBase {
public:
- using StaticEntryTable = spdy::HpackHeaderTable::StaticEntryTable;
- using DynamicEntryTable = spdy::HpackHeaderTable::DynamicEntryTable;
- using NameValueToEntryMap = spdy::HpackHeaderTable::NameValueToEntryMap;
- using NameToEntryMap = spdy::HpackHeaderTable::NameToEntryMap;
+ QpackHeaderTableBase();
+ QpackHeaderTableBase(const QpackHeaderTableBase&) = delete;
+ QpackHeaderTableBase& operator=(const QpackHeaderTableBase&) = delete;
- // Result of header table lookup.
- enum class MatchType { kNameAndValue, kName, kNoMatch };
-
- // Observer interface for dynamic table insertion.
- class QUIC_EXPORT_PRIVATE Observer {
- public:
- virtual ~Observer() = default;
-
- // Called when inserted_entry_count() reaches the threshold the Observer was
- // registered with. After this call the Observer automatically gets
- // deregistered.
- virtual void OnInsertCountReachedThreshold() = 0;
-
- // Called when QpackHeaderTable is destroyed to let the Observer know that
- // it must not call UnregisterObserver().
- virtual void Cancel() = 0;
- };
-
- QpackHeaderTable();
- QpackHeaderTable(const QpackHeaderTable&) = delete;
- QpackHeaderTable& operator=(const QpackHeaderTable&) = delete;
-
- ~QpackHeaderTable();
-
- // Returns the entry at absolute index |index| from the static or dynamic
- // table according to |is_static|. |index| is zero based for both the static
- // and the dynamic table. The returned pointer is valid until the entry is
- // evicted, even if other entries are inserted into the dynamic table.
- // Returns nullptr if entry does not exist.
- const QpackEntry* LookupEntry(bool is_static, uint64_t index) const;
-
- // Returns the absolute index of an entry with matching name and value if such
- // exists, otherwise one with matching name is such exists. |index| is zero
- // based for both the static and the dynamic table.
- MatchType FindHeaderField(absl::string_view name,
- absl::string_view value,
- bool* is_static,
- uint64_t* index) const;
+ virtual ~QpackHeaderTableBase() = default;
// Returns whether an entry with |name| and |value| has a size (including
// overhead) that is smaller than or equal to the capacity of the dynamic
@@ -89,13 +55,7 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// the underlying container might move entries around when resizing for
// insertion.
// Returns the absolute index of the inserted dynamic table entry.
- uint64_t InsertEntry(absl::string_view name, absl::string_view value);
-
- // Returns the size of the largest entry that could be inserted into the
- // dynamic table without evicting entry |index|. |index| might be larger than
- // inserted_entry_count(), in which case the capacity of the table is
- // returned. |index| must not be smaller than dropped_entry_count().
- uint64_t MaxInsertSizeWithoutEvictingGivenEntry(uint64_t index) const;
+ virtual uint64_t InsertEntry(absl::string_view name, absl::string_view value);
// Change dynamic table capacity to |capacity|. Returns true on success.
// Returns false is |capacity| exceeds maximum dynamic table capacity.
@@ -112,24 +72,11 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// returning false.
bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
- // Get |maximum_dynamic_table_capacity_|.
+ uint64_t dynamic_table_size() const { return dynamic_table_size_; }
+ uint64_t dynamic_table_capacity() const { return dynamic_table_capacity_; }
uint64_t maximum_dynamic_table_capacity() const {
return maximum_dynamic_table_capacity_;
}
-
- // Register an observer to be notified when inserted_entry_count() reaches
- // |required_insert_count|. After the notification, |observer| automatically
- // gets unregistered. Each observer must only be registered at most once.
- void RegisterObserver(uint64_t required_insert_count, Observer* observer);
-
- // Unregister previously registered observer. Must be called with the same
- // |required_insert_count| value that |observer| was registered with. Must be
- // called before an observer still waiting for notification is destroyed,
- // unless QpackHeaderTable already called Observer::Cancel(), in which case
- // this method must not be called.
- void UnregisterObserver(uint64_t required_insert_count, Observer* observer);
-
- // Used on request streams to encode and decode Required Insert Count.
uint64_t max_entries() const { return max_entries_; }
// The number of entries inserted to the dynamic table (including ones that
@@ -141,14 +88,6 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// The number of entries dropped from the dynamic table.
uint64_t dropped_entry_count() const { return dropped_entry_count_; }
- // Returns the draining index described at
- // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#avoiding-blocked-insertions.
- // Entries with an index larger than or equal to the draining index take up
- // approximately |1.0 - draining_fraction| of dynamic table capacity. The
- // remaining capacity is taken up by draining entries and unused space.
- // The returned index might not be the index of a valid entry.
- uint64_t draining_index(float draining_fraction) const;
-
void set_dynamic_table_entry_referenced() {
dynamic_table_entry_referenced_ = true;
}
@@ -156,20 +95,178 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
return dynamic_table_entry_referenced_;
}
- private:
- friend class test::QpackHeaderTablePeer;
+ protected:
+ // Removes a single entry from the end of the dynamic table, updates
+ // |dynamic_table_size_| and |dropped_entry_count_|.
+ virtual void RemoveEntryFromEnd();
+ const DynamicEntryTable& dynamic_entries() const { return dynamic_entries_; }
+
+ private:
// Evict entries from the dynamic table until table size is less than or equal
// to |capacity|.
void EvictDownToCapacity(uint64_t capacity);
- // Static Table
+ // Dynamic Table entries.
+ DynamicEntryTable dynamic_entries_;
- // |static_entries_|, |static_index_|, |static_name_index_| are owned by
- // QpackStaticTable singleton.
+ // Size of the dynamic table. This is the sum of the size of its entries.
+ uint64_t dynamic_table_size_;
- // Tracks QpackEntries by index.
- const StaticEntryTable& static_entries_;
+ // Dynamic Table Capacity is the maximum allowed value of
+ // |dynamic_table_size_|. Entries are evicted if necessary before inserting a
+ // new entry to ensure that dynamic table size never exceeds capacity.
+ // Initial value is |maximum_dynamic_table_capacity_|. Capacity can be
+ // changed by the encoder, as long as it does not exceed
+ // |maximum_dynamic_table_capacity_|.
+ uint64_t dynamic_table_capacity_;
+
+ // Maximum allowed value of |dynamic_table_capacity|. The initial value is
+ // zero. Can be changed by SetMaximumDynamicTableCapacity().
+ uint64_t maximum_dynamic_table_capacity_;
+
+ // MaxEntries, see Section 3.2.2. Calculated based on
+ // |maximum_dynamic_table_capacity_|. Used on request streams to encode and
+ // decode Required Insert Count.
+ uint64_t max_entries_;
+
+ // The number of entries dropped from the dynamic table.
+ uint64_t dropped_entry_count_;
+
+ // True if any dynamic table entries have been referenced from a header block.
+ // Set directly by the encoder or decoder. Used for stats.
+ bool dynamic_table_entry_referenced_;
+};
+
+template <typename DynamicEntryTable>
+QpackHeaderTableBase<DynamicEntryTable>::QpackHeaderTableBase()
+ : dynamic_table_size_(0),
+ dynamic_table_capacity_(0),
+ maximum_dynamic_table_capacity_(0),
+ max_entries_(0),
+ dropped_entry_count_(0),
+ dynamic_table_entry_referenced_(false) {}
+
+template <typename DynamicEntryTable>
+bool QpackHeaderTableBase<DynamicEntryTable>::EntryFitsDynamicTableCapacity(
+ absl::string_view name,
+ absl::string_view value) const {
+ return QpackEntry::Size(name, value) <= dynamic_table_capacity_;
+}
+
+template <typename DynamicEntryTable>
+uint64_t QpackHeaderTableBase<DynamicEntryTable>::InsertEntry(
+ absl::string_view name,
+ absl::string_view value) {
+ QUICHE_DCHECK(EntryFitsDynamicTableCapacity(name, value));
+
+ const uint64_t index = dropped_entry_count_ + dynamic_entries_.size();
+
+ // Copy name and value before modifying the container, because evicting
+ // entries or even inserting a new one might invalidate |name| or |value| if
+ // they point to an entry.
+ QpackEntry new_entry((std::string(name)), (std::string(value)));
+ const size_t entry_size = new_entry.Size();
+
+ EvictDownToCapacity(dynamic_table_capacity_ - entry_size);
+
+ dynamic_table_size_ += entry_size;
+ dynamic_entries_.push_back(std::move(new_entry));
+
+ return index;
+}
+
+template <typename DynamicEntryTable>
+bool QpackHeaderTableBase<DynamicEntryTable>::SetDynamicTableCapacity(
+ uint64_t capacity) {
+ if (capacity > maximum_dynamic_table_capacity_) {
+ return false;
+ }
+
+ dynamic_table_capacity_ = capacity;
+ EvictDownToCapacity(capacity);
+
+ QUICHE_DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_);
+
+ return true;
+}
+
+template <typename DynamicEntryTable>
+bool QpackHeaderTableBase<DynamicEntryTable>::SetMaximumDynamicTableCapacity(
+ uint64_t maximum_dynamic_table_capacity) {
+ 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_;
+}
+
+template <typename DynamicEntryTable>
+void QpackHeaderTableBase<DynamicEntryTable>::RemoveEntryFromEnd() {
+ const uint64_t entry_size = dynamic_entries_.front().Size();
+ QUICHE_DCHECK_GE(dynamic_table_size_, entry_size);
+ dynamic_table_size_ -= entry_size;
+
+ dynamic_entries_.pop_front();
+ ++dropped_entry_count_;
+}
+
+template <typename DynamicEntryTable>
+void QpackHeaderTableBase<DynamicEntryTable>::EvictDownToCapacity(
+ uint64_t capacity) {
+ while (dynamic_table_size_ > capacity) {
+ QUICHE_DCHECK(!dynamic_entries_.empty());
+ RemoveEntryFromEnd();
+ }
+}
+
+class QUIC_EXPORT_PRIVATE QpackEncoderHeaderTable
+ : public QpackHeaderTableBase<QpackEncoderDynamicTable> {
+ public:
+ // Result of header table lookup.
+ enum class MatchType { kNameAndValue, kName, kNoMatch };
+
+ QpackEncoderHeaderTable();
+ ~QpackEncoderHeaderTable() override = default;
+
+ uint64_t InsertEntry(absl::string_view name,
+ absl::string_view value) override;
+
+ // Returns the absolute index of an entry with matching name and value if such
+ // exists, otherwise one with matching name is such exists. |index| is zero
+ // based for both the static and the dynamic table.
+ MatchType FindHeaderField(absl::string_view name,
+ absl::string_view value,
+ bool* is_static,
+ uint64_t* index) const;
+
+ // Returns the size of the largest entry that could be inserted into the
+ // dynamic table without evicting entry |index|. |index| might be larger than
+ // inserted_entry_count(), in which case the capacity of the table is
+ // returned. |index| must not be smaller than dropped_entry_count().
+ uint64_t MaxInsertSizeWithoutEvictingGivenEntry(uint64_t index) const;
+
+ // Returns the draining index described at
+ // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#avoiding-blocked-insertions.
+ // Entries with an index larger than or equal to the draining index take up
+ // approximately |1.0 - draining_fraction| of dynamic table capacity. The
+ // remaining capacity is taken up by draining entries and unused space.
+ // The returned index might not be the index of a valid entry.
+ uint64_t draining_index(float draining_fraction) const;
+
+ protected:
+ void RemoveEntryFromEnd() override;
+
+ private:
+ using NameValueToEntryMap = spdy::HpackHeaderTable::NameValueToEntryMap;
+ using NameToEntryMap = spdy::HpackHeaderTable::NameToEntryMap;
+
+ // Static Table
+
+ // |static_index_| and |static_name_index_| are owned by QpackStaticTable
+ // singleton.
// Tracks the unique static entry for a given header name and value.
const NameValueToEntryMap& static_index_;
@@ -179,49 +276,69 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// Dynamic Table
- // Queue of dynamic table entries, for lookup by index.
- // |dynamic_entries_| owns the entries in the dynamic table.
- DynamicEntryTable dynamic_entries_;
-
// An unordered set of QpackEntry pointers with a comparison operator that
// only cares about name and value. This allows fast lookup of the most
// recently inserted dynamic entry for a given header name and value pair.
- // Entries point to entries owned by |dynamic_entries_|.
+ // Entries point to entries owned by |QpackHeaderTableBase::dynamic_entries_|.
NameValueToEntryMap dynamic_index_;
// An unordered map of QpackEntry pointers keyed off header name. This allows
// fast lookup of the most recently inserted dynamic entry for a given header
- // name. Entries point to entries owned by |dynamic_entries_|.
+ // name. Entries point to entries owned by
+ // |QpackHeaderTableBase::dynamic_entries_|.
NameToEntryMap dynamic_name_index_;
+};
- // Size of the dynamic table. This is the sum of the size of its entries.
- uint64_t dynamic_table_size_;
+class QUIC_EXPORT_PRIVATE QpackDecoderHeaderTable
+ : public QpackHeaderTableBase<QpackDecoderDynamicTable> {
+ public:
+ // Observer interface for dynamic table insertion.
+ class QUIC_EXPORT_PRIVATE Observer {
+ public:
+ virtual ~Observer() = default;
- // Dynamic Table Capacity is the maximum allowed value of
- // |dynamic_table_size_|. Entries are evicted if necessary before inserting a
- // new entry to ensure that dynamic table size never exceeds capacity.
- // Initial value is |maximum_dynamic_table_capacity_|. Capacity can be
- // changed by the encoder, as long as it does not exceed
- // |maximum_dynamic_table_capacity_|.
- uint64_t dynamic_table_capacity_;
+ // Called when inserted_entry_count() reaches the threshold the Observer was
+ // registered with. After this call the Observer automatically gets
+ // deregistered.
+ virtual void OnInsertCountReachedThreshold() = 0;
- // Maximum allowed value of |dynamic_table_capacity|. The initial value is
- // zero. Can be changed by SetMaximumDynamicTableCapacity().
- uint64_t maximum_dynamic_table_capacity_;
+ // Called when QpackDecoderHeaderTable is destroyed to let the Observer know
+ // that it must not call UnregisterObserver().
+ virtual void Cancel() = 0;
+ };
- // MaxEntries, see Section 3.2.2. Calculated based on
- // |maximum_dynamic_table_capacity_|.
- uint64_t max_entries_;
+ QpackDecoderHeaderTable();
+ ~QpackDecoderHeaderTable() override;
- // The number of entries dropped from the dynamic table.
- uint64_t dropped_entry_count_;
+ uint64_t InsertEntry(absl::string_view name,
+ absl::string_view value) override;
+
+ // Returns the entry at absolute index |index| from the static or dynamic
+ // table according to |is_static|. |index| is zero based for both the static
+ // and the dynamic table. The returned pointer is valid until the entry is
+ // evicted, even if other entries are inserted into the dynamic table.
+ // Returns nullptr if entry does not exist.
+ const QpackEntry* LookupEntry(bool is_static, uint64_t index) const;
+
+ // Register an observer to be notified when inserted_entry_count() reaches
+ // |required_insert_count|. After the notification, |observer| automatically
+ // gets unregistered. Each observer must only be registered at most once.
+ void RegisterObserver(uint64_t required_insert_count, Observer* observer);
+
+ // Unregister previously registered observer. Must be called with the same
+ // |required_insert_count| value that |observer| was registered with. Must be
+ // called before an observer still waiting for notification is destroyed,
+ // unless QpackDecoderHeaderTable already called Observer::Cancel(), in which
+ // case this method must not be called.
+ void UnregisterObserver(uint64_t required_insert_count, Observer* observer);
+
+ private:
+ // Static Table entries. Owned by QpackStaticTable singleton.
+ using StaticEntryTable = spdy::HpackHeaderTable::StaticEntryTable;
+ const StaticEntryTable& static_entries_;
// Observers waiting to be notified, sorted by required insert count.
std::multimap<uint64_t, Observer*> observers_;
-
- // True if any dynamic table entries have been referenced from a header block.
- // Set directly by the encoder or decoder. Used for stats.
- bool dynamic_table_entry_referenced_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
index 0af250efd32..4a1e39c2325 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
@@ -21,64 +21,16 @@ namespace {
const uint64_t kMaximumDynamicTableCapacityForTesting = 1024 * 1024;
-class MockObserver : public QpackHeaderTable::Observer {
- public:
- ~MockObserver() override = default;
-
- MOCK_METHOD(void, OnInsertCountReachedThreshold, (), (override));
- MOCK_METHOD(void, Cancel, (), (override));
-};
-
+template <typename T>
class QpackHeaderTableTest : public QuicTest {
protected:
- QpackHeaderTableTest() {
- table_.SetMaximumDynamicTableCapacity(
- kMaximumDynamicTableCapacityForTesting);
- table_.SetDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting);
- }
~QpackHeaderTableTest() override = default;
- void ExpectEntryAtIndex(bool is_static,
- uint64_t index,
- absl::string_view expected_name,
- absl::string_view expected_value) const {
- const auto* entry = table_.LookupEntry(is_static, index);
- ASSERT_TRUE(entry);
- EXPECT_EQ(expected_name, entry->name());
- EXPECT_EQ(expected_value, entry->value());
- }
-
- void ExpectNoEntryAtIndex(bool is_static, uint64_t index) const {
- EXPECT_FALSE(table_.LookupEntry(is_static, index));
- }
-
- void ExpectMatch(absl::string_view name,
- absl::string_view value,
- QpackHeaderTable::MatchType expected_match_type,
- bool expected_is_static,
- uint64_t expected_index) const {
- // Initialize outparams to a value different from the expected to ensure
- // that FindHeaderField() sets them.
- bool is_static = !expected_is_static;
- uint64_t index = expected_index + 1;
-
- QpackHeaderTable::MatchType matchtype =
- table_.FindHeaderField(name, value, &is_static, &index);
-
- EXPECT_EQ(expected_match_type, matchtype) << name << ": " << value;
- EXPECT_EQ(expected_is_static, is_static) << name << ": " << value;
- EXPECT_EQ(expected_index, index) << name << ": " << value;
- }
-
- void ExpectNoMatch(absl::string_view name, absl::string_view value) const {
- bool is_static = false;
- uint64_t index = 0;
-
- QpackHeaderTable::MatchType matchtype =
- table_.FindHeaderField(name, value, &is_static, &index);
-
- EXPECT_EQ(QpackHeaderTable::MatchType::kNoMatch, matchtype)
- << name << ": " << value;
+ void SetUp() override {
+ ASSERT_TRUE(table_.SetMaximumDynamicTableCapacity(
+ kMaximumDynamicTableCapacityForTesting));
+ ASSERT_TRUE(
+ table_.SetDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting));
}
bool EntryFitsDynamicTableCapacity(absl::string_view name,
@@ -94,110 +46,129 @@ class QpackHeaderTableTest : public QuicTest {
return table_.SetDynamicTableCapacity(capacity);
}
- void RegisterObserver(uint64_t required_insert_count,
- QpackHeaderTable::Observer* observer) {
- table_.RegisterObserver(required_insert_count, observer);
- }
-
- void UnregisterObserver(uint64_t required_insert_count,
- QpackHeaderTable::Observer* observer) {
- table_.UnregisterObserver(required_insert_count, observer);
- }
-
uint64_t max_entries() const { return table_.max_entries(); }
uint64_t inserted_entry_count() const {
return table_.inserted_entry_count();
}
uint64_t dropped_entry_count() const { return table_.dropped_entry_count(); }
- private:
- QpackHeaderTable table_;
+ T table_;
};
-TEST_F(QpackHeaderTableTest, LookupStaticEntry) {
- ExpectEntryAtIndex(/* is_static = */ true, 0, ":authority", "");
+using MyTypes =
+ ::testing::Types<QpackEncoderHeaderTable, QpackDecoderHeaderTable>;
+TYPED_TEST_SUITE(QpackHeaderTableTest, MyTypes);
- ExpectEntryAtIndex(/* is_static = */ true, 1, ":path", "/");
-
- // 98 is the last entry.
- ExpectEntryAtIndex(/* is_static = */ true, 98, "x-frame-options",
- "sameorigin");
+// MaxEntries is determined by maximum dynamic table capacity,
+// which is set at construction time.
+TYPED_TEST(QpackHeaderTableTest, MaxEntries) {
+ TypeParam table1;
+ table1.SetMaximumDynamicTableCapacity(1024);
+ EXPECT_EQ(32u, table1.max_entries());
- ASSERT_EQ(99u, QpackStaticTableVector().size());
- ExpectNoEntryAtIndex(/* is_static = */ true, 99);
+ TypeParam table2;
+ table2.SetMaximumDynamicTableCapacity(500);
+ EXPECT_EQ(15u, table2.max_entries());
}
-TEST_F(QpackHeaderTableTest, InsertAndLookupDynamicEntry) {
- // Dynamic table is initially entry.
- ExpectNoEntryAtIndex(/* is_static = */ false, 0);
- ExpectNoEntryAtIndex(/* is_static = */ false, 1);
- ExpectNoEntryAtIndex(/* is_static = */ false, 2);
- ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+TYPED_TEST(QpackHeaderTableTest, SetDynamicTableCapacity) {
+ // Dynamic table capacity does not affect MaxEntries.
+ EXPECT_TRUE(this->SetDynamicTableCapacity(1024));
+ EXPECT_EQ(32u * 1024, this->max_entries());
- // Insert one entry.
- InsertEntry("foo", "bar");
+ EXPECT_TRUE(this->SetDynamicTableCapacity(500));
+ EXPECT_EQ(32u * 1024, this->max_entries());
- ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar");
+ // Dynamic table capacity cannot exceed maximum dynamic table capacity.
+ EXPECT_FALSE(this->SetDynamicTableCapacity(
+ 2 * kMaximumDynamicTableCapacityForTesting));
+}
- ExpectNoEntryAtIndex(/* is_static = */ false, 1);
- ExpectNoEntryAtIndex(/* is_static = */ false, 2);
- ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+TYPED_TEST(QpackHeaderTableTest, EntryFitsDynamicTableCapacity) {
+ EXPECT_TRUE(this->SetDynamicTableCapacity(39));
- // Insert a different entry.
- InsertEntry("baz", "bing");
+ EXPECT_TRUE(this->EntryFitsDynamicTableCapacity("foo", "bar"));
+ EXPECT_TRUE(this->EntryFitsDynamicTableCapacity("foo", "bar2"));
+ EXPECT_FALSE(this->EntryFitsDynamicTableCapacity("foo", "bar12"));
+}
- ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar");
+class QpackEncoderHeaderTableTest
+ : public QpackHeaderTableTest<QpackEncoderHeaderTable> {
+ protected:
+ ~QpackEncoderHeaderTableTest() override = default;
- ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing");
+ void ExpectMatch(absl::string_view name,
+ absl::string_view value,
+ QpackEncoderHeaderTable::MatchType expected_match_type,
+ bool expected_is_static,
+ uint64_t expected_index) const {
+ // Initialize outparams to a value different from the expected to ensure
+ // that FindHeaderField() sets them.
+ bool is_static = !expected_is_static;
+ uint64_t index = expected_index + 1;
- ExpectNoEntryAtIndex(/* is_static = */ false, 2);
- ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+ QpackEncoderHeaderTable::MatchType matchtype =
+ table_.FindHeaderField(name, value, &is_static, &index);
- // Insert an entry identical to the most recently inserted one.
- InsertEntry("baz", "bing");
+ EXPECT_EQ(expected_match_type, matchtype) << name << ": " << value;
+ EXPECT_EQ(expected_is_static, is_static) << name << ": " << value;
+ EXPECT_EQ(expected_index, index) << name << ": " << value;
+ }
- ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar");
+ void ExpectNoMatch(absl::string_view name, absl::string_view value) const {
+ bool is_static = false;
+ uint64_t index = 0;
- ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing");
+ QpackEncoderHeaderTable::MatchType matchtype =
+ table_.FindHeaderField(name, value, &is_static, &index);
- ExpectEntryAtIndex(/* is_static = */ false, 2, "baz", "bing");
+ EXPECT_EQ(QpackEncoderHeaderTable::MatchType::kNoMatch, matchtype)
+ << name << ": " << value;
+ }
- ExpectNoEntryAtIndex(/* is_static = */ false, 3);
-}
+ uint64_t MaxInsertSizeWithoutEvictingGivenEntry(uint64_t index) const {
+ return table_.MaxInsertSizeWithoutEvictingGivenEntry(index);
+ }
-TEST_F(QpackHeaderTableTest, FindStaticHeaderField) {
+ uint64_t draining_index(float draining_fraction) const {
+ return table_.draining_index(draining_fraction);
+ }
+};
+
+TEST_F(QpackEncoderHeaderTableTest, FindStaticHeaderField) {
// A header name that has multiple entries with different values.
- ExpectMatch(":method", "GET", QpackHeaderTable::MatchType::kNameAndValue,
- true, 17u);
+ ExpectMatch(":method", "GET",
+ QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 17u);
- ExpectMatch(":method", "POST", QpackHeaderTable::MatchType::kNameAndValue,
- true, 20u);
+ ExpectMatch(":method", "POST",
+ QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 20u);
- ExpectMatch(":method", "TRACE", QpackHeaderTable::MatchType::kName, true,
- 15u);
+ ExpectMatch(":method", "TRACE", QpackEncoderHeaderTable::MatchType::kName,
+ true, 15u);
// A header name that has a single entry with non-empty value.
ExpectMatch("accept-encoding", "gzip, deflate, br",
- QpackHeaderTable::MatchType::kNameAndValue, true, 31u);
+ QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 31u);
- ExpectMatch("accept-encoding", "compress", QpackHeaderTable::MatchType::kName,
- true, 31u);
+ ExpectMatch("accept-encoding", "compress",
+ QpackEncoderHeaderTable::MatchType::kName, true, 31u);
- ExpectMatch("accept-encoding", "", QpackHeaderTable::MatchType::kName, true,
- 31u);
+ ExpectMatch("accept-encoding", "", QpackEncoderHeaderTable::MatchType::kName,
+ true, 31u);
// A header name that has a single entry with empty value.
- ExpectMatch("location", "", QpackHeaderTable::MatchType::kNameAndValue, true,
- 12u);
+ ExpectMatch("location", "", QpackEncoderHeaderTable::MatchType::kNameAndValue,
+ true, 12u);
- ExpectMatch("location", "foo", QpackHeaderTable::MatchType::kName, true, 12u);
+ ExpectMatch("location", "foo", QpackEncoderHeaderTable::MatchType::kName,
+ true, 12u);
// No matching header name.
ExpectNoMatch("foo", "");
ExpectNoMatch("foo", "bar");
}
-TEST_F(QpackHeaderTableTest, FindDynamicHeaderField) {
+TEST_F(QpackEncoderHeaderTableTest, FindDynamicHeaderField) {
// Dynamic table is initially entry.
ExpectNoMatch("foo", "bar");
ExpectNoMatch("foo", "baz");
@@ -206,75 +177,49 @@ TEST_F(QpackHeaderTableTest, FindDynamicHeaderField) {
InsertEntry("foo", "bar");
// Match name and value.
- ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, false,
- 0u);
+ ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue,
+ false, 0u);
// Match name only.
- ExpectMatch("foo", "baz", QpackHeaderTable::MatchType::kName, false, 0u);
+ ExpectMatch("foo", "baz", QpackEncoderHeaderTable::MatchType::kName, false,
+ 0u);
// Insert an identical entry. FindHeaderField() should return the index of
// the most recently inserted matching entry.
InsertEntry("foo", "bar");
// Match name and value.
- ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, false,
- 1u);
+ ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue,
+ false, 1u);
// Match name only.
- ExpectMatch("foo", "baz", QpackHeaderTable::MatchType::kName, false, 1u);
+ ExpectMatch("foo", "baz", QpackEncoderHeaderTable::MatchType::kName, false,
+ 1u);
}
-TEST_F(QpackHeaderTableTest, FindHeaderFieldPrefersStaticTable) {
+TEST_F(QpackEncoderHeaderTableTest, FindHeaderFieldPrefersStaticTable) {
// Insert an entry to the dynamic table that exists in the static table.
InsertEntry(":method", "GET");
- // Insertion works.
- ExpectEntryAtIndex(/* is_static = */ false, 0, ":method", "GET");
-
// FindHeaderField() prefers static table if both have name-and-value match.
- ExpectMatch(":method", "GET", QpackHeaderTable::MatchType::kNameAndValue,
- true, 17u);
+ ExpectMatch(":method", "GET",
+ QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 17u);
// FindHeaderField() prefers static table if both have name match but no value
// match, and prefers the first entry with matching name.
- ExpectMatch(":method", "TRACE", QpackHeaderTable::MatchType::kName, true,
- 15u);
+ ExpectMatch(":method", "TRACE", QpackEncoderHeaderTable::MatchType::kName,
+ true, 15u);
// Add new entry to the dynamic table.
InsertEntry(":method", "TRACE");
// FindHeaderField prefers name-and-value match in dynamic table over name
// only match in static table.
- ExpectMatch(":method", "TRACE", QpackHeaderTable::MatchType::kNameAndValue,
- false, 1u);
+ ExpectMatch(":method", "TRACE",
+ QpackEncoderHeaderTable::MatchType::kNameAndValue, false, 1u);
}
-// MaxEntries is determined by maximum dynamic table capacity,
-// which is set at construction time.
-TEST_F(QpackHeaderTableTest, MaxEntries) {
- QpackHeaderTable table1;
- table1.SetMaximumDynamicTableCapacity(1024);
- EXPECT_EQ(32u, table1.max_entries());
-
- QpackHeaderTable table2;
- table2.SetMaximumDynamicTableCapacity(500);
- EXPECT_EQ(15u, table2.max_entries());
-}
-
-TEST_F(QpackHeaderTableTest, SetDynamicTableCapacity) {
- // Dynamic table capacity does not affect MaxEntries.
- EXPECT_TRUE(SetDynamicTableCapacity(1024));
- EXPECT_EQ(32u * 1024, max_entries());
-
- EXPECT_TRUE(SetDynamicTableCapacity(500));
- EXPECT_EQ(32u * 1024, max_entries());
-
- // Dynamic table capacity cannot exceed maximum dynamic table capacity.
- EXPECT_FALSE(
- SetDynamicTableCapacity(2 * kMaximumDynamicTableCapacityForTesting));
-}
-
-TEST_F(QpackHeaderTableTest, EvictByInsertion) {
+TEST_F(QpackEncoderHeaderTableTest, EvictByInsertion) {
EXPECT_TRUE(SetDynamicTableCapacity(40));
// Entry size is 3 + 3 + 32 = 38.
@@ -282,7 +227,7 @@ TEST_F(QpackHeaderTableTest, EvictByInsertion) {
EXPECT_EQ(1u, inserted_entry_count());
EXPECT_EQ(0u, dropped_entry_count());
- ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 0u);
// Inserting second entry evicts the first one.
@@ -291,20 +236,20 @@ TEST_F(QpackHeaderTableTest, EvictByInsertion) {
EXPECT_EQ(1u, dropped_entry_count());
ExpectNoMatch("foo", "bar");
- ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 1u);
}
-TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) {
+TEST_F(QpackEncoderHeaderTableTest, EvictByUpdateTableSize) {
// Entry size is 3 + 3 + 32 = 38.
InsertEntry("foo", "bar");
InsertEntry("baz", "qux");
EXPECT_EQ(2u, inserted_entry_count());
EXPECT_EQ(0u, dropped_entry_count());
- ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 0u);
- ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 1u);
EXPECT_TRUE(SetDynamicTableCapacity(40));
@@ -312,7 +257,7 @@ TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) {
EXPECT_EQ(1u, dropped_entry_count());
ExpectNoMatch("foo", "bar");
- ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 1u);
EXPECT_TRUE(SetDynamicTableCapacity(20));
@@ -323,7 +268,7 @@ TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) {
ExpectNoMatch("baz", "qux");
}
-TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) {
+TEST_F(QpackEncoderHeaderTableTest, EvictOldestOfIdentical) {
EXPECT_TRUE(SetDynamicTableCapacity(80));
// Entry size is 3 + 3 + 32 = 38.
@@ -334,7 +279,7 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) {
EXPECT_EQ(0u, dropped_entry_count());
// Find most recently inserted entry.
- ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 1u);
// Inserting third entry evicts the first one, not the second.
@@ -342,13 +287,13 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) {
EXPECT_EQ(3u, inserted_entry_count());
EXPECT_EQ(1u, dropped_entry_count());
- ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 1u);
- ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 2u);
}
-TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) {
+TEST_F(QpackEncoderHeaderTableTest, EvictOldestOfSameName) {
EXPECT_TRUE(SetDynamicTableCapacity(80));
// Entry size is 3 + 3 + 32 = 38.
@@ -359,7 +304,7 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) {
EXPECT_EQ(0u, dropped_entry_count());
// Find most recently inserted entry with matching name.
- ExpectMatch("foo", "foo", QpackHeaderTable::MatchType::kName,
+ ExpectMatch("foo", "foo", QpackEncoderHeaderTable::MatchType::kName,
/* expected_is_static = */ false, 1u);
// Inserting third entry evicts the first one, not the second.
@@ -367,63 +312,276 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) {
EXPECT_EQ(3u, inserted_entry_count());
EXPECT_EQ(1u, dropped_entry_count());
- ExpectMatch("foo", "foo", QpackHeaderTable::MatchType::kName,
+ ExpectMatch("foo", "foo", QpackEncoderHeaderTable::MatchType::kName,
/* expected_is_static = */ false, 1u);
- ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
+ ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 2u);
}
// Returns the size of the largest entry that could be inserted into the
// dynamic table without evicting entry |index|.
-TEST_F(QpackHeaderTableTest, MaxInsertSizeWithoutEvictingGivenEntry) {
+TEST_F(QpackEncoderHeaderTableTest, MaxInsertSizeWithoutEvictingGivenEntry) {
const uint64_t dynamic_table_capacity = 100;
- QpackHeaderTable table;
- table.SetMaximumDynamicTableCapacity(dynamic_table_capacity);
- EXPECT_TRUE(table.SetDynamicTableCapacity(dynamic_table_capacity));
+ EXPECT_TRUE(SetDynamicTableCapacity(dynamic_table_capacity));
// Empty table can take an entry up to its capacity.
- EXPECT_EQ(dynamic_table_capacity,
- table.MaxInsertSizeWithoutEvictingGivenEntry(0));
+ EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(0));
const uint64_t entry_size1 = QpackEntry::Size("foo", "bar");
- table.InsertEntry("foo", "bar");
+ InsertEntry("foo", "bar");
EXPECT_EQ(dynamic_table_capacity - entry_size1,
- table.MaxInsertSizeWithoutEvictingGivenEntry(0));
+ MaxInsertSizeWithoutEvictingGivenEntry(0));
// Table can take an entry up to its capacity if all entries are allowed to be
// evicted.
- EXPECT_EQ(dynamic_table_capacity,
- table.MaxInsertSizeWithoutEvictingGivenEntry(1));
+ EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(1));
const uint64_t entry_size2 = QpackEntry::Size("baz", "foobar");
- table.InsertEntry("baz", "foobar");
+ InsertEntry("baz", "foobar");
// Table can take an entry up to its capacity if all entries are allowed to be
// evicted.
- EXPECT_EQ(dynamic_table_capacity,
- table.MaxInsertSizeWithoutEvictingGivenEntry(2));
+ EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(2));
// Second entry must stay.
EXPECT_EQ(dynamic_table_capacity - entry_size2,
- table.MaxInsertSizeWithoutEvictingGivenEntry(1));
+ MaxInsertSizeWithoutEvictingGivenEntry(1));
// First and second entry must stay.
EXPECT_EQ(dynamic_table_capacity - entry_size2 - entry_size1,
- table.MaxInsertSizeWithoutEvictingGivenEntry(0));
+ MaxInsertSizeWithoutEvictingGivenEntry(0));
// Third entry evicts first one.
const uint64_t entry_size3 = QpackEntry::Size("last", "entry");
- table.InsertEntry("last", "entry");
- EXPECT_EQ(1u, table.dropped_entry_count());
+ InsertEntry("last", "entry");
+ EXPECT_EQ(1u, dropped_entry_count());
// Table can take an entry up to its capacity if all entries are allowed to be
// evicted.
- EXPECT_EQ(dynamic_table_capacity,
- table.MaxInsertSizeWithoutEvictingGivenEntry(3));
+ EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(3));
// Third entry must stay.
EXPECT_EQ(dynamic_table_capacity - entry_size3,
- table.MaxInsertSizeWithoutEvictingGivenEntry(2));
+ MaxInsertSizeWithoutEvictingGivenEntry(2));
// Second and third entry must stay.
EXPECT_EQ(dynamic_table_capacity - entry_size3 - entry_size2,
- table.MaxInsertSizeWithoutEvictingGivenEntry(1));
+ MaxInsertSizeWithoutEvictingGivenEntry(1));
+}
+
+TEST_F(QpackEncoderHeaderTableTest, DrainingIndex) {
+ EXPECT_TRUE(SetDynamicTableCapacity(4 * QpackEntry::Size("foo", "bar")));
+
+ // Empty table: no draining entry.
+ EXPECT_EQ(0u, draining_index(0.0));
+ EXPECT_EQ(0u, draining_index(1.0));
+
+ // Table with one entry.
+ InsertEntry("foo", "bar");
+ // Any entry can be referenced if none of the table is draining.
+ EXPECT_EQ(0u, draining_index(0.0));
+ // No entry can be referenced if all of the table is draining.
+ EXPECT_EQ(1u, draining_index(1.0));
+
+ // Table with two entries is at half capacity.
+ InsertEntry("foo", "bar");
+ // Any entry can be referenced if at most half of the table is draining,
+ // because current entries only take up half of total capacity.
+ EXPECT_EQ(0u, draining_index(0.0));
+ EXPECT_EQ(0u, draining_index(0.5));
+ // No entry can be referenced if all of the table is draining.
+ EXPECT_EQ(2u, draining_index(1.0));
+
+ // Table with four entries is full.
+ InsertEntry("foo", "bar");
+ InsertEntry("foo", "bar");
+ // Any entry can be referenced if none of the table is draining.
+ EXPECT_EQ(0u, draining_index(0.0));
+ // In a full table with identically sized entries, |draining_fraction| of all
+ // entries are draining.
+ EXPECT_EQ(2u, draining_index(0.5));
+ // No entry can be referenced if all of the table is draining.
+ EXPECT_EQ(4u, draining_index(1.0));
}
-TEST_F(QpackHeaderTableTest, RegisterObserver) {
+class MockObserver : public QpackDecoderHeaderTable::Observer {
+ public:
+ ~MockObserver() override = default;
+
+ MOCK_METHOD(void, OnInsertCountReachedThreshold, (), (override));
+ MOCK_METHOD(void, Cancel, (), (override));
+};
+
+class QpackDecoderHeaderTableTest
+ : public QpackHeaderTableTest<QpackDecoderHeaderTable> {
+ protected:
+ ~QpackDecoderHeaderTableTest() override = default;
+
+ void ExpectEntryAtIndex(bool is_static,
+ uint64_t index,
+ absl::string_view expected_name,
+ absl::string_view expected_value) const {
+ const auto* entry = table_.LookupEntry(is_static, index);
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(expected_name, entry->name());
+ EXPECT_EQ(expected_value, entry->value());
+ }
+
+ void ExpectNoEntryAtIndex(bool is_static, uint64_t index) const {
+ EXPECT_FALSE(table_.LookupEntry(is_static, index));
+ }
+
+ void RegisterObserver(uint64_t required_insert_count,
+ QpackDecoderHeaderTable::Observer* observer) {
+ table_.RegisterObserver(required_insert_count, observer);
+ }
+
+ void UnregisterObserver(uint64_t required_insert_count,
+ QpackDecoderHeaderTable::Observer* observer) {
+ table_.UnregisterObserver(required_insert_count, observer);
+ }
+};
+
+TEST_F(QpackDecoderHeaderTableTest, LookupStaticEntry) {
+ ExpectEntryAtIndex(/* is_static = */ true, 0, ":authority", "");
+
+ ExpectEntryAtIndex(/* is_static = */ true, 1, ":path", "/");
+
+ // 98 is the last entry.
+ ExpectEntryAtIndex(/* is_static = */ true, 98, "x-frame-options",
+ "sameorigin");
+
+ ASSERT_EQ(99u, QpackStaticTableVector().size());
+ ExpectNoEntryAtIndex(/* is_static = */ true, 99);
+}
+
+TEST_F(QpackDecoderHeaderTableTest, InsertAndLookupDynamicEntry) {
+ // Dynamic table is initially entry.
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 1);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 2);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+
+ // Insert one entry.
+ InsertEntry("foo", "bar");
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar");
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 1);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 2);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+
+ // Insert a different entry.
+ InsertEntry("baz", "bing");
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar");
+
+ ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing");
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 2);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+
+ // Insert an entry identical to the most recently inserted one.
+ InsertEntry("baz", "bing");
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar");
+
+ ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing");
+
+ ExpectEntryAtIndex(/* is_static = */ false, 2, "baz", "bing");
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 3);
+}
+
+TEST_F(QpackDecoderHeaderTableTest, EvictByInsertion) {
+ EXPECT_TRUE(SetDynamicTableCapacity(40));
+
+ // Entry size is 3 + 3 + 32 = 38.
+ InsertEntry("foo", "bar");
+ EXPECT_EQ(1u, inserted_entry_count());
+ EXPECT_EQ(0u, dropped_entry_count());
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar");
+
+ // Inserting second entry evicts the first one.
+ InsertEntry("baz", "qux");
+ EXPECT_EQ(2u, inserted_entry_count());
+ EXPECT_EQ(1u, dropped_entry_count());
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0u);
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "baz", "qux");
+}
+
+TEST_F(QpackDecoderHeaderTableTest, EvictByUpdateTableSize) {
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0u);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 1u);
+
+ // Entry size is 3 + 3 + 32 = 38.
+ InsertEntry("foo", "bar");
+ InsertEntry("baz", "qux");
+ EXPECT_EQ(2u, inserted_entry_count());
+ EXPECT_EQ(0u, dropped_entry_count());
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar");
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "baz", "qux");
+
+ EXPECT_TRUE(SetDynamicTableCapacity(40));
+ EXPECT_EQ(2u, inserted_entry_count());
+ EXPECT_EQ(1u, dropped_entry_count());
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0u);
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "baz", "qux");
+
+ EXPECT_TRUE(SetDynamicTableCapacity(20));
+ EXPECT_EQ(2u, inserted_entry_count());
+ EXPECT_EQ(2u, dropped_entry_count());
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0u);
+ ExpectNoEntryAtIndex(/* is_static = */ false, 1u);
+}
+
+TEST_F(QpackDecoderHeaderTableTest, EvictOldestOfIdentical) {
+ EXPECT_TRUE(SetDynamicTableCapacity(80));
+
+ // Entry size is 3 + 3 + 32 = 38.
+ // Insert same entry twice.
+ InsertEntry("foo", "bar");
+ InsertEntry("foo", "bar");
+ EXPECT_EQ(2u, inserted_entry_count());
+ EXPECT_EQ(0u, dropped_entry_count());
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar");
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "bar");
+ ExpectNoEntryAtIndex(/* is_static = */ false, 2u);
+
+ // Inserting third entry evicts the first one, not the second.
+ InsertEntry("baz", "qux");
+ EXPECT_EQ(3u, inserted_entry_count());
+ EXPECT_EQ(1u, dropped_entry_count());
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0u);
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "bar");
+ ExpectEntryAtIndex(/* is_static = */ false, 2u, "baz", "qux");
+}
+
+TEST_F(QpackDecoderHeaderTableTest, EvictOldestOfSameName) {
+ EXPECT_TRUE(SetDynamicTableCapacity(80));
+
+ // Entry size is 3 + 3 + 32 = 38.
+ // Insert two entries with same name but different values.
+ InsertEntry("foo", "bar");
+ InsertEntry("foo", "baz");
+ EXPECT_EQ(2u, inserted_entry_count());
+ EXPECT_EQ(0u, dropped_entry_count());
+
+ ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar");
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "baz");
+ ExpectNoEntryAtIndex(/* is_static = */ false, 2u);
+
+ // Inserting third entry evicts the first one, not the second.
+ InsertEntry("baz", "qux");
+ EXPECT_EQ(3u, inserted_entry_count());
+ EXPECT_EQ(1u, dropped_entry_count());
+
+ ExpectNoEntryAtIndex(/* is_static = */ false, 0u);
+ ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "baz");
+ ExpectEntryAtIndex(/* is_static = */ false, 2u, "baz", "qux");
+}
+
+TEST_F(QpackDecoderHeaderTableTest, RegisterObserver) {
StrictMock<MockObserver> observer1;
RegisterObserver(1, &observer1);
EXPECT_CALL(observer1, OnInsertCountReachedThreshold);
@@ -462,7 +620,7 @@ TEST_F(QpackHeaderTableTest, RegisterObserver) {
Mock::VerifyAndClearExpectations(&observer5);
}
-TEST_F(QpackHeaderTableTest, UnregisterObserver) {
+TEST_F(QpackDecoderHeaderTableTest, UnregisterObserver) {
StrictMock<MockObserver> observer1;
StrictMock<MockObserver> observer2;
StrictMock<MockObserver> observer3;
@@ -483,61 +641,15 @@ TEST_F(QpackHeaderTableTest, UnregisterObserver) {
EXPECT_EQ(3u, inserted_entry_count());
}
-TEST_F(QpackHeaderTableTest, DrainingIndex) {
- QpackHeaderTable table;
- table.SetMaximumDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting);
- EXPECT_TRUE(
- table.SetDynamicTableCapacity(4 * QpackEntry::Size("foo", "bar")));
-
- // Empty table: no draining entry.
- EXPECT_EQ(0u, table.draining_index(0.0));
- EXPECT_EQ(0u, table.draining_index(1.0));
-
- // Table with one entry.
- table.InsertEntry("foo", "bar");
- // Any entry can be referenced if none of the table is draining.
- EXPECT_EQ(0u, table.draining_index(0.0));
- // No entry can be referenced if all of the table is draining.
- EXPECT_EQ(1u, table.draining_index(1.0));
-
- // Table with two entries is at half capacity.
- table.InsertEntry("foo", "bar");
- // Any entry can be referenced if at most half of the table is draining,
- // because current entries only take up half of total capacity.
- EXPECT_EQ(0u, table.draining_index(0.0));
- EXPECT_EQ(0u, table.draining_index(0.5));
- // No entry can be referenced if all of the table is draining.
- EXPECT_EQ(2u, table.draining_index(1.0));
-
- // Table with four entries is full.
- table.InsertEntry("foo", "bar");
- table.InsertEntry("foo", "bar");
- // Any entry can be referenced if none of the table is draining.
- EXPECT_EQ(0u, table.draining_index(0.0));
- // In a full table with identically sized entries, |draining_fraction| of all
- // entries are draining.
- EXPECT_EQ(2u, table.draining_index(0.5));
- // No entry can be referenced if all of the table is draining.
- EXPECT_EQ(4u, table.draining_index(1.0));
-}
-
-TEST_F(QpackHeaderTableTest, Cancel) {
+TEST_F(QpackDecoderHeaderTableTest, Cancel) {
StrictMock<MockObserver> observer;
- auto table = std::make_unique<QpackHeaderTable>();
+ auto table = std::make_unique<QpackDecoderHeaderTable>();
table->RegisterObserver(1, &observer);
EXPECT_CALL(observer, Cancel);
table.reset();
}
-TEST_F(QpackHeaderTableTest, EntryFitsDynamicTableCapacity) {
- EXPECT_TRUE(SetDynamicTableCapacity(39));
-
- EXPECT_TRUE(EntryFitsDynamicTableCapacity("foo", "bar"));
- EXPECT_TRUE(EntryFitsDynamicTableCapacity("foo", "bar2"));
- EXPECT_FALSE(EntryFitsDynamicTableCapacity("foo", "bar12"));
-}
-
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc
index 3f68d749f36..b10c1b42d86 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc
@@ -12,7 +12,6 @@
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
using ::testing::_;
using ::testing::Eq;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc
index 36b89bd01ec..c84634b1321 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -8,7 +8,6 @@
#include "absl/strings/string_view.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_test.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace test {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
index ac07fedff61..3e7d0ad5127 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
@@ -20,7 +20,7 @@ QpackProgressiveDecoder::QpackProgressiveDecoder(
QuicStreamId stream_id,
BlockedStreamLimitEnforcer* enforcer,
DecodingCompletedVisitor* visitor,
- QpackHeaderTable* header_table,
+ QpackDecoderHeaderTable* header_table,
HeadersHandlerInterface* handler)
: stream_id_(stream_id),
prefix_decoder_(
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
index e806ea0fd66..ced6bf0c2dd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
@@ -18,12 +18,12 @@
namespace quic {
-class QpackHeaderTable;
+class QpackDecoderHeaderTable;
// Class to decode a single header block.
class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
: public QpackInstructionDecoder::Delegate,
- public QpackHeaderTable::Observer {
+ public QpackDecoderHeaderTable::Observer {
public:
// Interface for receiving decoded header block from the decoder.
class QUIC_EXPORT_PRIVATE HeadersHandlerInterface {
@@ -82,7 +82,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
QpackProgressiveDecoder(QuicStreamId stream_id,
BlockedStreamLimitEnforcer* enforcer,
DecodingCompletedVisitor* visitor,
- QpackHeaderTable* header_table,
+ QpackDecoderHeaderTable* header_table,
HeadersHandlerInterface* handler);
QpackProgressiveDecoder(const QpackProgressiveDecoder&) = delete;
QpackProgressiveDecoder& operator=(const QpackProgressiveDecoder&) = delete;
@@ -103,7 +103,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
void OnInstructionDecodingError(QpackInstructionDecoder::ErrorCode error_code,
absl::string_view error_message) override;
- // QpackHeaderTable::Observer implementation.
+ // QpackDecoderHeaderTable::Observer implementation.
void OnInsertCountReachedThreshold() override;
void Cancel() override;
@@ -134,7 +134,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
BlockedStreamLimitEnforcer* const enforcer_;
DecodingCompletedVisitor* const visitor_;
- QpackHeaderTable* const header_table_;
+ QpackDecoderHeaderTable* const header_table_;
HeadersHandlerInterface* const handler_;
// Required Insert Count and Base are decoded from the Header Data Prefix.
@@ -163,7 +163,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
// True if a decoding error has been detected.
bool error_detected_;
- // True if QpackHeaderTable has been destroyed
+ // True if QpackDecoderHeaderTable has been destroyed
// while decoding is still blocked.
bool cancelled_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc
new file mode 100644
index 00000000000..4eb353b183d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/quic_chaos_protector.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "quic/core/crypto/quic_random.h"
+#include "quic/core/frames/quic_crypto_frame.h"
+#include "quic/core/frames/quic_frame.h"
+#include "quic/core/frames/quic_padding_frame.h"
+#include "quic/core/frames/quic_ping_frame.h"
+#include "quic/core/quic_data_reader.h"
+#include "quic/core/quic_data_writer.h"
+#include "quic/core/quic_framer.h"
+#include "quic/core/quic_packets.h"
+#include "quic/core/quic_stream_frame_data_producer.h"
+#include "quic/platform/api/quic_bug_tracker.h"
+#include "common/platform/api/quiche_logging.h"
+
+namespace quic {
+
+QuicChaosProtector::QuicChaosProtector(const QuicCryptoFrame& crypto_frame,
+ int num_padding_bytes,
+ size_t packet_size,
+ QuicFramer* framer,
+ QuicRandom* random)
+ : packet_size_(packet_size),
+ crypto_data_length_(crypto_frame.data_length),
+ crypto_buffer_offset_(crypto_frame.offset),
+ level_(crypto_frame.level),
+ remaining_padding_bytes_(num_padding_bytes),
+ framer_(framer),
+ random_(random) {
+ QUICHE_DCHECK_NE(framer_, nullptr);
+ QUICHE_DCHECK_NE(framer_->data_producer(), nullptr);
+ QUICHE_DCHECK_NE(random_, nullptr);
+}
+
+QuicChaosProtector::~QuicChaosProtector() {
+ DeleteFrames(&frames_);
+}
+
+absl::optional<size_t> QuicChaosProtector::BuildDataPacket(
+ const QuicPacketHeader& header,
+ char* buffer) {
+ if (!CopyCryptoDataToLocalBuffer()) {
+ return absl::nullopt;
+ }
+ SplitCryptoFrame();
+ AddPingFrames();
+ SpreadPadding();
+ ReorderFrames();
+ return BuildPacket(header, buffer);
+}
+
+WriteStreamDataResult QuicChaosProtector::WriteStreamData(
+ QuicStreamId id,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* /*writer*/) {
+ QUIC_BUG(chaos stream) << "This should never be called; id " << id
+ << " offset " << offset << " data_length "
+ << data_length;
+ return STREAM_MISSING;
+}
+
+bool QuicChaosProtector::WriteCryptoData(EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* writer) {
+ if (level != level_) {
+ QUIC_BUG(chaos bad level) << "Unexpected " << level << " != " << level_;
+ return false;
+ }
+ // This is `offset + data_length > buffer_offset_ + buffer_length_`
+ // but with integer overflow protection.
+ if (offset < crypto_buffer_offset_ || data_length > crypto_data_length_ ||
+ offset - crypto_buffer_offset_ > crypto_data_length_ - data_length) {
+ QUIC_BUG(chaos bad lengths)
+ << "Unexpected buffer_offset_ " << crypto_buffer_offset_ << " offset "
+ << offset << " buffer_length_ " << crypto_data_length_
+ << " data_length " << data_length;
+ return false;
+ }
+ writer->WriteBytes(&crypto_data_buffer_[offset - crypto_buffer_offset_],
+ data_length);
+ return true;
+}
+
+bool QuicChaosProtector::CopyCryptoDataToLocalBuffer() {
+ crypto_frame_buffer_ = std::make_unique<char[]>(packet_size_);
+ frames_.push_back(QuicFrame(
+ new QuicCryptoFrame(level_, crypto_buffer_offset_, crypto_data_length_)));
+ // We use |framer_| to serialize the CRYPTO frame in order to extract its
+ // data from the crypto data producer. This ensures that we reuse the
+ // usual serialization code path, but has the downside that we then need to
+ // parse the offset and length in order to skip over those fields.
+ QuicDataWriter writer(packet_size_, crypto_frame_buffer_.get());
+ if (!framer_->AppendCryptoFrame(*frames_.front().crypto_frame, &writer)) {
+ QUIC_BUG(chaos write crypto data);
+ return false;
+ }
+ QuicDataReader reader(crypto_frame_buffer_.get(), writer.length());
+ uint64_t parsed_offset, parsed_length;
+ if (!reader.ReadVarInt62(&parsed_offset) ||
+ !reader.ReadVarInt62(&parsed_length)) {
+ QUIC_BUG(chaos parse crypto frame);
+ return false;
+ }
+
+ absl::string_view crypto_data = reader.ReadRemainingPayload();
+ crypto_data_buffer_ = crypto_data.data();
+
+ QUICHE_DCHECK_EQ(parsed_offset, crypto_buffer_offset_);
+ QUICHE_DCHECK_EQ(parsed_length, crypto_data_length_);
+ QUICHE_DCHECK_EQ(parsed_length, crypto_data.length());
+
+ return true;
+}
+
+void QuicChaosProtector::SplitCryptoFrame() {
+ const int max_overhead_of_adding_a_crypto_frame =
+ static_cast<int>(QuicFramer::GetMinCryptoFrameSize(
+ crypto_buffer_offset_ + crypto_data_length_, crypto_data_length_));
+ // Pick a random number of CRYPTO frames to add.
+ constexpr uint64_t kMaxAddedCryptoFrames = 10;
+ const uint64_t num_added_crypto_frames =
+ random_->InsecureRandUint64() % (kMaxAddedCryptoFrames + 1);
+ for (uint64_t i = 0; i < num_added_crypto_frames; i++) {
+ if (remaining_padding_bytes_ < max_overhead_of_adding_a_crypto_frame) {
+ break;
+ }
+ // Pick a random frame and split it by shrinking the picked frame and
+ // moving the second half of its data to a new frame that is then appended
+ // to |frames|.
+ size_t frame_to_split_index =
+ random_->InsecureRandUint64() % frames_.size();
+ QuicCryptoFrame* frame_to_split =
+ frames_[frame_to_split_index].crypto_frame;
+ if (frame_to_split->data_length <= 1) {
+ continue;
+ }
+ const int frame_to_split_old_overhead =
+ static_cast<int>(QuicFramer::GetMinCryptoFrameSize(
+ frame_to_split->offset, frame_to_split->data_length));
+ const QuicPacketLength frame_to_split_new_data_length =
+ 1 + (random_->InsecureRandUint64() % (frame_to_split->data_length - 1));
+ const QuicPacketLength new_frame_data_length =
+ frame_to_split->data_length - frame_to_split_new_data_length;
+ const QuicStreamOffset new_frame_offset =
+ frame_to_split->offset + frame_to_split_new_data_length;
+ frame_to_split->data_length -= new_frame_data_length;
+ frames_.push_back(QuicFrame(
+ new QuicCryptoFrame(level_, new_frame_offset, new_frame_data_length)));
+ const int frame_to_split_new_overhead =
+ static_cast<int>(QuicFramer::GetMinCryptoFrameSize(
+ frame_to_split->offset, frame_to_split->data_length));
+ const int new_frame_overhead =
+ static_cast<int>(QuicFramer::GetMinCryptoFrameSize(
+ new_frame_offset, new_frame_data_length));
+ QUICHE_DCHECK_LE(frame_to_split_new_overhead, frame_to_split_old_overhead);
+ // Readjust padding based on increased overhead.
+ remaining_padding_bytes_ -= new_frame_overhead;
+ remaining_padding_bytes_ -= frame_to_split_new_overhead;
+ remaining_padding_bytes_ += frame_to_split_old_overhead;
+ }
+}
+
+void QuicChaosProtector::AddPingFrames() {
+ constexpr uint64_t kMaxAddedPingFrames = 10;
+ const uint64_t num_ping_frames =
+ random_->InsecureRandUint64() %
+ std::min<uint64_t>(kMaxAddedPingFrames, remaining_padding_bytes_);
+ for (uint64_t i = 0; i < num_ping_frames; i++) {
+ frames_.push_back(QuicFrame(QuicPingFrame()));
+ }
+ remaining_padding_bytes_ -= static_cast<int>(num_ping_frames);
+}
+
+void QuicChaosProtector::ReorderFrames() {
+ // Walk the array backwards and swap each frame with a random earlier one.
+ for (size_t i = frames_.size() - 1; i > 0; i--) {
+ std::swap(frames_[i], frames_[random_->InsecureRandUint64() % (i + 1)]);
+ }
+}
+
+void QuicChaosProtector::SpreadPadding() {
+ for (auto it = frames_.begin(); it != frames_.end(); ++it) {
+ const int padding_bytes_in_this_frame =
+ random_->InsecureRandUint64() % (remaining_padding_bytes_ + 1);
+ if (padding_bytes_in_this_frame <= 0) {
+ continue;
+ }
+ it = frames_.insert(
+ it, QuicFrame(QuicPaddingFrame(padding_bytes_in_this_frame)));
+ ++it; // Skip over the padding frame we just added.
+ remaining_padding_bytes_ -= padding_bytes_in_this_frame;
+ }
+ if (remaining_padding_bytes_ > 0) {
+ frames_.push_back(QuicFrame(QuicPaddingFrame(remaining_padding_bytes_)));
+ }
+}
+
+absl::optional<size_t> QuicChaosProtector::BuildPacket(
+ const QuicPacketHeader& header,
+ char* buffer) {
+ QuicStreamFrameDataProducer* original_data_producer =
+ framer_->data_producer();
+ framer_->set_data_producer(this);
+
+ size_t length =
+ framer_->BuildDataPacket(header, frames_, buffer, packet_size_, level_);
+
+ framer_->set_data_producer(original_data_producer);
+ if (length == 0) {
+ return absl::nullopt;
+ }
+ return length;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h
new file mode 100644
index 00000000000..6bcd42087e7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_CHAOS_PROTECTOR_H_
+#define QUICHE_QUIC_CORE_QUIC_CHAOS_PROTECTOR_H_
+
+#include <cstddef>
+#include <memory>
+
+#include "absl/types/optional.h"
+#include "quic/core/crypto/quic_random.h"
+#include "quic/core/frames/quic_crypto_frame.h"
+#include "quic/core/frames/quic_frame.h"
+#include "quic/core/quic_data_writer.h"
+#include "quic/core/quic_framer.h"
+#include "quic/core/quic_packets.h"
+#include "quic/core/quic_stream_frame_data_producer.h"
+#include "quic/core/quic_types.h"
+
+namespace quic {
+
+namespace test {
+class QuicChaosProtectorTest;
+}
+
+// QuicChaosProtector will take a crypto frame and an amount of padding and
+// build a data packet that will parse to something equivalent.
+class QUIC_EXPORT_PRIVATE QuicChaosProtector
+ : public QuicStreamFrameDataProducer {
+ public:
+ // |framer| and |random| must be valid for the lifetime of QuicChaosProtector.
+ explicit QuicChaosProtector(const QuicCryptoFrame& crypto_frame,
+ int num_padding_bytes,
+ size_t packet_size,
+ QuicFramer* framer,
+ QuicRandom* random);
+
+ ~QuicChaosProtector() override;
+
+ QuicChaosProtector(const QuicChaosProtector&) = delete;
+ QuicChaosProtector(QuicChaosProtector&&) = delete;
+ QuicChaosProtector& operator=(const QuicChaosProtector&) = delete;
+ QuicChaosProtector& operator=(QuicChaosProtector&&) = delete;
+
+ // Attempts to build a data packet with chaos protection. If an error occurs,
+ // then absl::nullopt is returned. Otherwise returns the serialized length.
+ absl::optional<size_t> BuildDataPacket(const QuicPacketHeader& header,
+ char* buffer);
+
+ // From QuicStreamFrameDataProducer.
+ WriteStreamDataResult WriteStreamData(QuicStreamId id,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* /*writer*/) override;
+ bool WriteCryptoData(EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* writer) override;
+
+ private:
+ friend class test::QuicChaosProtectorTest;
+
+ // Allocate the crypto data buffer, create the CRYPTO frame and write the
+ // crypto data to our buffer.
+ bool CopyCryptoDataToLocalBuffer();
+
+ // Split the CRYPTO frame in |frames_| into one or more CRYPTO frames that
+ // collectively represent the same data. Adjusts padding to compensate.
+ void SplitCryptoFrame();
+
+ // Add a random number of PING frames to |frames_| and adjust padding.
+ void AddPingFrames();
+
+ // Randomly reorder |frames_|.
+ void ReorderFrames();
+
+ // Add PADDING frames randomly between all other frames.
+ void SpreadPadding();
+
+ // Serialize |frames_| using |framer_|.
+ absl::optional<size_t> BuildPacket(const QuicPacketHeader& header,
+ char* buffer);
+
+ size_t packet_size_;
+ std::unique_ptr<char[]> crypto_frame_buffer_;
+ const char* crypto_data_buffer_ = nullptr;
+ QuicByteCount crypto_data_length_;
+ QuicStreamOffset crypto_buffer_offset_;
+ EncryptionLevel level_;
+ int remaining_padding_bytes_;
+ QuicFrames frames_; // Inner frames owned, will be deleted by destructor.
+ QuicFramer* framer_; // Unowned.
+ QuicRandom* random_; // Unowned.
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QUIC_CHAOS_PROTECTOR_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc
new file mode 100644
index 00000000000..1ec985beea1
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/quic_chaos_protector.h"
+
+#include <cstddef>
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "quic/core/frames/quic_crypto_frame.h"
+#include "quic/core/quic_connection_id.h"
+#include "quic/core/quic_framer.h"
+#include "quic/core/quic_packet_number.h"
+#include "quic/core/quic_packets.h"
+#include "quic/core/quic_stream_frame_data_producer.h"
+#include "quic/core/quic_time.h"
+#include "quic/core/quic_types.h"
+#include "quic/core/quic_versions.h"
+#include "quic/platform/api/quic_test.h"
+#include "quic/test_tools/mock_random.h"
+#include "quic/test_tools/quic_test_utils.h"
+#include "quic/test_tools/simple_quic_framer.h"
+
+namespace quic {
+namespace test {
+
+class QuicChaosProtectorTest : public QuicTestWithParam<ParsedQuicVersion>,
+ public QuicStreamFrameDataProducer {
+ public:
+ QuicChaosProtectorTest()
+ : version_(GetParam()),
+ framer_({version_},
+ QuicTime::Zero(),
+ Perspective::IS_CLIENT,
+ kQuicDefaultConnectionIdLength),
+ validation_framer_({version_}),
+ random_(/*base=*/3),
+ level_(ENCRYPTION_INITIAL),
+ crypto_offset_(0),
+ crypto_data_length_(100),
+ crypto_frame_(level_, crypto_offset_, crypto_data_length_),
+ num_padding_bytes_(50),
+ packet_size_(1000),
+ packet_buffer_(std::make_unique<char[]>(packet_size_)),
+ chaos_protector_(crypto_frame_,
+ num_padding_bytes_,
+ packet_size_,
+ SetupHeaderAndFramers(),
+ &random_) {}
+
+ // From QuicStreamFrameDataProducer.
+ WriteStreamDataResult WriteStreamData(QuicStreamId /*id*/,
+ QuicStreamOffset /*offset*/,
+ QuicByteCount /*data_length*/,
+ QuicDataWriter* /*writer*/) override {
+ ADD_FAILURE() << "This should never be called";
+ return STREAM_MISSING;
+ }
+
+ // From QuicStreamFrameDataProducer.
+ bool WriteCryptoData(EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* writer) override {
+ EXPECT_EQ(level, level);
+ EXPECT_EQ(offset, crypto_offset_);
+ EXPECT_EQ(data_length, crypto_data_length_);
+ for (QuicByteCount i = 0; i < data_length; i++) {
+ EXPECT_TRUE(writer->WriteUInt8(static_cast<uint8_t>(i & 0xFF)));
+ }
+ return true;
+ }
+
+ protected:
+ QuicFramer* SetupHeaderAndFramers() {
+ // Setup header.
+ header_.destination_connection_id = TestConnectionId();
+ header_.destination_connection_id_included = CONNECTION_ID_PRESENT;
+ header_.source_connection_id = EmptyQuicConnectionId();
+ header_.source_connection_id_included = CONNECTION_ID_PRESENT;
+ header_.reset_flag = false;
+ header_.version_flag = true;
+ header_.has_possible_stateless_reset_token = false;
+ header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
+ header_.version = version_;
+ header_.packet_number = QuicPacketNumber(1);
+ header_.form = IETF_QUIC_LONG_HEADER_PACKET;
+ header_.long_packet_type = INITIAL;
+ header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header_.length_length = kQuicDefaultLongHeaderLengthLength;
+ // Setup validation framer.
+ validation_framer_.framer()->SetInitialObfuscators(
+ header_.destination_connection_id);
+ // Setup framer.
+ framer_.SetInitialObfuscators(header_.destination_connection_id);
+ framer_.set_data_producer(this);
+ return &framer_;
+ }
+
+ void BuildEncryptAndParse() {
+ absl::optional<size_t> length =
+ chaos_protector_.BuildDataPacket(header_, packet_buffer_.get());
+ ASSERT_TRUE(length.has_value());
+ ASSERT_GT(length.value(), 0u);
+ size_t encrypted_length = framer_.EncryptInPlace(
+ level_, header_.packet_number,
+ GetStartOfEncryptedData(framer_.transport_version(), header_),
+ length.value(), packet_size_, packet_buffer_.get());
+ ASSERT_GT(encrypted_length, 0u);
+ ASSERT_TRUE(validation_framer_.ProcessPacket(QuicEncryptedPacket(
+ absl::string_view(packet_buffer_.get(), encrypted_length))));
+ }
+
+ void ResetOffset(QuicStreamOffset offset) {
+ crypto_offset_ = offset;
+ crypto_frame_.offset = offset;
+ chaos_protector_.crypto_buffer_offset_ = offset;
+ }
+
+ ParsedQuicVersion version_;
+ QuicPacketHeader header_;
+ QuicFramer framer_;
+ SimpleQuicFramer validation_framer_;
+ MockRandom random_;
+ EncryptionLevel level_;
+ QuicStreamOffset crypto_offset_;
+ QuicByteCount crypto_data_length_;
+ QuicCryptoFrame crypto_frame_;
+ int num_padding_bytes_;
+ size_t packet_size_;
+ std::unique_ptr<char[]> packet_buffer_;
+ QuicChaosProtector chaos_protector_;
+};
+
+namespace {
+
+ParsedQuicVersionVector TestVersions() {
+ ParsedQuicVersionVector versions;
+ for (const ParsedQuicVersion& version : AllSupportedVersions()) {
+ if (version.UsesCryptoFrames()) {
+ versions.push_back(version);
+ }
+ }
+ return versions;
+}
+
+INSTANTIATE_TEST_SUITE_P(QuicChaosProtectorTests,
+ QuicChaosProtectorTest,
+ ::testing::ValuesIn(TestVersions()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(QuicChaosProtectorTest, Main) {
+ BuildEncryptAndParse();
+ ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, 0u);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 1u);
+ ASSERT_EQ(validation_framer_.ping_frames().size(), 3u);
+ ASSERT_EQ(validation_framer_.padding_frames().size(), 7u);
+ EXPECT_EQ(validation_framer_.padding_frames()[0].num_padding_bytes, 3);
+}
+
+TEST_P(QuicChaosProtectorTest, DifferentRandom) {
+ random_.ResetBase(4);
+ BuildEncryptAndParse();
+ ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u);
+ ASSERT_EQ(validation_framer_.ping_frames().size(), 4u);
+ ASSERT_EQ(validation_framer_.padding_frames().size(), 8u);
+}
+
+TEST_P(QuicChaosProtectorTest, RandomnessZero) {
+ random_.ResetBase(0);
+ BuildEncryptAndParse();
+ ASSERT_EQ(validation_framer_.crypto_frames().size(), 1u);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length,
+ crypto_data_length_);
+ ASSERT_EQ(validation_framer_.ping_frames().size(), 0u);
+ ASSERT_EQ(validation_framer_.padding_frames().size(), 1u);
+}
+
+TEST_P(QuicChaosProtectorTest, Offset) {
+ ResetOffset(123);
+ BuildEncryptAndParse();
+ ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 1u);
+ ASSERT_EQ(validation_framer_.ping_frames().size(), 3u);
+ ASSERT_EQ(validation_framer_.padding_frames().size(), 7u);
+ EXPECT_EQ(validation_framer_.padding_frames()[0].num_padding_bytes, 3);
+}
+
+TEST_P(QuicChaosProtectorTest, OffsetAndRandomnessZero) {
+ ResetOffset(123);
+ random_.ResetBase(0);
+ BuildEncryptAndParse();
+ ASSERT_EQ(validation_framer_.crypto_frames().size(), 1u);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
+ EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length,
+ crypto_data_length_);
+ ASSERT_EQ(validation_framer_.ping_frames().size(), 0u);
+ ASSERT_EQ(validation_framer_.padding_frames().size(), 1u);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h
deleted file mode 100644
index 44637abcbd6..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h
+++ /dev/null
@@ -1,757 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_
-#define QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_
-
-#include <algorithm>
-#include <cstddef>
-#include <cstring>
-#include <iterator>
-#include <memory>
-#include <ostream>
-#include <type_traits>
-
-#include "quic/platform/api/quic_export.h"
-#include "quic/platform/api/quic_logging.h"
-
-namespace quic {
-
-// QuicCircularDeque is a STL-style container that is similar to std deque in
-// API and std::vector in capacity management. The goal is to optimize a common
-// QUIC use case where we keep adding new elements to the end and removing old
-// elements from the beginning, under such scenarios, if the container's size()
-// remain relatively stable, QuicCircularDeque requires little to no memory
-// allocations or deallocations.
-//
-// The implementation, as the name suggests, uses a flat circular buffer to hold
-// all elements. At any point in time, either
-// a) All elements are placed in a contiguous portion of this buffer, like a
-// c-array, or
-// b) Elements are phycially divided into two parts: the first part occupies the
-// end of the buffer and the second part occupies the beginning of the
-// buffer.
-//
-// Currently, elements can only be pushed or poped from either ends, it can't be
-// inserted or erased in the middle.
-//
-// TODO(wub): Make memory grow/shrink strategies customizable.
-template <typename T,
- size_t MinCapacityIncrement = 3,
- typename Allocator = std::allocator<T>>
-class QUIC_NO_EXPORT QuicCircularDeque {
- using AllocatorTraits = std::allocator_traits<Allocator>;
-
- // Pointee is either T or const T.
- template <typename Pointee>
- class QUIC_NO_EXPORT basic_iterator {
- using size_type = typename AllocatorTraits::size_type;
-
- public:
- using iterator_category = std::random_access_iterator_tag;
- using value_type = typename AllocatorTraits::value_type;
- using difference_type = typename AllocatorTraits::difference_type;
- using pointer = Pointee*;
- using reference = Pointee&;
-
- basic_iterator() = default;
-
- // A copy constructor if Pointee is T.
- // A conversion from iterator to const_iterator if Pointee is const T.
- basic_iterator(
- const basic_iterator<value_type>& it) // NOLINT(runtime/explicit)
- : deque_(it.deque_), index_(it.index_) {}
-
- // A copy assignment if Pointee is T.
- // A assignment from iterator to const_iterator if Pointee is const T.
- basic_iterator& operator=(const basic_iterator<value_type>& it) {
- if (this != &it) {
- deque_ = it.deque_;
- index_ = it.index_;
- }
- return *this;
- }
-
- reference operator*() const { return *deque_->index_to_address(index_); }
- pointer operator->() const { return deque_->index_to_address(index_); }
- reference operator[](difference_type i) { return *(*this + i); }
-
- basic_iterator& operator++() {
- Increment();
- return *this;
- }
-
- basic_iterator operator++(int) {
- basic_iterator result = *this;
- Increment();
- return result;
- }
-
- basic_iterator operator--() {
- Decrement();
- return *this;
- }
-
- basic_iterator operator--(int) {
- basic_iterator result = *this;
- Decrement();
- return result;
- }
-
- friend basic_iterator operator+(const basic_iterator& it,
- difference_type delta) {
- basic_iterator result = it;
- result.IncrementBy(delta);
- return result;
- }
-
- basic_iterator& operator+=(difference_type delta) {
- IncrementBy(delta);
- return *this;
- }
-
- friend basic_iterator operator-(const basic_iterator& it,
- difference_type delta) {
- basic_iterator result = it;
- result.IncrementBy(-delta);
- return result;
- }
-
- basic_iterator& operator-=(difference_type delta) {
- IncrementBy(-delta);
- return *this;
- }
-
- friend difference_type operator-(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return lhs.ExternalPosition() - rhs.ExternalPosition();
- }
-
- friend bool operator==(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return lhs.index_ == rhs.index_;
- }
-
- friend bool operator!=(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return !(lhs == rhs);
- }
-
- friend bool operator<(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return lhs.ExternalPosition() < rhs.ExternalPosition();
- }
-
- friend bool operator<=(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return !(lhs > rhs);
- }
-
- friend bool operator>(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return lhs.ExternalPosition() > rhs.ExternalPosition();
- }
-
- friend bool operator>=(const basic_iterator& lhs,
- const basic_iterator& rhs) {
- return !(lhs < rhs);
- }
-
- private:
- basic_iterator(const QuicCircularDeque* deque, size_type index)
- : deque_(deque), index_(index) {}
-
- void Increment() {
- QUICHE_DCHECK_LE(ExternalPosition() + 1, deque_->size());
- index_ = deque_->index_next(index_);
- }
-
- void Decrement() {
- QUICHE_DCHECK_GE(ExternalPosition(), 1u);
- index_ = deque_->index_prev(index_);
- }
-
- void IncrementBy(difference_type delta) {
- if (delta >= 0) {
- // After increment we are before or at end().
- QUICHE_DCHECK_LE(static_cast<size_type>(ExternalPosition() + delta),
- deque_->size());
- } else {
- // After decrement we are after or at begin().
- QUICHE_DCHECK_GE(ExternalPosition(), static_cast<size_type>(-delta));
- }
- index_ = deque_->index_increment_by(index_, delta);
- }
-
- size_type ExternalPosition() const {
- if (index_ >= deque_->begin_) {
- return index_ - deque_->begin_;
- }
- return index_ + deque_->data_capacity() - deque_->begin_;
- }
-
- friend class QuicCircularDeque;
- const QuicCircularDeque* deque_ = nullptr;
- size_type index_ = 0;
- };
-
- public:
- using allocator_type = typename AllocatorTraits::allocator_type;
- using value_type = typename AllocatorTraits::value_type;
- using size_type = typename AllocatorTraits::size_type;
- using difference_type = typename AllocatorTraits::difference_type;
- using reference = value_type&;
- using const_reference = const value_type&;
- using pointer = typename AllocatorTraits::pointer;
- using const_pointer = typename AllocatorTraits::const_pointer;
- using iterator = basic_iterator<T>;
- using const_iterator = basic_iterator<const T>;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- QuicCircularDeque() : QuicCircularDeque(allocator_type()) {}
- explicit QuicCircularDeque(const allocator_type& alloc)
- : allocator_and_data_(alloc) {}
-
- QuicCircularDeque(size_type count,
- const T& value,
- const Allocator& alloc = allocator_type())
- : allocator_and_data_(alloc) {
- resize(count, value);
- }
-
- explicit QuicCircularDeque(size_type count,
- const Allocator& alloc = allocator_type())
- : allocator_and_data_(alloc) {
- resize(count);
- }
-
- template <
- class InputIt,
- typename = std::enable_if_t<std::is_base_of<
- std::input_iterator_tag,
- typename std::iterator_traits<InputIt>::iterator_category>::value>>
- QuicCircularDeque(InputIt first,
- InputIt last,
- const Allocator& alloc = allocator_type())
- : allocator_and_data_(alloc) {
- AssignRange(first, last);
- }
-
- QuicCircularDeque(const QuicCircularDeque& other)
- : QuicCircularDeque(
- other,
- AllocatorTraits::select_on_container_copy_construction(
- other.allocator_and_data_.allocator())) {}
-
- QuicCircularDeque(const QuicCircularDeque& other, const allocator_type& alloc)
- : allocator_and_data_(alloc) {
- assign(other.begin(), other.end());
- }
-
- QuicCircularDeque(QuicCircularDeque&& other)
- : begin_(other.begin_),
- end_(other.end_),
- allocator_and_data_(std::move(other.allocator_and_data_)) {
- other.begin_ = other.end_ = 0;
- other.allocator_and_data_.data = nullptr;
- other.allocator_and_data_.data_capacity = 0;
- }
-
- QuicCircularDeque(QuicCircularDeque&& other, const allocator_type& alloc)
- : allocator_and_data_(alloc) {
- MoveRetainAllocator(std::move(other));
- }
-
- QuicCircularDeque(std::initializer_list<T> init,
- const allocator_type& alloc = allocator_type())
- : QuicCircularDeque(init.begin(), init.end(), alloc) {}
-
- QuicCircularDeque& operator=(const QuicCircularDeque& other) {
- if (this == &other) {
- return *this;
- }
- if (AllocatorTraits::propagate_on_container_copy_assignment::value &&
- (allocator_and_data_.allocator() !=
- other.allocator_and_data_.allocator())) {
- // Destroy all current elements and blocks with the current allocator,
- // before switching this to use the allocator propagated from "other".
- DestroyAndDeallocateAll();
- begin_ = end_ = 0;
- allocator_and_data_ =
- AllocatorAndData(other.allocator_and_data_.allocator());
- }
- assign(other.begin(), other.end());
- return *this;
- }
-
- QuicCircularDeque& operator=(QuicCircularDeque&& other) {
- if (this == &other) {
- return *this;
- }
- if (AllocatorTraits::propagate_on_container_move_assignment::value) {
- // Take over the storage of "other", along with its allocator.
- this->~QuicCircularDeque();
- new (this) QuicCircularDeque(std::move(other));
- } else {
- MoveRetainAllocator(std::move(other));
- }
- return *this;
- }
-
- ~QuicCircularDeque() { DestroyAndDeallocateAll(); }
-
- void assign(size_type count, const T& value) {
- ClearRetainCapacity();
- reserve(count);
- for (size_t i = 0; i < count; ++i) {
- emplace_back(value);
- }
- }
-
- template <
- class InputIt,
- typename = std::enable_if_t<std::is_base_of<
- std::input_iterator_tag,
- typename std::iterator_traits<InputIt>::iterator_category>::value>>
- void assign(InputIt first, InputIt last) {
- AssignRange(first, last);
- }
-
- void assign(std::initializer_list<T> ilist) {
- assign(ilist.begin(), ilist.end());
- }
-
- reference at(size_type pos) {
- QUICHE_DCHECK(pos < size()) << "pos:" << pos << ", size():" << size();
- size_type index = begin_ + pos;
- if (index < data_capacity()) {
- return *index_to_address(index);
- }
- return *index_to_address(index - data_capacity());
- }
-
- const_reference at(size_type pos) const {
- return const_cast<QuicCircularDeque*>(this)->at(pos);
- }
-
- reference operator[](size_type pos) { return at(pos); }
-
- const_reference operator[](size_type pos) const { return at(pos); }
-
- reference front() {
- QUICHE_DCHECK(!empty());
- return *index_to_address(begin_);
- }
-
- const_reference front() const {
- return const_cast<QuicCircularDeque*>(this)->front();
- }
-
- reference back() {
- QUICHE_DCHECK(!empty());
- return *(index_to_address(end_ == 0 ? data_capacity() - 1 : end_ - 1));
- }
-
- const_reference back() const {
- return const_cast<QuicCircularDeque*>(this)->back();
- }
-
- iterator begin() { return iterator(this, begin_); }
- const_iterator begin() const { return const_iterator(this, begin_); }
- const_iterator cbegin() const { return const_iterator(this, begin_); }
-
- iterator end() { return iterator(this, end_); }
- const_iterator end() const { return const_iterator(this, end_); }
- const_iterator cend() const { return const_iterator(this, end_); }
-
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- const_reverse_iterator rbegin() const {
- return const_reverse_iterator(end());
- }
- const_reverse_iterator crbegin() const { return rbegin(); }
-
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator rend() const {
- return const_reverse_iterator(begin());
- }
- const_reverse_iterator crend() const { return rend(); }
-
- size_type capacity() const {
- return data_capacity() == 0 ? 0 : data_capacity() - 1;
- }
-
- void reserve(size_type new_cap) {
- if (new_cap > capacity()) {
- Relocate(new_cap);
- }
- }
-
- // Remove all elements. Leave capacity unchanged.
- void clear() { ClearRetainCapacity(); }
-
- bool empty() const { return begin_ == end_; }
-
- size_type size() const {
- if (begin_ <= end_) {
- return end_ - begin_;
- }
- return data_capacity() + end_ - begin_;
- }
-
- void resize(size_type count) { ResizeInternal(count); }
-
- void resize(size_type count, const value_type& value) {
- ResizeInternal(count, value);
- }
-
- void push_front(const T& value) { emplace_front(value); }
- void push_front(T&& value) { emplace_front(std::move(value)); }
-
- template <class... Args>
- reference emplace_front(Args&&... args) {
- MaybeExpandCapacity(1);
- begin_ = index_prev(begin_);
- new (index_to_address(begin_)) T(std::forward<Args>(args)...);
- return front();
- }
-
- void push_back(const T& value) { emplace_back(value); }
- void push_back(T&& value) { emplace_back(std::move(value)); }
-
- template <class... Args>
- reference emplace_back(Args&&... args) {
- MaybeExpandCapacity(1);
- new (index_to_address(end_)) T(std::forward<Args>(args)...);
- end_ = index_next(end_);
- return back();
- }
-
- void pop_front() {
- QUICHE_DCHECK(!empty());
- DestroyByIndex(begin_);
- begin_ = index_next(begin_);
- MaybeShrinkCapacity();
- }
-
- size_type pop_front_n(size_type count) {
- size_type num_elements_to_pop = std::min(count, size());
- size_type new_begin = index_increment_by(begin_, num_elements_to_pop);
- DestroyRange(begin_, new_begin);
- begin_ = new_begin;
- MaybeShrinkCapacity();
- return num_elements_to_pop;
- }
-
- void pop_back() {
- QUICHE_DCHECK(!empty());
- end_ = index_prev(end_);
- DestroyByIndex(end_);
- MaybeShrinkCapacity();
- }
-
- size_type pop_back_n(size_type count) {
- size_type num_elements_to_pop = std::min(count, size());
- size_type new_end = index_increment_by(end_, -num_elements_to_pop);
- DestroyRange(new_end, end_);
- end_ = new_end;
- MaybeShrinkCapacity();
- return num_elements_to_pop;
- }
-
- void swap(QuicCircularDeque& other) {
- using std::swap;
- swap(begin_, other.begin_);
- swap(end_, other.end_);
-
- if (AllocatorTraits::propagate_on_container_swap::value) {
- swap(allocator_and_data_, other.allocator_and_data_);
- } else {
- // When propagate_on_container_swap is false, it is undefined behavior, by
- // c++ standard, to swap between two AllocatorAwareContainer(s) with
- // unequal allocators.
- QUICHE_DCHECK(get_allocator() == other.get_allocator())
- << "Undefined swap behavior";
- swap(allocator_and_data_.data, other.allocator_and_data_.data);
- swap(allocator_and_data_.data_capacity,
- other.allocator_and_data_.data_capacity);
- }
- }
-
- friend void swap(QuicCircularDeque& lhs, QuicCircularDeque& rhs) {
- lhs.swap(rhs);
- }
-
- allocator_type get_allocator() const {
- return allocator_and_data_.allocator();
- }
-
- friend bool operator==(const QuicCircularDeque& lhs,
- const QuicCircularDeque& rhs) {
- return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
- }
-
- friend bool operator!=(const QuicCircularDeque& lhs,
- const QuicCircularDeque& rhs) {
- return !(lhs == rhs);
- }
-
- friend QUIC_NO_EXPORT std::ostream& operator<<(std::ostream& os,
- const QuicCircularDeque& dq) {
- os << "{";
- for (size_type pos = 0; pos != dq.size(); ++pos) {
- if (pos != 0) {
- os << ",";
- }
- os << " " << dq[pos];
- }
- os << " }";
- return os;
- }
-
- private:
- void MoveRetainAllocator(QuicCircularDeque&& other) {
- if (get_allocator() == other.get_allocator()) {
- // Take over the storage of "other", with which we share an allocator.
- DestroyAndDeallocateAll();
-
- begin_ = other.begin_;
- end_ = other.end_;
- allocator_and_data_.data = other.allocator_and_data_.data;
- allocator_and_data_.data_capacity =
- other.allocator_and_data_.data_capacity;
-
- other.begin_ = other.end_ = 0;
- other.allocator_and_data_.data = nullptr;
- other.allocator_and_data_.data_capacity = 0;
- } else {
- // We cannot take over of the storage from "other", since it has a
- // different allocator; we're stuck move-assigning elements individually.
- ClearRetainCapacity();
- for (auto& elem : other) {
- push_back(std::move(elem));
- }
- other.clear();
- }
- }
-
- template <
- typename InputIt,
- typename = std::enable_if_t<std::is_base_of<
- std::input_iterator_tag,
- typename std::iterator_traits<InputIt>::iterator_category>::value>>
- void AssignRange(InputIt first, InputIt last) {
- ClearRetainCapacity();
- if (std::is_base_of<
- std::random_access_iterator_tag,
- typename std::iterator_traits<InputIt>::iterator_category>::value) {
- reserve(std::distance(first, last));
- }
- for (; first != last; ++first) {
- emplace_back(*first);
- }
- }
-
- // WARNING: begin_, end_ and allocator_and_data_ are not modified.
- void DestroyAndDeallocateAll() {
- DestroyRange(begin_, end_);
-
- if (data_capacity() > 0) {
- QUICHE_DCHECK_NE(nullptr, allocator_and_data_.data);
- AllocatorTraits::deallocate(allocator_and_data_.allocator(),
- allocator_and_data_.data, data_capacity());
- }
- }
-
- void ClearRetainCapacity() {
- DestroyRange(begin_, end_);
- begin_ = end_ = 0;
- }
-
- void MaybeShrinkCapacity() {
- // TODO(wub): Implement a storage policy that actually shrinks.
- }
-
- void MaybeExpandCapacity(size_t num_additional_elements) {
- size_t new_size = size() + num_additional_elements;
- if (capacity() >= new_size) {
- return;
- }
-
- // The minimum amount of additional capacity to grow.
- size_t min_additional_capacity =
- std::max(MinCapacityIncrement, capacity() / 4);
- size_t new_capacity =
- std::max(new_size, capacity() + min_additional_capacity);
-
- Relocate(new_capacity);
- }
-
- void Relocate(size_t new_capacity) {
- const size_t num_elements = size();
- QUICHE_DCHECK_GT(new_capacity, num_elements)
- << "new_capacity:" << new_capacity << ", num_elements:" << num_elements;
-
- size_t new_data_capacity = new_capacity + 1;
- pointer new_data = AllocatorTraits::allocate(
- allocator_and_data_.allocator(), new_data_capacity);
-
- if (begin_ < end_) {
- // Not wrapped.
- RelocateUnwrappedRange(begin_, end_, new_data);
- } else if (begin_ > end_) {
- // Wrapped.
- const size_t num_elements_before_wrap = data_capacity() - begin_;
- RelocateUnwrappedRange(begin_, data_capacity(), new_data);
- RelocateUnwrappedRange(0, end_, new_data + num_elements_before_wrap);
- }
-
- if (data_capacity()) {
- AllocatorTraits::deallocate(allocator_and_data_.allocator(),
- allocator_and_data_.data, data_capacity());
- }
-
- allocator_and_data_.data = new_data;
- allocator_and_data_.data_capacity = new_data_capacity;
- begin_ = 0;
- end_ = num_elements;
- }
-
- template <typename T_ = T>
- typename std::enable_if<std::is_trivially_copyable<T_>::value, void>::type
- RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const {
- QUICHE_DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end;
- pointer src = index_to_address(begin);
- QUICHE_DCHECK_NE(src, nullptr);
- memcpy(dest, src, sizeof(T) * (end - begin));
- DestroyRange(begin, end);
- }
-
- template <typename T_ = T>
- typename std::enable_if<!std::is_trivially_copyable<T_>::value &&
- std::is_move_constructible<T_>::value,
- void>::type
- RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const {
- QUICHE_DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end;
- pointer src = index_to_address(begin);
- pointer src_end = index_to_address(end);
- while (src != src_end) {
- new (dest) T(std::move(*src));
- DestroyByAddress(src);
- ++dest;
- ++src;
- }
- }
-
- template <typename T_ = T>
- typename std::enable_if<!std::is_trivially_copyable<T_>::value &&
- !std::is_move_constructible<T_>::value,
- void>::type
- RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const {
- QUICHE_DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end;
- pointer src = index_to_address(begin);
- pointer src_end = index_to_address(end);
- while (src != src_end) {
- new (dest) T(*src);
- DestroyByAddress(src);
- ++dest;
- ++src;
- }
- }
-
- template <class... U>
- void ResizeInternal(size_type count, U&&... u) {
- if (count > size()) {
- // Expanding.
- MaybeExpandCapacity(count - size());
- while (size() < count) {
- emplace_back(std::forward<U>(u)...);
- }
- } else {
- // Most likely shrinking. No-op if count == size().
- size_type new_end = (begin_ + count) % data_capacity();
- DestroyRange(new_end, end_);
- end_ = new_end;
-
- MaybeShrinkCapacity();
- }
- }
-
- void DestroyRange(size_type begin, size_type end) const {
- if (std::is_trivially_destructible<T>::value) {
- return;
- }
- if (end >= begin) {
- DestroyUnwrappedRange(begin, end);
- } else {
- DestroyUnwrappedRange(begin, data_capacity());
- DestroyUnwrappedRange(0, end);
- }
- }
-
- // Should only be called from DestroyRange.
- void DestroyUnwrappedRange(size_type begin, size_type end) const {
- QUICHE_DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end;
- for (; begin != end; ++begin) {
- DestroyByIndex(begin);
- }
- }
-
- void DestroyByIndex(size_type index) const {
- DestroyByAddress(index_to_address(index));
- }
-
- void DestroyByAddress(pointer address) const {
- if (std::is_trivially_destructible<T>::value) {
- return;
- }
- address->~T();
- }
-
- size_type data_capacity() const { return allocator_and_data_.data_capacity; }
-
- pointer index_to_address(size_type index) const {
- return allocator_and_data_.data + index;
- }
-
- size_type index_prev(size_type index) const {
- return index == 0 ? data_capacity() - 1 : index - 1;
- }
-
- size_type index_next(size_type index) const {
- return index == data_capacity() - 1 ? 0 : index + 1;
- }
-
- size_type index_increment_by(size_type index, difference_type delta) const {
- if (delta == 0) {
- return index;
- }
-
- QUICHE_DCHECK_LT(static_cast<size_type>(std::abs(delta)), data_capacity());
- return (index + data_capacity() + delta) % data_capacity();
- }
-
- // Empty base-class optimization: bundle storage for our allocator together
- // with the fields we had to store anyway, via inheriting from the allocator,
- // so this allocator instance doesn't consume any storage when its type has no
- // data members.
- struct AllocatorAndData : private allocator_type {
- explicit AllocatorAndData(const allocator_type& alloc)
- : allocator_type(alloc) {}
-
- const allocator_type& allocator() const { return *this; }
- allocator_type& allocator() { return *this; }
-
- pointer data = nullptr;
- size_type data_capacity = 0;
- };
-
- size_type begin_ = 0;
- size_type end_ = 0;
- AllocatorAndData allocator_and_data_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc
deleted file mode 100644
index 25aa78e709a..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc
+++ /dev/null
@@ -1,796 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "quic/core/quic_circular_deque.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <type_traits>
-
-#include "quic/platform/api/quic_logging.h"
-#include "quic/platform/api/quic_test.h"
-
-using testing::ElementsAre;
-
-namespace quic {
-namespace test {
-namespace {
-
-template <typename T, template <typename> class BaseAllocator = std::allocator>
-class CountingAllocator : public BaseAllocator<T> {
- using BaseType = BaseAllocator<T>;
-
- public:
- using propagate_on_container_copy_assignment = std::true_type;
- using propagate_on_container_move_assignment = std::true_type;
- using propagate_on_container_swap = std::true_type;
-
- T* allocate(std::size_t n) {
- ++shared_counts_->allocate_count;
- return BaseType::allocate(n);
- }
-
- void deallocate(T* ptr, std::size_t n) {
- ++shared_counts_->deallocate_count;
- return BaseType::deallocate(ptr, n);
- }
-
- size_t allocate_count() const { return shared_counts_->allocate_count; }
-
- size_t deallocate_count() const { return shared_counts_->deallocate_count; }
-
- friend bool operator==(const CountingAllocator& lhs,
- const CountingAllocator& rhs) {
- return lhs.shared_counts_ == rhs.shared_counts_;
- }
-
- friend bool operator!=(const CountingAllocator& lhs,
- const CountingAllocator& rhs) {
- return !(lhs == rhs);
- }
-
- private:
- struct Counts {
- size_t allocate_count = 0;
- size_t deallocate_count = 0;
- };
-
- std::shared_ptr<Counts> shared_counts_ = std::make_shared<Counts>();
-};
-
-template <typename T,
- typename propagate_on_copy_assignment,
- typename propagate_on_move_assignment,
- typename propagate_on_swap,
- bool equality_result,
- template <typename> class BaseAllocator = std::allocator>
-struct ConfigurableAllocator : public BaseAllocator<T> {
- using propagate_on_container_copy_assignment = propagate_on_copy_assignment;
- using propagate_on_container_move_assignment = propagate_on_move_assignment;
- using propagate_on_container_swap = propagate_on_swap;
-
- friend bool operator==(const ConfigurableAllocator& /*lhs*/,
- const ConfigurableAllocator& /*rhs*/) {
- return equality_result;
- }
-
- friend bool operator!=(const ConfigurableAllocator& lhs,
- const ConfigurableAllocator& rhs) {
- return !(lhs == rhs);
- }
-};
-
-// [1, 2, 3, 4] ==> [4, 1, 2, 3]
-template <typename Deque>
-void ShiftRight(Deque* dq, bool emplace) {
- auto back = *(&dq->back());
- dq->pop_back();
- if (emplace) {
- dq->emplace_front(back);
- } else {
- dq->push_front(back);
- }
-}
-
-// [1, 2, 3, 4] ==> [2, 3, 4, 1]
-template <typename Deque>
-void ShiftLeft(Deque* dq, bool emplace) {
- auto front = *(&dq->front());
- dq->pop_front();
- if (emplace) {
- dq->emplace_back(front);
- } else {
- dq->push_back(front);
- }
-}
-
-class QuicCircularDequeTest : public QuicTest {};
-
-TEST_F(QuicCircularDequeTest, Empty) {
- QuicCircularDeque<int> dq;
- EXPECT_TRUE(dq.empty());
- EXPECT_EQ(0u, dq.size());
- dq.clear();
- dq.push_back(10);
- EXPECT_FALSE(dq.empty());
- EXPECT_EQ(1u, dq.size());
- EXPECT_EQ(10, dq.front());
- EXPECT_EQ(10, dq.back());
- dq.pop_front();
- EXPECT_TRUE(dq.empty());
- EXPECT_EQ(0u, dq.size());
-
- EXPECT_QUIC_DEBUG_DEATH(dq.front(), "");
- EXPECT_QUIC_DEBUG_DEATH(dq.back(), "");
- EXPECT_QUIC_DEBUG_DEATH(dq.at(0), "");
- EXPECT_QUIC_DEBUG_DEATH(dq[0], "");
-}
-
-TEST_F(QuicCircularDequeTest, Constructor) {
- QuicCircularDeque<int> dq;
- EXPECT_TRUE(dq.empty());
-
- std::allocator<int> alloc;
- QuicCircularDeque<int> dq1(alloc);
- EXPECT_TRUE(dq1.empty());
-
- QuicCircularDeque<int> dq2(8, 100, alloc);
- EXPECT_THAT(dq2, ElementsAre(100, 100, 100, 100, 100, 100, 100, 100));
-
- QuicCircularDeque<int> dq3(5, alloc);
- EXPECT_THAT(dq3, ElementsAre(0, 0, 0, 0, 0));
-
- QuicCircularDeque<int> dq4_rand_iter(dq3.begin(), dq3.end(), alloc);
- EXPECT_THAT(dq4_rand_iter, ElementsAre(0, 0, 0, 0, 0));
- EXPECT_EQ(dq4_rand_iter, dq3);
-
- std::list<int> dq4_src = {4, 4, 4, 4};
- QuicCircularDeque<int> dq4_bidi_iter(dq4_src.begin(), dq4_src.end());
- EXPECT_THAT(dq4_bidi_iter, ElementsAre(4, 4, 4, 4));
-
- QuicCircularDeque<int> dq5(dq4_bidi_iter);
- EXPECT_THAT(dq5, ElementsAre(4, 4, 4, 4));
- EXPECT_EQ(dq5, dq4_bidi_iter);
-
- QuicCircularDeque<int> dq6(dq5, alloc);
- EXPECT_THAT(dq6, ElementsAre(4, 4, 4, 4));
- EXPECT_EQ(dq6, dq5);
-
- QuicCircularDeque<int> dq7(std::move(*&dq6));
- EXPECT_THAT(dq7, ElementsAre(4, 4, 4, 4));
- EXPECT_TRUE(dq6.empty());
-
- QuicCircularDeque<int> dq8_equal_allocator(std::move(*&dq7), alloc);
- EXPECT_THAT(dq8_equal_allocator, ElementsAre(4, 4, 4, 4));
- EXPECT_TRUE(dq7.empty());
-
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq8_temp = {5, 6, 7, 8, 9};
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq8_unequal_allocator(
- std::move(*&dq8_temp), CountingAllocator<int>());
- EXPECT_THAT(dq8_unequal_allocator, ElementsAre(5, 6, 7, 8, 9));
- EXPECT_TRUE(dq8_temp.empty());
-
- QuicCircularDeque<int> dq9({3, 4, 5, 6, 7}, alloc);
- EXPECT_THAT(dq9, ElementsAre(3, 4, 5, 6, 7));
-}
-
-TEST_F(QuicCircularDequeTest, Assign) {
- // assign()
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq;
- dq.assign(7, 1);
- EXPECT_THAT(dq, ElementsAre(1, 1, 1, 1, 1, 1, 1));
- EXPECT_EQ(1u, dq.get_allocator().allocate_count());
-
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq2;
- dq2.assign(dq.begin(), dq.end());
- EXPECT_THAT(dq2, ElementsAre(1, 1, 1, 1, 1, 1, 1));
- EXPECT_EQ(1u, dq2.get_allocator().allocate_count());
- EXPECT_TRUE(std::equal(dq.begin(), dq.end(), dq2.begin(), dq2.end()));
-
- dq2.assign({2, 2, 2, 2, 2, 2});
- EXPECT_THAT(dq2, ElementsAre(2, 2, 2, 2, 2, 2));
-
- // Assign from a non random access iterator.
- std::list<int> dq3_src = {3, 3, 3, 3, 3};
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq3;
- dq3.assign(dq3_src.begin(), dq3_src.end());
- EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3));
- EXPECT_LT(1u, dq3.get_allocator().allocate_count());
-
- // Copy assignment
- dq3 = *&dq3;
- EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3));
-
- QuicCircularDeque<
- int, 3,
- ConfigurableAllocator<int,
- /*propagate_on_copy_assignment=*/std::true_type,
- /*propagate_on_move_assignment=*/std::true_type,
- /*propagate_on_swap=*/std::true_type,
- /*equality_result=*/false>>
- dq4, dq5;
- dq4.assign(dq3.begin(), dq3.end());
- dq5 = dq4;
- EXPECT_THAT(dq5, ElementsAre(3, 3, 3, 3, 3));
-
- QuicCircularDeque<
- int, 3,
- ConfigurableAllocator<int,
- /*propagate_on_copy_assignment=*/std::false_type,
- /*propagate_on_move_assignment=*/std::true_type,
- /*propagate_on_swap=*/std::true_type,
- /*equality_result=*/true>>
- dq6, dq7;
- dq6.assign(dq3.begin(), dq3.end());
- dq7 = dq6;
- EXPECT_THAT(dq7, ElementsAre(3, 3, 3, 3, 3));
-
- // Move assignment
- dq3 = std::move(*&dq3);
- EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3));
-
- ASSERT_TRUE(decltype(
- dq3.get_allocator())::propagate_on_container_move_assignment::value);
- decltype(dq3) dq8;
- dq8 = std::move(*&dq3);
- EXPECT_THAT(dq8, ElementsAre(3, 3, 3, 3, 3));
- EXPECT_TRUE(dq3.empty());
-
- QuicCircularDeque<
- int, 3,
- ConfigurableAllocator<int,
- /*propagate_on_copy_assignment=*/std::true_type,
- /*propagate_on_move_assignment=*/std::false_type,
- /*propagate_on_swap=*/std::true_type,
- /*equality_result=*/true>>
- dq9, dq10;
- dq9.assign(dq8.begin(), dq8.end());
- dq10.assign(dq2.begin(), dq2.end());
- dq9 = std::move(*&dq10);
- EXPECT_THAT(dq9, ElementsAre(2, 2, 2, 2, 2, 2));
- EXPECT_TRUE(dq10.empty());
-
- QuicCircularDeque<
- int, 3,
- ConfigurableAllocator<int,
- /*propagate_on_copy_assignment=*/std::true_type,
- /*propagate_on_move_assignment=*/std::false_type,
- /*propagate_on_swap=*/std::true_type,
- /*equality_result=*/false>>
- dq11, dq12;
- dq11.assign(dq8.begin(), dq8.end());
- dq12.assign(dq2.begin(), dq2.end());
- dq11 = std::move(*&dq12);
- EXPECT_THAT(dq11, ElementsAre(2, 2, 2, 2, 2, 2));
- EXPECT_TRUE(dq12.empty());
-}
-
-TEST_F(QuicCircularDequeTest, Access) {
- // at()
- // operator[]
- // front()
- // back()
-
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq;
- dq.push_back(10);
- EXPECT_EQ(dq.front(), 10);
- EXPECT_EQ(dq.back(), 10);
- EXPECT_EQ(dq.at(0), 10);
- EXPECT_EQ(dq[0], 10);
- dq.front() = 12;
- EXPECT_EQ(dq.front(), 12);
- EXPECT_EQ(dq.back(), 12);
- EXPECT_EQ(dq.at(0), 12);
- EXPECT_EQ(dq[0], 12);
-
- const auto& dqref = dq;
- EXPECT_EQ(dqref.front(), 12);
- EXPECT_EQ(dqref.back(), 12);
- EXPECT_EQ(dqref.at(0), 12);
- EXPECT_EQ(dqref[0], 12);
-
- dq.pop_front();
- EXPECT_TRUE(dqref.empty());
-
- // Push to capacity.
- dq.push_back(15);
- dq.push_front(5);
- dq.push_back(25);
- EXPECT_EQ(dq.size(), dq.capacity());
- EXPECT_THAT(dq, ElementsAre(5, 15, 25));
- EXPECT_LT(&dq.front(), &dq.back());
- EXPECT_EQ(dq.front(), 5);
- EXPECT_EQ(dq.back(), 25);
- EXPECT_EQ(dq.at(0), 5);
- EXPECT_EQ(dq.at(1), 15);
- EXPECT_EQ(dq.at(2), 25);
- EXPECT_EQ(dq[0], 5);
- EXPECT_EQ(dq[1], 15);
- EXPECT_EQ(dq[2], 25);
-
- // Shift right such that begin=1 and end=0. Data is still not wrapped.
- dq.pop_front();
- dq.push_back(35);
- EXPECT_THAT(dq, ElementsAre(15, 25, 35));
- EXPECT_LT(&dq.front(), &dq.back());
- EXPECT_EQ(dq.front(), 15);
- EXPECT_EQ(dq.back(), 35);
- EXPECT_EQ(dq.at(0), 15);
- EXPECT_EQ(dq.at(1), 25);
- EXPECT_EQ(dq.at(2), 35);
- EXPECT_EQ(dq[0], 15);
- EXPECT_EQ(dq[1], 25);
- EXPECT_EQ(dq[2], 35);
-
- // Shift right such that data is wrapped.
- dq.pop_front();
- dq.push_back(45);
- EXPECT_THAT(dq, ElementsAre(25, 35, 45));
- EXPECT_GT(&dq.front(), &dq.back());
- EXPECT_EQ(dq.front(), 25);
- EXPECT_EQ(dq.back(), 45);
- EXPECT_EQ(dq.at(0), 25);
- EXPECT_EQ(dq.at(1), 35);
- EXPECT_EQ(dq.at(2), 45);
- EXPECT_EQ(dq[0], 25);
- EXPECT_EQ(dq[1], 35);
- EXPECT_EQ(dq[2], 45);
-
- // Shift right again, data is still wrapped.
- dq.pop_front();
- dq.push_back(55);
- EXPECT_THAT(dq, ElementsAre(35, 45, 55));
- EXPECT_GT(&dq.front(), &dq.back());
- EXPECT_EQ(dq.front(), 35);
- EXPECT_EQ(dq.back(), 55);
- EXPECT_EQ(dq.at(0), 35);
- EXPECT_EQ(dq.at(1), 45);
- EXPECT_EQ(dq.at(2), 55);
- EXPECT_EQ(dq[0], 35);
- EXPECT_EQ(dq[1], 45);
- EXPECT_EQ(dq[2], 55);
-
- // Shift right one last time. begin returns to 0. Data is no longer wrapped.
- dq.pop_front();
- dq.push_back(65);
- EXPECT_THAT(dq, ElementsAre(45, 55, 65));
- EXPECT_LT(&dq.front(), &dq.back());
- EXPECT_EQ(dq.front(), 45);
- EXPECT_EQ(dq.back(), 65);
- EXPECT_EQ(dq.at(0), 45);
- EXPECT_EQ(dq.at(1), 55);
- EXPECT_EQ(dq.at(2), 65);
- EXPECT_EQ(dq[0], 45);
- EXPECT_EQ(dq[1], 55);
- EXPECT_EQ(dq[2], 65);
-
- EXPECT_EQ(1u, dq.get_allocator().allocate_count());
-}
-
-TEST_F(QuicCircularDequeTest, Iterate) {
- QuicCircularDeque<int> dq;
- EXPECT_EQ(dq.begin(), dq.end());
- EXPECT_EQ(dq.cbegin(), dq.cend());
- EXPECT_EQ(dq.rbegin(), dq.rend());
- EXPECT_EQ(dq.crbegin(), dq.crend());
-
- dq.emplace_back(2);
- QuicCircularDeque<int>::const_iterator citer = dq.begin();
- EXPECT_NE(citer, dq.end());
- EXPECT_EQ(*citer, 2);
- ++citer;
- EXPECT_EQ(citer, dq.end());
-
- EXPECT_EQ(*dq.begin(), 2);
- EXPECT_EQ(*dq.cbegin(), 2);
- EXPECT_EQ(*dq.rbegin(), 2);
- EXPECT_EQ(*dq.crbegin(), 2);
-
- dq.emplace_front(1);
- QuicCircularDeque<int>::const_reverse_iterator criter = dq.rbegin();
- EXPECT_NE(criter, dq.rend());
- EXPECT_EQ(*criter, 2);
- ++criter;
- EXPECT_NE(criter, dq.rend());
- EXPECT_EQ(*criter, 1);
- ++criter;
- EXPECT_EQ(criter, dq.rend());
-
- EXPECT_EQ(*dq.begin(), 1);
- EXPECT_EQ(*dq.cbegin(), 1);
- EXPECT_EQ(*dq.rbegin(), 2);
- EXPECT_EQ(*dq.crbegin(), 2);
-
- dq.push_back(3);
-
- // Forward iterate.
- int expected_value = 1;
- for (QuicCircularDeque<int>::iterator it = dq.begin(); it != dq.end(); ++it) {
- EXPECT_EQ(expected_value++, *it);
- }
-
- expected_value = 1;
- for (QuicCircularDeque<int>::const_iterator it = dq.cbegin(); it != dq.cend();
- ++it) {
- EXPECT_EQ(expected_value++, *it);
- }
-
- // Reverse iterate.
- expected_value = 3;
- for (QuicCircularDeque<int>::reverse_iterator it = dq.rbegin();
- it != dq.rend(); ++it) {
- EXPECT_EQ(expected_value--, *it);
- }
-
- expected_value = 3;
- for (QuicCircularDeque<int>::const_reverse_iterator it = dq.crbegin();
- it != dq.crend(); ++it) {
- EXPECT_EQ(expected_value--, *it);
- }
-}
-
-TEST_F(QuicCircularDequeTest, Iterator) {
- // Default constructed iterators of the same type compare equal.
- EXPECT_EQ(QuicCircularDeque<int>::iterator(),
- QuicCircularDeque<int>::iterator());
- EXPECT_EQ(QuicCircularDeque<int>::const_iterator(),
- QuicCircularDeque<int>::const_iterator());
- EXPECT_EQ(QuicCircularDeque<int>::reverse_iterator(),
- QuicCircularDeque<int>::reverse_iterator());
- EXPECT_EQ(QuicCircularDeque<int>::const_reverse_iterator(),
- QuicCircularDeque<int>::const_reverse_iterator());
-
- QuicCircularDeque<QuicCircularDeque<int>, 3> dqdq = {
- {1, 2}, {10, 20, 30}, {100, 200, 300, 400}};
-
- // iter points to {1, 2}
- decltype(dqdq)::iterator iter = dqdq.begin();
- EXPECT_EQ(iter->size(), 2u);
- EXPECT_THAT(*iter, ElementsAre(1, 2));
-
- // citer points to {10, 20, 30}
- decltype(dqdq)::const_iterator citer = dqdq.cbegin() + 1;
- EXPECT_NE(*iter, *citer);
- EXPECT_EQ(citer->size(), 3u);
- int x = 10;
- for (auto it = citer->begin(); it != citer->end(); ++it) {
- EXPECT_EQ(*it, x);
- x += 10;
- }
-
- EXPECT_LT(iter, citer);
- EXPECT_LE(iter, iter);
- EXPECT_GT(citer, iter);
- EXPECT_GE(citer, citer);
-
- // iter points to {100, 200, 300, 400}
- iter += 2;
- EXPECT_NE(*iter, *citer);
- EXPECT_EQ(iter->size(), 4u);
- for (int i = 1; i <= 4; ++i) {
- EXPECT_EQ(iter->begin()[i - 1], i * 100);
- }
-
- EXPECT_LT(citer, iter);
- EXPECT_LE(iter, iter);
- EXPECT_GT(iter, citer);
- EXPECT_GE(citer, citer);
-
- // iter points to {10, 20, 30}. (same as citer)
- iter -= 1;
- EXPECT_EQ(*iter, *citer);
- EXPECT_EQ(iter->size(), 3u);
- x = 10;
- for (auto it = iter->begin(); it != iter->end();) {
- EXPECT_EQ(*(it++), x);
- x += 10;
- }
- x = 30;
- for (auto it = iter->begin() + 2; it != iter->begin();) {
- EXPECT_EQ(*(it--), x);
- x -= 10;
- }
-}
-
-TEST_F(QuicCircularDequeTest, Resize) {
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq;
- dq.resize(8);
- EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0));
- EXPECT_EQ(1u, dq.get_allocator().allocate_count());
-
- dq.resize(10, 5);
- EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0, 5, 5));
-
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq2 = dq;
-
- for (size_t new_size = dq.size(); new_size != 0; --new_size) {
- dq.resize(new_size);
- EXPECT_TRUE(
- std::equal(dq.begin(), dq.end(), dq2.begin(), dq2.begin() + new_size));
- }
-
- dq.resize(0);
- EXPECT_TRUE(dq.empty());
-
- // Resize when data is wrapped.
- ASSERT_EQ(dq2.size(), dq2.capacity());
- while (dq2.size() < dq2.capacity()) {
- dq2.push_back(5);
- }
-
- // Shift left once such that data is wrapped.
- ASSERT_LT(&dq2.front(), &dq2.back());
- dq2.pop_back();
- dq2.push_front(-5);
- ASSERT_GT(&dq2.front(), &dq2.back());
-
- EXPECT_EQ(-5, dq2.front());
- EXPECT_EQ(5, dq2.back());
- dq2.resize(dq2.size() + 1, 10);
-
- // Data should be unwrapped after the resize.
- ASSERT_LT(&dq2.front(), &dq2.back());
- EXPECT_EQ(-5, dq2.front());
- EXPECT_EQ(10, dq2.back());
- EXPECT_EQ(5, *(dq2.rbegin() + 1));
-}
-
-namespace {
-class Foo {
- public:
- Foo() : Foo(0xF00) {}
-
- explicit Foo(int i) : i_(new int(i)) {}
-
- ~Foo() {
- if (i_ != nullptr) {
- delete i_;
- // Do not set i_ to nullptr such that if the container calls destructor
- // multiple times, asan can detect it.
- }
- }
-
- Foo(const Foo& other) : i_(new int(*other.i_)) {}
-
- Foo(Foo&& other) = delete;
-
- void Set(int i) { *i_ = i; }
-
- int i() const { return *i_; }
-
- friend bool operator==(const Foo& lhs, const Foo& rhs) {
- return lhs.i() == rhs.i();
- }
-
- friend std::ostream& operator<<(std::ostream& os, const Foo& foo) {
- return os << "Foo(" << foo.i() << ")";
- }
-
- private:
- // By pointing i_ to a dynamically allocated integer, a memory leak will be
- // reported if the container forget to properly destruct this object.
- int* i_ = nullptr;
-};
-} // namespace
-
-TEST_F(QuicCircularDequeTest, RelocateNonTriviallyCopyable) {
- // When relocating non-trivially-copyable objects:
- // - Move constructor is preferred, if available.
- // - Copy constructor is used otherwise.
-
- {
- // Move construct in Relocate.
- using MoveConstructible = std::unique_ptr<Foo>;
- ASSERT_FALSE(std::is_trivially_copyable<MoveConstructible>::value);
- ASSERT_TRUE(std::is_move_constructible<MoveConstructible>::value);
- QuicCircularDeque<MoveConstructible, 3,
- CountingAllocator<MoveConstructible>>
- dq1;
- dq1.resize(3);
- EXPECT_EQ(dq1.size(), dq1.capacity());
- EXPECT_EQ(1u, dq1.get_allocator().allocate_count());
-
- dq1.emplace_back(new Foo(0xF1)); // Cause existing elements to relocate.
- EXPECT_EQ(4u, dq1.size());
- EXPECT_EQ(2u, dq1.get_allocator().allocate_count());
- EXPECT_EQ(dq1[0], nullptr);
- EXPECT_EQ(dq1[1], nullptr);
- EXPECT_EQ(dq1[2], nullptr);
- EXPECT_EQ(dq1[3]->i(), 0xF1);
- }
-
- {
- // Copy construct in Relocate.
- using NonMoveConstructible = Foo;
- ASSERT_FALSE(std::is_trivially_copyable<NonMoveConstructible>::value);
- ASSERT_FALSE(std::is_move_constructible<NonMoveConstructible>::value);
- QuicCircularDeque<NonMoveConstructible, 3,
- CountingAllocator<NonMoveConstructible>>
- dq2;
- dq2.resize(3);
- EXPECT_EQ(dq2.size(), dq2.capacity());
- EXPECT_EQ(1u, dq2.get_allocator().allocate_count());
-
- dq2.emplace_back(0xF1); // Cause existing elements to relocate.
- EXPECT_EQ(4u, dq2.size());
- EXPECT_EQ(2u, dq2.get_allocator().allocate_count());
- EXPECT_EQ(dq2[0].i(), 0xF00);
- EXPECT_EQ(dq2[1].i(), 0xF00);
- EXPECT_EQ(dq2[2].i(), 0xF00);
- EXPECT_EQ(dq2[3].i(), 0xF1);
- }
-}
-
-TEST_F(QuicCircularDequeTest, PushPop) {
- // (push|pop|emplace)_(back|front)
-
- {
- QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq(4);
- for (size_t i = 0; i < dq.size(); ++i) {
- dq[i].Set(i + 1);
- }
- QUIC_LOG(INFO) << "dq initialized to " << dq;
- EXPECT_THAT(dq, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4)));
-
- ShiftLeft(&dq, false);
- QUIC_LOG(INFO) << "shift left once : " << dq;
- EXPECT_THAT(dq, ElementsAre(Foo(2), Foo(3), Foo(4), Foo(1)));
-
- ShiftLeft(&dq, true);
- QUIC_LOG(INFO) << "shift left twice: " << dq;
- EXPECT_THAT(dq, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2)));
- ASSERT_GT(&dq.front(), &dq.back());
- // dq destructs with wrapped data.
- }
-
- {
- QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq1(4);
- for (size_t i = 0; i < dq1.size(); ++i) {
- dq1[i].Set(i + 1);
- }
- QUIC_LOG(INFO) << "dq1 initialized to " << dq1;
- EXPECT_THAT(dq1, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4)));
-
- ShiftRight(&dq1, false);
- QUIC_LOG(INFO) << "shift right once : " << dq1;
- EXPECT_THAT(dq1, ElementsAre(Foo(4), Foo(1), Foo(2), Foo(3)));
-
- ShiftRight(&dq1, true);
- QUIC_LOG(INFO) << "shift right twice: " << dq1;
- EXPECT_THAT(dq1, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2)));
- ASSERT_GT(&dq1.front(), &dq1.back());
- // dq1 destructs with wrapped data.
- }
-
- { // Pop n elements from front.
- QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq2(5);
- for (size_t i = 0; i < dq2.size(); ++i) {
- dq2[i].Set(i + 1);
- }
- EXPECT_THAT(dq2, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)));
-
- EXPECT_EQ(2u, dq2.pop_front_n(2));
- EXPECT_THAT(dq2, ElementsAre(Foo(3), Foo(4), Foo(5)));
-
- EXPECT_EQ(3u, dq2.pop_front_n(100));
- EXPECT_TRUE(dq2.empty());
- }
-
- { // Pop n elements from back.
- QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq3(6);
- for (size_t i = 0; i < dq3.size(); ++i) {
- dq3[i].Set(i + 1);
- }
- EXPECT_THAT(dq3,
- ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4), Foo(5), Foo(6)));
-
- ShiftRight(&dq3, true);
- ShiftRight(&dq3, true);
- ShiftRight(&dq3, true);
- EXPECT_THAT(dq3,
- ElementsAre(Foo(4), Foo(5), Foo(6), Foo(1), Foo(2), Foo(3)));
-
- EXPECT_EQ(2u, dq3.pop_back_n(2));
- EXPECT_THAT(dq3, ElementsAre(Foo(4), Foo(5), Foo(6), Foo(1)));
-
- EXPECT_EQ(2u, dq3.pop_back_n(2));
- EXPECT_THAT(dq3, ElementsAre(Foo(4), Foo(5)));
- }
-}
-
-TEST_F(QuicCircularDequeTest, Allocation) {
- CountingAllocator<int> alloc;
-
- {
- QuicCircularDeque<int, 3, CountingAllocator<int>> dq(alloc);
- EXPECT_EQ(alloc, dq.get_allocator());
- EXPECT_EQ(0u, dq.size());
- EXPECT_EQ(0u, dq.capacity());
- EXPECT_EQ(0u, alloc.allocate_count());
- EXPECT_EQ(0u, alloc.deallocate_count());
-
- for (int i = 1; i <= 18; ++i) {
- SCOPED_TRACE(testing::Message()
- << "i=" << i << ", capacity_b4_push=" << dq.capacity());
- dq.push_back(i);
- EXPECT_EQ(i, static_cast<int>(dq.size()));
-
- const size_t capacity = 3 + (i - 1) / 3 * 3;
- EXPECT_EQ(capacity, dq.capacity());
- EXPECT_EQ(capacity / 3, alloc.allocate_count());
- EXPECT_EQ(capacity / 3 - 1, alloc.deallocate_count());
- }
-
- dq.push_back(19);
- EXPECT_EQ(22u, dq.capacity()); // 18 + 18 / 4
- EXPECT_EQ(7u, alloc.allocate_count());
- EXPECT_EQ(6u, alloc.deallocate_count());
- }
-
- EXPECT_EQ(7u, alloc.deallocate_count());
-}
-
-} // namespace
-} // namespace test
-} // namespace quic
-
-// Use a non-quic namespace to make sure swap can be used via ADL.
-namespace {
-
-template <typename T>
-using SwappableAllocator = quic::test::ConfigurableAllocator<
- T,
- /*propagate_on_copy_assignment=*/std::true_type,
- /*propagate_on_move_assignment=*/std::true_type,
- /*propagate_on_swap=*/std::true_type,
- /*equality_result=*/true>;
-
-template <typename T>
-using UnswappableEqualAllocator = quic::test::ConfigurableAllocator<
- T,
- /*propagate_on_copy_assignment=*/std::true_type,
- /*propagate_on_move_assignment=*/std::true_type,
- /*propagate_on_swap=*/std::false_type,
- /*equality_result=*/true>;
-
-template <typename T>
-using UnswappableUnequalAllocator = quic::test::ConfigurableAllocator<
- T,
- /*propagate_on_copy_assignment=*/std::true_type,
- /*propagate_on_move_assignment=*/std::true_type,
- /*propagate_on_swap=*/std::false_type,
- /*equality_result=*/false>;
-
-using quic::test::QuicCircularDequeTest;
-
-TEST_F(QuicCircularDequeTest, Swap) {
- using std::swap;
-
- quic::QuicCircularDeque<int64_t, 3, SwappableAllocator<int64_t>> dq1, dq2;
- dq1.push_back(10);
- dq1.push_back(11);
- dq2.push_back(20);
- swap(dq1, dq2);
- EXPECT_THAT(dq1, ElementsAre(20));
- EXPECT_THAT(dq2, ElementsAre(10, 11));
-
- quic::QuicCircularDeque<char, 3, UnswappableEqualAllocator<char>> dq3, dq4;
- dq3 = {1, 2, 3, 4, 5};
- dq4 = {6, 7, 8, 9, 0};
- swap(dq3, dq4);
- EXPECT_THAT(dq3, ElementsAre(6, 7, 8, 9, 0));
- EXPECT_THAT(dq4, ElementsAre(1, 2, 3, 4, 5));
-
- quic::QuicCircularDeque<int, 3, UnswappableUnequalAllocator<int>> dq5, dq6;
- dq6.push_front(4);
-
- // Using UnswappableUnequalAllocator is ok as long as swap is not called.
- dq5.assign(dq6.begin(), dq6.end());
- EXPECT_THAT(dq5, ElementsAre(4));
-
- // Undefined behavior to swap between two containers with unequal allocators.
- EXPECT_QUIC_DEBUG_DEATH(swap(dq5, dq6), "Undefined swap behavior");
-}
-} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc
index 9bd21403263..09806f5a8a8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc
@@ -48,7 +48,7 @@
#include "quic/platform/api/quic_map_util.h"
#include "quic/platform/api/quic_server_stats.h"
#include "quic/platform/api/quic_socket_address.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
@@ -225,8 +225,8 @@ class ScopedCoalescedPacketClearer {
};
// Whether this incoming packet is allowed to replace our connection ID.
-bool PacketCanReplaceConnectionId(const QuicPacketHeader& header,
- Perspective perspective) {
+bool PacketCanReplaceServerConnectionId(const QuicPacketHeader& header,
+ Perspective perspective) {
return perspective == Perspective::IS_CLIENT &&
header.form == IETF_QUIC_LONG_HEADER_PACKET &&
header.version.IsKnown() &&
@@ -282,7 +282,12 @@ QuicConnection::QuicConnection(
client_connection_id_(EmptyQuicConnectionId()),
client_connection_id_is_set_(false),
direct_peer_address_(initial_peer_address),
- default_path_(initial_self_address, QuicSocketAddress()),
+ default_path_(initial_self_address,
+ QuicSocketAddress(),
+ /*client_connection_id=*/EmptyQuicConnectionId(),
+ server_connection_id,
+ /*stateless_reset_token_received=*/false,
+ /*stateless_reset_token=*/{}),
active_effective_peer_migration_type_(NO_CHANGE),
support_key_update_for_connection_(false),
last_packet_decrypted_(false),
@@ -329,7 +334,7 @@ QuicConnection::QuicConnection(
&arena_)),
visitor_(nullptr),
debug_visitor_(nullptr),
- packet_creator_(server_connection_id_, &framer_, random_generator_, this),
+ packet_creator_(server_connection_id, &framer_, random_generator_, this),
time_of_last_received_packet_(clock_->ApproximateNow()),
sent_packet_manager_(perspective,
clock_,
@@ -370,11 +375,7 @@ QuicConnection::QuicConnection(
encrypted_control_frames_ &&
GetQuicReloadableFlag(quic_use_encryption_level_context)),
path_validator_(alarm_factory_, &arena_, this, random_generator_),
- alternative_path_(QuicSocketAddress(), QuicSocketAddress()),
most_recent_frame_type_(NUM_FRAME_TYPES) {
- QUIC_BUG_IF(quic_bug_12714_1,
- !start_peer_migration_earlier_ && send_path_response_);
-
QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT ||
default_path_.self_address.IsInitialized());
@@ -384,12 +385,10 @@ QuicConnection::QuicConnection(
support_multiple_connection_ids_ =
version().HasIetfQuicFrames() &&
- framer_.do_not_synthesize_source_cid_for_short_header() &&
- GetQuicRestartFlag(quic_use_reference_counted_sesssion_map) &&
GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2) &&
GetQuicRestartFlag(
quic_dispatcher_support_multiple_cid_per_connection_v2) &&
- GetQuicReloadableFlag(quic_connection_support_multiple_cids_v2);
+ GetQuicReloadableFlag(quic_connection_support_multiple_cids_v4);
QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID "
<< server_connection_id
@@ -418,7 +417,7 @@ QuicConnection::QuicConnection(
MaybeEnableMultiplePacketNumberSpacesSupport();
QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT ||
supported_versions.size() == 1);
- InstallInitialCrypters(server_connection_id_);
+ InstallInitialCrypters(ServerConnectionId());
// On the server side, version negotiation has been done by the dispatcher,
// and the server connection is created with the right version.
@@ -449,6 +448,7 @@ void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) {
}
QuicConnection::~QuicConnection() {
+ QUICHE_DCHECK_GE(stats_.max_egress_mtu, long_term_mtu_);
if (owns_writer_) {
delete writer_;
}
@@ -482,9 +482,9 @@ bool QuicConnection::ValidateConfigConnectionIds(const QuicConfig& config) {
// Validate initial_source_connection_id.
QuicConnectionId expected_initial_source_connection_id;
if (perspective_ == Perspective::IS_CLIENT) {
- expected_initial_source_connection_id = server_connection_id_;
+ expected_initial_source_connection_id = ServerConnectionId();
} else {
- expected_initial_source_connection_id = client_connection_id_;
+ expected_initial_source_connection_id = ClientConnectionId();
}
if (!config.HasReceivedInitialSourceConnectionId() ||
config.ReceivedInitialSourceConnectionId() !=
@@ -585,6 +585,9 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
} else {
SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
config.max_idle_time_before_crypto_handshake());
+ if (config.HasClientRequestedIndependentOption(kCHSP, perspective_)) {
+ packet_creator_.set_chaos_protection_enabled(true);
+ }
}
if (support_multiple_connection_ids_ &&
@@ -679,8 +682,14 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
no_stop_waiting_frames_ = true;
}
if (config.HasReceivedStatelessResetToken()) {
- stateless_reset_token_received_ = true;
- received_stateless_reset_token_ = config.ReceivedStatelessResetToken();
+ if (use_connection_id_on_default_path_) {
+ default_path_.stateless_reset_token_received = true;
+ default_path_.stateless_reset_token =
+ config.ReceivedStatelessResetToken();
+ } else {
+ stateless_reset_token_received_ = true;
+ received_stateless_reset_token_ = config.ReceivedStatelessResetToken();
+ }
}
if (config.HasReceivedAckDelayExponent()) {
framer_.set_peer_ack_delay_exponent(config.ReceivedAckDelayExponent());
@@ -704,6 +713,17 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 6, 6);
validate_client_addresses_ = true;
}
+ // Having connection_migration_use_new_cid_ depends on the same set of flags
+ // and connection option on both client and server sides has the advantage of:
+ // 1) Less chance of skew in using new connection ID or not between client
+ // and server in unit tests with random flag combinations.
+ // 2) Client side's rollout can be protected by the same connection option.
+ connection_migration_use_new_cid_ =
+ support_multiple_connection_ids_ && validate_client_addresses_ &&
+ use_connection_id_on_default_path_ &&
+ group_path_response_and_challenge_sending_closer_ &&
+ GetQuicReloadableFlag(quic_drop_unsent_path_response) &&
+ GetQuicReloadableFlag(quic_connection_migration_use_new_cid_v2);
if (config.HasReceivedMaxPacketSize()) {
peer_max_packet_size_ = config.ReceivedMaxPacketSize();
MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
@@ -865,7 +885,7 @@ void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) {
// Check that any public reset packet with a different connection ID that was
// routed to this QuicConnection has been redirected before control reaches
// here. (Check for a bug regression.)
- QUICHE_DCHECK_EQ(server_connection_id_, packet.connection_id);
+ QUICHE_DCHECK_EQ(ServerConnectionId(), packet.connection_id);
QUICHE_DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
QUICHE_DCHECK(!version().HasIetfInvariantHeader());
if (debug_visitor_ != nullptr) {
@@ -903,7 +923,7 @@ void QuicConnection::OnVersionNegotiationPacket(
// Check that any public reset packet with a different connection ID that was
// routed to this QuicConnection has been redirected before control reaches
// here. (Check for a bug regression.)
- QUICHE_DCHECK_EQ(server_connection_id_, packet.connection_id);
+ QUICHE_DCHECK_EQ(ServerConnectionId(), packet.connection_id);
if (perspective_ == Perspective::IS_SERVER) {
const std::string error_details =
"Server received version negotiation packet.";
@@ -954,17 +974,17 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id,
absl::string_view retry_without_tag) {
QUICHE_DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
if (version().UsesTls()) {
- if (!CryptoUtils::ValidateRetryIntegrityTag(
- version(), server_connection_id_, retry_without_tag,
- retry_integrity_tag)) {
+ if (!CryptoUtils::ValidateRetryIntegrityTag(version(), ServerConnectionId(),
+ retry_without_tag,
+ retry_integrity_tag)) {
QUIC_DLOG(ERROR) << "Ignoring RETRY with invalid integrity tag";
return;
}
} else {
- if (original_connection_id != server_connection_id_) {
+ if (original_connection_id != ServerConnectionId()) {
QUIC_DLOG(ERROR) << "Ignoring RETRY with original connection ID "
<< original_connection_id << " not matching expected "
- << server_connection_id_ << " token "
+ << ServerConnectionId() << " token "
<< absl::BytesToHexString(retry_token);
return;
}
@@ -972,10 +992,10 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id,
framer_.set_drop_incoming_retry_packets(true);
stats_.retry_packet_processed = true;
QUIC_DLOG(INFO) << "Received RETRY, replacing connection ID "
- << server_connection_id_ << " with " << new_connection_id
+ << ServerConnectionId() << " with " << new_connection_id
<< ", received token " << absl::BytesToHexString(retry_token);
if (!original_destination_connection_id_.has_value()) {
- original_destination_connection_id_ = server_connection_id_;
+ original_destination_connection_id_ = ServerConnectionId();
}
QUICHE_DCHECK(!retry_source_connection_id_.has_value())
<< retry_source_connection_id_.value();
@@ -984,12 +1004,18 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id,
packet_creator_.SetRetryToken(retry_token);
// Reinstall initial crypters because the connection ID changed.
- InstallInitialCrypters(server_connection_id_);
+ InstallInitialCrypters(ServerConnectionId());
sent_packet_manager_.MarkInitialPacketsForRetransmission();
}
-bool QuicConnection::HasIncomingConnectionId(QuicConnectionId connection_id) {
+bool QuicConnection::HasIncomingConnectionId(
+ QuicConnectionId connection_id) const {
+ if (quic_deprecate_incoming_connection_ids_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_incoming_connection_ids);
+ // TODO(haoyuewang) Inline this after the flag is deprecated.
+ return connection_id == original_destination_connection_id_;
+ }
for (QuicConnectionId const& incoming_connection_id :
incoming_connection_ids_) {
if (incoming_connection_id == connection_id) {
@@ -1004,54 +1030,89 @@ void QuicConnection::SetOriginalDestinationConnectionId(
QUIC_DLOG(INFO) << "Setting original_destination_connection_id to "
<< original_destination_connection_id
<< " on connection with server_connection_id "
- << server_connection_id_;
- QUICHE_DCHECK_NE(original_destination_connection_id, server_connection_id_);
- if (!HasIncomingConnectionId(original_destination_connection_id)) {
- incoming_connection_ids_.push_back(original_destination_connection_id);
+ << ServerConnectionId();
+ QUICHE_DCHECK_NE(original_destination_connection_id, ServerConnectionId());
+ if (!quic_deprecate_incoming_connection_ids_) {
+ if (!HasIncomingConnectionId(original_destination_connection_id)) {
+ incoming_connection_ids_.push_back(original_destination_connection_id);
+ }
}
InstallInitialCrypters(original_destination_connection_id);
QUICHE_DCHECK(!original_destination_connection_id_.has_value())
<< original_destination_connection_id_.value();
original_destination_connection_id_ = original_destination_connection_id;
+ original_destination_connection_id_replacement_ = ServerConnectionId();
}
QuicConnectionId QuicConnection::GetOriginalDestinationConnectionId() {
if (original_destination_connection_id_.has_value()) {
return original_destination_connection_id_.value();
}
- return server_connection_id_;
+ return ServerConnectionId();
+}
+
+bool QuicConnection::ValidateServerConnectionId(
+ const QuicPacketHeader& header) const {
+ if (perspective_ == Perspective::IS_CLIENT &&
+ header.form == IETF_QUIC_SHORT_HEADER_PACKET) {
+ return true;
+ }
+
+ QuicConnectionId server_connection_id =
+ GetServerConnectionIdAsRecipient(header, perspective_);
+
+ if (server_connection_id == ServerConnectionId() ||
+ HasIncomingConnectionId(server_connection_id)) {
+ return true;
+ }
+
+ if (PacketCanReplaceServerConnectionId(header, perspective_)) {
+ QUIC_DLOG(INFO) << ENDPOINT << "Accepting packet with new connection ID "
+ << server_connection_id << " instead of "
+ << ServerConnectionId();
+ return true;
+ }
+
+ if (connection_migration_use_new_cid_ &&
+ perspective_ == Perspective::IS_SERVER &&
+ self_issued_cid_manager_ != nullptr &&
+ self_issued_cid_manager_->IsConnectionIdInUse(server_connection_id)) {
+ return true;
+ }
+
+ return false;
}
bool QuicConnection::OnUnauthenticatedPublicHeader(
const QuicPacketHeader& header) {
+ last_packet_destination_connection_id_ = header.destination_connection_id;
+ // If last packet destination connection ID is the original server
+ // connection ID chosen by client, replaces it with the connection ID chosen
+ // by server.
+ if (use_connection_id_on_default_path_ &&
+ perspective_ == Perspective::IS_SERVER &&
+ original_destination_connection_id_.has_value() &&
+ last_packet_destination_connection_id_ ==
+ *original_destination_connection_id_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_connection_id_on_default_path_v2, 3,
+ 3);
+ last_packet_destination_connection_id_ =
+ original_destination_connection_id_replacement_;
+ }
+
// As soon as we receive an initial we start ignoring subsequent retries.
if (header.version_flag && header.long_packet_type == INITIAL) {
framer_.set_drop_incoming_retry_packets(true);
}
- bool skip_server_connection_id_validation =
- framer_.do_not_synthesize_source_cid_for_short_header() &&
- perspective_ == Perspective::IS_CLIENT &&
- header.form == IETF_QUIC_SHORT_HEADER_PACKET;
-
- QuicConnectionId server_connection_id =
- GetServerConnectionIdAsRecipient(header, perspective_);
-
- if (!skip_server_connection_id_validation &&
- server_connection_id != server_connection_id_ &&
- !HasIncomingConnectionId(server_connection_id)) {
- if (PacketCanReplaceConnectionId(header, perspective_)) {
- QUIC_DLOG(INFO) << ENDPOINT << "Accepting packet with new connection ID "
- << server_connection_id << " instead of "
- << server_connection_id_;
- return true;
- }
-
+ if (!ValidateServerConnectionId(header)) {
++stats_.packets_dropped;
+ QuicConnectionId server_connection_id =
+ GetServerConnectionIdAsRecipient(header, perspective_);
QUIC_DLOG(INFO) << ENDPOINT
<< "Ignoring packet from unexpected server connection ID "
<< server_connection_id << " instead of "
- << server_connection_id_;
+ << ServerConnectionId();
if (debug_visitor_ != nullptr) {
debug_visitor_->OnIncorrectConnectionId(server_connection_id);
}
@@ -1066,18 +1127,15 @@ bool QuicConnection::OnUnauthenticatedPublicHeader(
return true;
}
- if (framer_.do_not_synthesize_source_cid_for_short_header() &&
- perspective_ == Perspective::IS_SERVER &&
+ if (perspective_ == Perspective::IS_SERVER &&
header.form == IETF_QUIC_SHORT_HEADER_PACKET) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_do_not_synthesize_source_cid_for_short_header, 3, 3);
return true;
}
QuicConnectionId client_connection_id =
GetClientConnectionIdAsRecipient(header, perspective_);
- if (client_connection_id == client_connection_id_) {
+ if (client_connection_id == ClientConnectionId()) {
return true;
}
@@ -1089,11 +1147,18 @@ bool QuicConnection::OnUnauthenticatedPublicHeader(
return true;
}
+ if (connection_migration_use_new_cid_ &&
+ perspective_ == Perspective::IS_CLIENT &&
+ self_issued_cid_manager_ != nullptr &&
+ self_issued_cid_manager_->IsConnectionIdInUse(client_connection_id)) {
+ return true;
+ }
+
++stats_.packets_dropped;
QUIC_DLOG(INFO) << ENDPOINT
<< "Ignoring packet from unexpected client connection ID "
<< client_connection_id << " instead of "
- << client_connection_id_;
+ << ClientConnectionId();
return false;
}
@@ -1102,17 +1167,8 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
debug_visitor_->OnUnauthenticatedHeader(header);
}
- // Check that any public reset packet with a different connection ID that was
- // routed to this QuicConnection has been redirected before control reaches
- // here.
- QUICHE_DCHECK((framer_.do_not_synthesize_source_cid_for_short_header() &&
- perspective_ == Perspective::IS_CLIENT &&
- header.form == IETF_QUIC_SHORT_HEADER_PACKET) ||
- GetServerConnectionIdAsRecipient(header, perspective_) ==
- server_connection_id_ ||
- HasIncomingConnectionId(
- GetServerConnectionIdAsRecipient(header, perspective_)) ||
- PacketCanReplaceConnectionId(header, perspective_));
+ // Sanity check on the server connection ID in header.
+ QUICHE_DCHECK(ValidateServerConnectionId(header));
if (packet_creator_.HasPendingFrames()) {
// Incoming packets may change a queued ACK frame.
@@ -1264,6 +1320,43 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
default_path_.peer_address,
GetEffectivePeerAddressFromCurrentPacket());
+ if (connection_migration_use_new_cid_) {
+ auto effective_peer_address = GetEffectivePeerAddressFromCurrentPacket();
+ // Since server does not send new connection ID to client before handshake
+ // completion and source connection ID is omitted in short header packet,
+ // the server_connection_id on PathState on the server side does not
+ // affect the packets server writes after handshake completion. On the
+ // other hand, it is still desirable to have the "correct" server
+ // connection ID set on path.
+ // 1) If client uses 1 unique server connection ID per path and the packet
+ // is received from an existing path, then
+ // last_packet_destination_connection_id_ will always be the same as the
+ // server connection ID on path. Server side will maintain the 1-to-1
+ // mapping from server connection ID to path.
+ // 2) If client uses multiple server connection IDs on the same path,
+ // compared to the server_connection_id on path,
+ // last_packet_destination_connection_id_ has the advantage that it is
+ // still present in the session map since the packet can be routed here
+ // regardless of packet reordering.
+ if (IsDefaultPath(last_packet_destination_address_,
+ effective_peer_address)) {
+ default_path_.server_connection_id =
+ last_packet_destination_connection_id_;
+ } else if (IsAlternativePath(last_packet_destination_address_,
+ effective_peer_address)) {
+ alternative_path_.server_connection_id =
+ last_packet_destination_connection_id_;
+ }
+ }
+
+ if (use_connection_id_on_default_path_ &&
+ last_packet_destination_connection_id_ != ServerConnectionId() &&
+ (!original_destination_connection_id_.has_value() ||
+ last_packet_destination_connection_id_ !=
+ *original_destination_connection_id_)) {
+ QUIC_CODE_COUNT(quic_connection_id_change);
+ }
+
QUIC_DLOG_IF(INFO, current_effective_peer_migration_type_ != NO_CHANGE)
<< ENDPOINT << "Effective peer's ip:port changed from "
<< default_path_.peer_address.ToString() << " to "
@@ -1284,17 +1377,13 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
uber_received_packet_manager_.RecordPacketReceived(
last_decrypted_packet_level_, last_header_,
idle_network_detector_.time_of_last_received_packet());
- if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_token_based_address_validation, 2,
- 2);
- if (EnforceAntiAmplificationLimit() && !IsHandshakeConfirmed() &&
- !header.retry_token.empty() &&
- visitor_->ValidateToken(header.retry_token)) {
- QUIC_DLOG(INFO) << ENDPOINT << "Address validated via token.";
- QUIC_CODE_COUNT(quic_address_validated_via_token);
- default_path_.validated = true;
- stats_.address_validated_via_token = true;
- }
+ if (EnforceAntiAmplificationLimit() && !IsHandshakeConfirmed() &&
+ !header.retry_token.empty() &&
+ visitor_->ValidateToken(header.retry_token)) {
+ QUIC_DLOG(INFO) << ENDPOINT << "Address validated via token.";
+ QUIC_CODE_COUNT(quic_address_validated_via_token);
+ default_path_.validated = true;
+ stats_.address_validated_via_token = true;
}
QUICHE_DCHECK(connected_);
return true;
@@ -1684,8 +1773,12 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
// PATH_RESPONSE. This context needs to be out of scope before returning.
// TODO(danzh) inline OnPathChallengeFrameInternal() once
// support_reverse_path_validation_ is deprecated.
- QuicPacketCreator::ScopedPeerAddressContext context(
- &packet_creator_, last_packet_source_address_);
+ auto context =
+ group_path_response_and_challenge_sending_closer_
+ ? nullptr
+ : std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>(
+ &packet_creator_, last_packet_source_address_,
+ /*update_connection_id=*/false);
if (!OnPathChallengeFrameInternal(frame)) {
return false;
}
@@ -1695,6 +1788,7 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
bool QuicConnection::OnPathChallengeFrameInternal(
const QuicPathChallengeFrame& frame) {
+ should_proactively_validate_peer_address_on_path_challenge_ = false;
// UpdatePacketContent() may start reverse path validation.
if (!UpdatePacketContent(PATH_CHALLENGE_FRAME)) {
return false;
@@ -1703,6 +1797,35 @@ bool QuicConnection::OnPathChallengeFrameInternal(
debug_visitor_->OnPathChallengeFrame(frame);
}
+ std::unique_ptr<QuicPacketCreator::ScopedPeerAddressContext> context;
+ const QuicSocketAddress current_effective_peer_address =
+ GetEffectivePeerAddressFromCurrentPacket();
+ if (group_path_response_and_challenge_sending_closer_) {
+ QuicConnectionId client_cid, server_cid;
+ FindOnPathConnectionIds(last_packet_destination_address_,
+ current_effective_peer_address, &client_cid,
+ &server_cid);
+ context = std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>(
+ &packet_creator_, last_packet_source_address_, client_cid, server_cid,
+ connection_migration_use_new_cid_);
+ }
+ if (should_proactively_validate_peer_address_on_path_challenge_) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_group_path_response_and_challenge_sending_closer);
+ // Conditions to proactively validate peer address:
+ // The perspective is server
+ // The PATH_CHALLENGE is received on an unvalidated alternative path.
+ // The connection isn't validating migrated peer address, which is of
+ // higher prority.
+ QUIC_DVLOG(1) << "Proactively validate the effective peer address "
+ << current_effective_peer_address;
+ QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 2, 6);
+ ValidatePath(std::make_unique<ReversePathValidationContext>(
+ default_path_.self_address, last_packet_source_address_,
+ current_effective_peer_address, this),
+ std::make_unique<ReversePathValidationResultDelegate>(
+ this, peer_address()));
+ }
if (!send_path_response_) {
// Save the path challenge's payload, for later use in generating the
// response.
@@ -1717,10 +1840,19 @@ bool QuicConnection::OnPathChallengeFrameInternal(
// Queue or send PATH_RESPONSE. Send PATH_RESPONSE to the source address of
// the current incoming packet, even if it's not the default path or the
// alternative path.
- if (!SendPathResponse(frame.data_buffer, last_packet_source_address_)) {
- // Queue the payloads to re-try later.
- pending_path_challenge_payloads_.push_back(
- {frame.data_buffer, last_packet_source_address_});
+ const bool success =
+ SendPathResponse(frame.data_buffer, last_packet_source_address_,
+ current_effective_peer_address);
+ if (GetQuicReloadableFlag(quic_drop_unsent_path_response)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_drop_unsent_path_response);
+ }
+ if (!success) {
+ QUIC_CODE_COUNT(quic_failed_to_send_path_response);
+ if (!GetQuicReloadableFlag(quic_drop_unsent_path_response)) {
+ // Queue the payloads to re-try later.
+ pending_path_challenge_payloads_.push_back(
+ {frame.data_buffer, last_packet_source_address_});
+ }
}
// TODO(b/150095588): change the stats to
// num_valid_path_challenge_received.
@@ -1885,6 +2017,39 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
return connected_;
}
+void QuicConnection::OnClientConnectionIdAvailable() {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 3, 5);
+ QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER);
+ if (!peer_issued_cid_manager_->HasUnusedConnectionId()) {
+ return;
+ }
+ if (default_path_.client_connection_id.IsEmpty()) {
+ const QuicConnectionIdData* unused_cid_data =
+ peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+ QUIC_DVLOG(1) << ENDPOINT << "Patch connection ID "
+ << unused_cid_data->connection_id << " to default path";
+ default_path_.client_connection_id = unused_cid_data->connection_id;
+ default_path_.stateless_reset_token_received = true;
+ default_path_.stateless_reset_token =
+ unused_cid_data->stateless_reset_token;
+ QUICHE_DCHECK(!packet_creator_.HasPendingFrames());
+ QUICHE_DCHECK(packet_creator_.GetDestinationConnectionId().IsEmpty());
+ packet_creator_.SetClientConnectionId(default_path_.client_connection_id);
+ return;
+ }
+ if (alternative_path_.peer_address.IsInitialized() &&
+ alternative_path_.client_connection_id.IsEmpty()) {
+ const QuicConnectionIdData* unused_cid_data =
+ peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+ QUIC_DVLOG(1) << ENDPOINT << "Patch connection ID "
+ << unused_cid_data->connection_id << " to alternative path";
+ alternative_path_.client_connection_id = unused_cid_data->connection_id;
+ alternative_path_.stateless_reset_token_received = true;
+ alternative_path_.stateless_reset_token =
+ unused_cid_data->stateless_reset_token;
+ }
+}
+
bool QuicConnection::OnNewConnectionIdFrameInner(
const QuicNewConnectionIdFrame& frame) {
QUICHE_DCHECK(support_multiple_connection_ids_);
@@ -1903,7 +2068,11 @@ bool QuicConnection::OnNewConnectionIdFrameInner(
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v2, 1, 2);
+ if (use_connection_id_on_default_path_ &&
+ perspective_ == Perspective::IS_SERVER) {
+ OnClientConnectionIdAvailable();
+ }
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v4, 1, 2);
return true;
}
@@ -1939,6 +2108,11 @@ bool QuicConnection::OnRetireConnectionIdFrame(
if (debug_visitor_ != nullptr) {
debug_visitor_->OnRetireConnectionIdFrame(frame);
}
+ if (use_connection_id_on_default_path_ &&
+ !connection_migration_use_new_cid_) {
+ // Do not respond to RetireConnectionId frame.
+ return true;
+ }
if (!support_multiple_connection_ids_) {
return true;
}
@@ -1957,7 +2131,7 @@ bool QuicConnection::OnRetireConnectionIdFrame(
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v2, 2, 2);
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v4, 2, 2);
return true;
}
@@ -1972,17 +2146,14 @@ bool QuicConnection::OnNewTokenFrame(const QuicNewTokenFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnNewTokenFrame(frame);
}
- if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) {
- if (perspective_ == Perspective::IS_SERVER) {
- CloseConnection(QUIC_INVALID_NEW_TOKEN,
- "Server received new token frame.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- // NEW_TOKEN frame should insitgate ACKs.
- MaybeUpdateAckTimeout();
- visitor_->OnNewTokenReceived(frame.token);
+ if (perspective_ == Perspective::IS_SERVER) {
+ CloseConnection(QUIC_INVALID_NEW_TOKEN, "Server received new token frame.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
}
+ // NEW_TOKEN frame should insitgate ACKs.
+ MaybeUpdateAckTimeout();
+ visitor_->OnNewTokenReceived(frame.token);
return true;
}
@@ -2181,21 +2352,14 @@ void QuicConnection::MaybeRespondToConnectivityProbingOrMigration() {
return;
}
}
- // Server starts to migrate connection upon receiving of non-probing packet
- // from a new peer address.
- if (!start_peer_migration_earlier_ &&
- last_header_.packet_number == GetLargestReceivedPacket()) {
- direct_peer_address_ = last_packet_source_address_;
- if (current_effective_peer_migration_type_ != NO_CHANGE) {
- // TODO(fayang): When multiple packet number spaces is supported, only
- // start peer migration for the application data.
- StartEffectivePeerMigration(current_effective_peer_migration_type_);
- }
- }
}
bool QuicConnection::IsValidStatelessResetToken(
const StatelessResetToken& token) const {
+ if (use_connection_id_on_default_path_) {
+ return default_path_.stateless_reset_token_received &&
+ token == default_path_.stateless_reset_token;
+ }
return stateless_reset_token_received_ &&
token == received_stateless_reset_token_;
}
@@ -2280,23 +2444,13 @@ void QuicConnection::ClearLastFrames() {
}
void QuicConnection::CloseIfTooManyOutstandingSentPackets() {
- bool should_close;
- if (GetQuicReloadableFlag(
- quic_close_connection_with_too_many_outstanding_packets)) {
- QUIC_RELOADABLE_FLAG_COUNT(
- quic_close_connection_with_too_many_outstanding_packets);
- should_close =
- sent_packet_manager_.GetLargestSentPacket().IsInitialized() &&
- sent_packet_manager_.GetLargestSentPacket() >
- sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_;
- } else {
- should_close =
- sent_packet_manager_.GetLargestObserved().IsInitialized() &&
- sent_packet_manager_.GetLargestObserved() >
- sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_;
- }
// This occurs if we don't discard old packets we've seen fast enough. It's
// possible largest observed is less than leaset unacked.
+ const bool should_close =
+ sent_packet_manager_.GetLargestSentPacket().IsInitialized() &&
+ sent_packet_manager_.GetLargestSentPacket() >
+ sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_;
+
if (should_close) {
CloseConnection(
QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
@@ -2414,18 +2568,23 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
QuicUtils::IsCryptoStreamId(transport_version(), id)) {
MaybeActivateLegacyVersionEncapsulation();
}
- if (GetQuicReloadableFlag(quic_preempt_stream_data_with_handshake_packet) &&
- perspective_ == Perspective::IS_SERVER &&
+ if (perspective_ == Perspective::IS_SERVER &&
version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_preempt_stream_data_with_handshake_packet,
- 1, 2);
+ if (GetQuicReloadableFlag(quic_donot_pto_half_rtt_data)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_donot_pto_half_rtt_data);
+ if (in_on_retransmission_time_out_ &&
+ coalesced_packet_.NumberOfPackets() == 0u) {
+ // PTO fires while handshake is not confirmed. Do not preempt handshake
+ // data with stream data.
+ QUIC_CODE_COUNT(quic_try_to_send_half_rtt_data_when_pto_fires);
+ return QuicConsumedData(0, false);
+ }
+ }
if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_INITIAL) &&
coalesced_packet_.NumberOfPackets() == 1u) {
// Handshake is not confirmed yet, if there is only an initial packet in
// the coalescer, try to bundle an ENCRYPTION_HANDSHAKE packet before
// sending stream data.
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_preempt_stream_data_with_handshake_packet, 2, 2);
sent_packet_manager_.RetransmitDataOfSpaceIfAny(HANDSHAKE_DATA);
}
}
@@ -2510,8 +2669,8 @@ const QuicConnectionStats& QuicConnection::GetStats() {
stats_.estimated_bandwidth = sent_packet_manager_.BandwidthEstimate();
sent_packet_manager_.GetSendAlgorithm()->PopulateConnectionStats(&stats_);
- stats_.max_packet_size = packet_creator_.max_packet_length();
- stats_.max_received_packet_size = largest_received_packet_size_;
+ stats_.egress_mtu = long_term_mtu_;
+ stats_.ingress_mtu = largest_received_packet_size_;
return stats_;
}
@@ -2745,6 +2904,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
MaybeSendInResponseToPacket();
}
SetPingAlarm();
+ RetirePeerIssuedConnectionIdsNoLongerOnPath();
current_packet_data_ = nullptr;
is_current_packet_connectivity_probing_ = false;
}
@@ -2789,8 +2949,12 @@ void QuicConnection::OnCanWrite() {
QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response2, 4, 5);
const PendingPathChallenge& pending_path_challenge =
pending_path_challenge_payloads_.front();
+ // Note connection_migration_use_cid_ will depends on
+ // quic_drop_unsent_path_response flag eventually, and hence the empty
+ // effective_peer_address here will not be used.
if (!SendPathResponse(pending_path_challenge.received_path_challenge,
- pending_path_challenge.peer_address)) {
+ pending_path_challenge.peer_address,
+ /*effective_peer_address=*/QuicSocketAddress())) {
break;
}
pending_path_challenge_payloads_.pop_front();
@@ -2826,6 +2990,17 @@ void QuicConnection::WriteIfNotBlocked() {
}
}
+void QuicConnection::SetServerConnectionId(
+ const QuicConnectionId& server_connection_id) {
+ if (use_connection_id_on_default_path_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_connection_id_on_default_path_v2, 2,
+ 3);
+ default_path_.server_connection_id = server_connection_id;
+ } else {
+ server_connection_id_ = server_connection_id;
+ }
+}
+
void QuicConnection::ReplaceInitialServerConnectionId(
const QuicConnectionId& new_server_connection_id) {
QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT);
@@ -2836,10 +3011,10 @@ void QuicConnection::ReplaceInitialServerConnectionId(
if (peer_issued_cid_manager_ != nullptr) {
QUIC_BUG_IF(quic_bug_12714_22,
!peer_issued_cid_manager_->IsConnectionIdActive(
- server_connection_id_))
+ ServerConnectionId()))
<< "Connection ID replaced header is no longer active. old id: "
- << server_connection_id_ << " new_id: " << new_server_connection_id;
- peer_issued_cid_manager_->ReplaceConnectionId(server_connection_id_,
+ << ServerConnectionId() << " new_id: " << new_server_connection_id;
+ peer_issued_cid_manager_->ReplaceConnectionId(ServerConnectionId(),
new_server_connection_id);
} else {
peer_issued_cid_manager_ =
@@ -2849,8 +3024,74 @@ void QuicConnection::ReplaceInitialServerConnectionId(
}
}
}
- server_connection_id_ = new_server_connection_id;
- packet_creator_.SetServerConnectionId(server_connection_id_);
+ SetServerConnectionId(new_server_connection_id);
+ packet_creator_.SetServerConnectionId(ServerConnectionId());
+}
+
+void QuicConnection::FindMatchingOrNewClientConnectionIdOrToken(
+ const PathState& default_path,
+ const PathState& alternative_path,
+ const QuicConnectionId& server_connection_id,
+ QuicConnectionId* client_connection_id,
+ bool* stateless_reset_token_received,
+ StatelessResetToken* stateless_reset_token) {
+ if (!use_connection_id_on_default_path_) {
+ return;
+ }
+ QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER);
+ if (peer_issued_cid_manager_ == nullptr ||
+ server_connection_id == default_path.server_connection_id) {
+ *client_connection_id = default_path.client_connection_id;
+ *stateless_reset_token_received =
+ default_path.stateless_reset_token_received;
+ *stateless_reset_token = default_path.stateless_reset_token;
+ return;
+ }
+ if (server_connection_id == alternative_path_.server_connection_id) {
+ *client_connection_id = alternative_path.client_connection_id;
+ *stateless_reset_token_received =
+ alternative_path.stateless_reset_token_received;
+ *stateless_reset_token = alternative_path.stateless_reset_token;
+ return;
+ }
+ if (!connection_migration_use_new_cid_) {
+ QUIC_BUG(quic_bug_46004) << "Cannot find matching connection ID.";
+ return;
+ }
+ auto* connection_id_data =
+ peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+ if (connection_id_data == nullptr) {
+ return;
+ }
+ *client_connection_id = connection_id_data->connection_id;
+ *stateless_reset_token = connection_id_data->stateless_reset_token;
+ *stateless_reset_token_received = true;
+}
+
+bool QuicConnection::FindOnPathConnectionIds(
+ const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ QuicConnectionId* client_connection_id,
+ QuicConnectionId* server_connection_id) const {
+ if (IsDefaultPath(self_address, peer_address)) {
+ *client_connection_id = default_path_.client_connection_id,
+ *server_connection_id = default_path_.server_connection_id;
+ return true;
+ }
+ if (IsAlternativePath(self_address, peer_address)) {
+ *client_connection_id = alternative_path_.client_connection_id,
+ *server_connection_id = alternative_path_.server_connection_id;
+ return true;
+ }
+ return false;
+}
+
+void QuicConnection::SetDefaultPathState(PathState new_path_state) {
+ default_path_ = std::move(new_path_state);
+ if (connection_migration_use_new_cid_) {
+ packet_creator_.SetClientConnectionId(default_path_.client_connection_id);
+ packet_creator_.SetServerConnectionId(default_path_.server_connection_id);
+ }
}
bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
@@ -2885,21 +3126,21 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
default_path_.self_address = last_packet_destination_address_;
}
- if (PacketCanReplaceConnectionId(header, perspective_) &&
- server_connection_id_ != header.source_connection_id) {
+ if (PacketCanReplaceServerConnectionId(header, perspective_) &&
+ ServerConnectionId() != header.source_connection_id) {
QUICHE_DCHECK_EQ(header.long_packet_type, INITIAL);
if (server_connection_id_replaced_by_initial_) {
QUIC_DLOG(ERROR) << ENDPOINT << "Refusing to replace connection ID "
- << server_connection_id_ << " with "
+ << ServerConnectionId() << " with "
<< header.source_connection_id;
return false;
}
server_connection_id_replaced_by_initial_ = true;
QUIC_DLOG(INFO) << ENDPOINT << "Replacing connection ID "
- << server_connection_id_ << " with "
+ << ServerConnectionId() << " with "
<< header.source_connection_id;
if (!original_destination_connection_id_.has_value()) {
- original_destination_connection_id_ = server_connection_id_;
+ original_destination_connection_id_ = ServerConnectionId();
}
ReplaceInitialServerConnectionId(header.source_connection_id);
}
@@ -3039,6 +3280,15 @@ bool QuicConnection::ShouldGeneratePacket(
QuicVersionUsesCryptoFrames(transport_version()))
<< ENDPOINT
<< "Handshake in STREAM frames should not check ShouldGeneratePacket";
+ if (support_multiple_connection_ids_ && peer_issued_cid_manager_ != nullptr &&
+ packet_creator_.GetDestinationConnectionId().IsEmpty()) {
+ QUIC_CODE_COUNT(quic_generate_packet_blocked_by_no_connection_id);
+ QUIC_BUG_IF(quic_bug_90265_1, perspective_ == Perspective::IS_CLIENT);
+ QUIC_DLOG(INFO) << ENDPOINT
+ << "There is no destination connection ID available to "
+ "generate packet.";
+ return false;
+ }
if (!count_bytes_on_alternative_path_separately_) {
return CanWrite(retransmittable);
}
@@ -3319,7 +3569,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
legacy_version_encapsulation_sni_,
absl::string_view(packet->encrypted_buffer,
packet->encrypted_length),
- server_connection_id_, framer_.creation_time(),
+ ServerConnectionId(), framer_.creation_time(),
GetLimitedMaxPacketSize(long_term_mtu_),
const_cast<char*>(packet->encrypted_buffer));
if (encapsulated_length != 0) {
@@ -3514,6 +3764,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
SetRetransmissionAlarm();
}
SetPingAlarm();
+ RetirePeerIssuedConnectionIdsNoLongerOnPath();
// The packet number length must be updated after OnPacketSent, because it
// may change the packet number length in packet.
@@ -3827,13 +4078,13 @@ void QuicConnection::OnPathMtuIncreased(QuicPacketLength packet_size) {
std::unique_ptr<QuicSelfIssuedConnectionIdManager>
QuicConnection::MakeSelfIssuedConnectionIdManager() {
QUICHE_DCHECK((perspective_ == Perspective::IS_CLIENT &&
- !client_connection_id_.IsEmpty()) ||
+ !ClientConnectionId().IsEmpty()) ||
(perspective_ == Perspective::IS_SERVER &&
- !server_connection_id_.IsEmpty()));
+ !ServerConnectionId().IsEmpty()));
return std::make_unique<QuicSelfIssuedConnectionIdManager>(
kMinNumOfActiveConnectionIds,
- perspective_ == Perspective::IS_CLIENT ? client_connection_id_
- : server_connection_id_,
+ perspective_ == Perspective::IS_CLIENT ? ClientConnectionId()
+ : ServerConnectionId(),
clock_, alarm_factory_, this);
}
@@ -3847,6 +4098,11 @@ void QuicConnection::MaybeSendConnectionIdToClient() {
void QuicConnection::OnHandshakeComplete() {
sent_packet_manager_.SetHandshakeConfirmed();
+ if (connection_migration_use_new_cid_ &&
+ perspective_ == Perspective::IS_SERVER &&
+ self_issued_cid_manager_ != nullptr) {
+ self_issued_cid_manager_->MaybeSendNewConnectionIds();
+ }
if (send_ack_frequency_on_handshake_completion_ &&
sent_packet_manager_.CanSendAckFrequency()) {
QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 2, 3);
@@ -3926,6 +4182,7 @@ void QuicConnection::SendAck() {
}
void QuicConnection::OnRetransmissionTimeout() {
+ ScopedRetransmissionTimeoutIndicator indicator(this);
#ifndef NDEBUG
if (sent_packet_manager_.unacked_packets().empty()) {
QUICHE_DCHECK(sent_packet_manager_.handshake_mode_disabled());
@@ -4309,8 +4566,9 @@ void QuicConnection::SendConnectionClosePacket(
QuicIetfTransportErrorCodes ietf_error,
const std::string& details) {
// Always use the current path to send CONNECTION_CLOSE.
- QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_,
- peer_address());
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &packet_creator_, peer_address(), default_path_.client_connection_id,
+ default_path_.server_connection_id, connection_migration_use_new_cid_);
if (!SupportsMultiplePacketNumberSpaces()) {
QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet.";
if (!use_encryption_level_context_) {
@@ -4472,6 +4730,7 @@ QuicByteCount QuicConnection::max_packet_length() const {
void QuicConnection::SetMaxPacketLength(QuicByteCount length) {
long_term_mtu_ = length;
+ stats_.max_egress_mtu = std::max(stats_.max_egress_mtu, long_term_mtu_);
MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
}
@@ -4838,7 +5097,7 @@ bool QuicConnection::SendGenericPathProbePacket(
QUIC_DLOG(INFO) << ENDPOINT
<< "Sending path probe packet for connection_id = "
- << server_connection_id_;
+ << ServerConnectionId();
std::unique_ptr<SerializedPacket> probing_packet;
if (!version().HasIetfQuicFrames()) {
@@ -4883,7 +5142,7 @@ bool QuicConnection::WritePacketUsingWriter(
const QuicTime packet_send_time = clock_->Now();
QUIC_DVLOG(2) << ENDPOINT
<< "Sending path probe packet for server connection ID "
- << server_connection_id_ << std::endl
+ << ServerConnectionId() << std::endl
<< quiche::QuicheTextUtils::HexDump(absl::string_view(
packet->encrypted_buffer, packet->encrypted_length));
WriteResult result = writer->WritePacket(
@@ -5083,10 +5342,19 @@ void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) {
// Update the default path.
if (IsAlternativePath(last_packet_destination_address_,
current_effective_peer_address)) {
- default_path_ = std::move(alternative_path_);
+ SetDefaultPathState(std::move(alternative_path_));
} else {
- default_path_ = PathState(last_packet_destination_address_,
- current_effective_peer_address);
+ QuicConnectionId client_connection_id;
+ bool stateless_reset_token_received = false;
+ StatelessResetToken stateless_reset_token;
+ FindMatchingOrNewClientConnectionIdOrToken(
+ previous_default_path, alternative_path_,
+ last_packet_destination_connection_id_, &client_connection_id,
+ &stateless_reset_token_received, &stateless_reset_token);
+ SetDefaultPathState(PathState(
+ last_packet_destination_address_, current_effective_peer_address,
+ client_connection_id, last_packet_destination_connection_id_,
+ stateless_reset_token_received, stateless_reset_token));
// The path is considered validated if its peer IP address matches any
// validated path's peer IP address.
default_path_.validated =
@@ -5293,8 +5561,17 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) {
<< current_effective_peer_address << ", self address "
<< last_packet_destination_address_;
if (!validate_client_addresses_) {
- alternative_path_ = PathState(last_packet_destination_address_,
- current_effective_peer_address);
+ QuicConnectionId client_cid;
+ bool stateless_reset_token_received = false;
+ StatelessResetToken stateless_reset_token;
+ FindMatchingOrNewClientConnectionIdOrToken(
+ default_path_, alternative_path_,
+ last_packet_destination_connection_id_, &client_cid,
+ &stateless_reset_token_received, &stateless_reset_token);
+ alternative_path_ = PathState(
+ last_packet_destination_address_, current_effective_peer_address,
+ client_cid, last_packet_destination_connection_id_,
+ stateless_reset_token_received, stateless_reset_token);
} else if (!default_path_.validated) {
QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 4, 6);
// Skip reverse path validation because either handshake hasn't
@@ -5311,24 +5588,38 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) {
<< "No validated peer address to send after handshake comfirmed.";
} else if (!IsReceivedPeerAddressValidated()) {
QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 5, 6);
+ QuicConnectionId client_connection_id;
+ bool stateless_reset_token_received;
+ StatelessResetToken stateless_reset_token;
+ FindMatchingOrNewClientConnectionIdOrToken(
+ default_path_, alternative_path_,
+ last_packet_destination_connection_id_, &client_connection_id,
+ &stateless_reset_token_received, &stateless_reset_token);
// Only override alternative path state upon receiving a PATH_CHALLENGE
// from an unvalidated peer address, and the connection isn't validating
// a recent peer migration.
- alternative_path_ = PathState(last_packet_destination_address_,
- current_effective_peer_address);
- // Conditions to proactively validate peer address:
- // The perspective is server
- // The PATH_CHALLENGE is received on an unvalidated alternative path.
- // The connection isn't validating migrated peer address, which is of
- // higher prority.
- QUIC_DVLOG(1) << "Proactively validate the effective peer address "
- << current_effective_peer_address;
- ValidatePath(
- std::make_unique<ReversePathValidationContext>(
- default_path_.self_address, current_effective_peer_address,
- current_effective_peer_address, this),
- std::make_unique<ReversePathValidationResultDelegate>(
- this, peer_address()));
+ alternative_path_ = PathState(
+ last_packet_destination_address_, current_effective_peer_address,
+ client_connection_id, last_packet_destination_connection_id_,
+ stateless_reset_token_received, stateless_reset_token);
+ if (group_path_response_and_challenge_sending_closer_) {
+ should_proactively_validate_peer_address_on_path_challenge_ = true;
+ } else {
+ // Conditions to proactively validate peer address:
+ // The perspective is server
+ // The PATH_CHALLENGE is received on an unvalidated alternative path.
+ // The connection isn't validating migrated peer address, which is of
+ // higher prority.
+ QUIC_DVLOG(1) << "Proactively validate the effective peer address "
+ << current_effective_peer_address;
+ QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 1, 6);
+ ValidatePath(
+ std::make_unique<ReversePathValidationContext>(
+ default_path_.self_address, last_packet_source_address_,
+ current_effective_peer_address, this),
+ std::make_unique<ReversePathValidationResultDelegate>(
+ this, peer_address()));
+ }
}
}
MaybeUpdateBytesReceivedFromAlternativeAddress(last_size_);
@@ -5398,10 +5689,6 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) {
void QuicConnection::MaybeStartIetfPeerMigration() {
QUICHE_DCHECK(version().HasIetfQuicFrames());
- if (!start_peer_migration_earlier_) {
- return;
- }
- QUIC_CODE_COUNT(quic_start_peer_migration_earlier);
if (current_effective_peer_migration_type_ != NO_CHANGE &&
!IsHandshakeConfirmed()) {
QUIC_LOG_EVERY_N_SEC(INFO, 60)
@@ -5970,14 +6257,21 @@ void QuicConnection::set_client_connection_id(
<< client_connection_id << " with unsupported version " << version();
return;
}
- client_connection_id_ = client_connection_id;
+ if (use_connection_id_on_default_path_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_connection_id_on_default_path_v2, 1,
+ 3);
+ default_path_.client_connection_id = client_connection_id;
+ } else {
+ client_connection_id_ = client_connection_id;
+ }
+
client_connection_id_is_set_ = true;
- if (support_multiple_connection_ids_ && !client_connection_id_.IsEmpty()) {
+ if (support_multiple_connection_ids_ && !client_connection_id.IsEmpty()) {
if (perspective_ == Perspective::IS_SERVER) {
QUICHE_DCHECK(peer_issued_cid_manager_ == nullptr);
peer_issued_cid_manager_ =
std::make_unique<QuicPeerIssuedConnectionIdManager>(
- kMinNumOfActiveConnectionIds, client_connection_id_, clock_,
+ kMinNumOfActiveConnectionIds, client_connection_id, clock_,
alarm_factory_, this);
} else {
// Note in Chromium client, set_client_connection_id is not called and
@@ -5986,11 +6280,11 @@ void QuicConnection::set_client_connection_id(
}
}
QUIC_DLOG(INFO) << ENDPOINT << "setting client connection ID to "
- << client_connection_id_
+ << ClientConnectionId()
<< " for connection with server connection ID "
- << server_connection_id_;
- packet_creator_.SetClientConnectionId(client_connection_id_);
- framer_.SetExpectedClientConnectionIdLength(client_connection_id_.length());
+ << ServerConnectionId();
+ packet_creator_.SetClientConnectionId(ClientConnectionId());
+ framer_.SetExpectedClientConnectionIdLength(ClientConnectionId().length());
}
void QuicConnection::OnPathDegradingDetected() {
@@ -6069,12 +6363,21 @@ void QuicConnection::OnIdleNetworkDetected() {
void QuicConnection::OnPeerIssuedConnectionIdRetired() {
QUICHE_DCHECK(peer_issued_cid_manager_ != nullptr);
QuicConnectionId* default_path_cid = perspective_ == Perspective::IS_CLIENT
- ? &server_connection_id_
- : &client_connection_id_;
+ ? &ServerConnectionId()
+ : &ClientConnectionId();
+ QuicConnectionId* alternative_path_cid =
+ perspective_ == Perspective::IS_CLIENT
+ ? &alternative_path_.server_connection_id
+ : &alternative_path_.client_connection_id;
+ bool default_path_and_alternative_path_use_the_same_peer_connection_id =
+ *default_path_cid == *alternative_path_cid;
if (!default_path_cid->IsEmpty() &&
!peer_issued_cid_manager_->IsConnectionIdActive(*default_path_cid)) {
*default_path_cid = QuicConnectionId();
}
+ // TODO(haoyuewang) Handle the change for default_path_ & alternatvie_path_
+ // via the same helper function after use_connection_id_on_default_path_ is
+ // default true.
if (default_path_cid->IsEmpty()) {
// Try setting a new connection ID now such that subsequent
// RetireConnectionId frames can be sent on the default path.
@@ -6082,9 +6385,15 @@ void QuicConnection::OnPeerIssuedConnectionIdRetired() {
peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
if (unused_connection_id_data != nullptr) {
*default_path_cid = unused_connection_id_data->connection_id;
- received_stateless_reset_token_ =
- unused_connection_id_data->stateless_reset_token;
- stateless_reset_token_received_ = true;
+ if (use_connection_id_on_default_path_) {
+ default_path_.stateless_reset_token =
+ unused_connection_id_data->stateless_reset_token;
+ default_path_.stateless_reset_token_received = true;
+ } else {
+ received_stateless_reset_token_ =
+ unused_connection_id_data->stateless_reset_token;
+ stateless_reset_token_received_ = true;
+ }
if (perspective_ == Perspective::IS_CLIENT) {
packet_creator_.SetServerConnectionId(
unused_connection_id_data->connection_id);
@@ -6094,32 +6403,56 @@ void QuicConnection::OnPeerIssuedConnectionIdRetired() {
}
}
}
+ if (use_connection_id_on_default_path_) {
+ if (default_path_and_alternative_path_use_the_same_peer_connection_id) {
+ *alternative_path_cid = *default_path_cid;
+ alternative_path_.stateless_reset_token_received =
+ default_path_.stateless_reset_token_received;
+ alternative_path_.stateless_reset_token =
+ default_path_.stateless_reset_token;
+ } else if (!alternative_path_cid->IsEmpty() &&
+ !peer_issued_cid_manager_->IsConnectionIdActive(
+ *alternative_path_cid)) {
+ *alternative_path_cid = EmptyQuicConnectionId();
+ const QuicConnectionIdData* unused_connection_id_data =
+ peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+ if (unused_connection_id_data != nullptr) {
+ *alternative_path_cid = unused_connection_id_data->connection_id;
+ alternative_path_.stateless_reset_token =
+ unused_connection_id_data->stateless_reset_token;
+ alternative_path_.stateless_reset_token_received = true;
+ }
+ }
+ }
std::vector<uint64_t> retired_cid_sequence_numbers =
peer_issued_cid_manager_->ConsumeToBeRetiredConnectionIdSequenceNumbers();
QUICHE_DCHECK(!retired_cid_sequence_numbers.empty());
for (const auto& sequence_number : retired_cid_sequence_numbers) {
+ ++stats_.num_retire_connection_id_sent;
visitor_->SendRetireConnectionId(sequence_number);
}
}
bool QuicConnection::SendNewConnectionId(
const QuicNewConnectionIdFrame& frame) {
- QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER);
visitor_->SendNewConnectionId(frame);
+ ++stats_.num_new_connection_id_sent;
return connected_;
}
void QuicConnection::OnNewConnectionIdIssued(
const QuicConnectionId& connection_id) {
- QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER);
- visitor_->OnServerConnectionIdIssued(connection_id);
+ if (perspective_ == Perspective::IS_SERVER) {
+ visitor_->OnServerConnectionIdIssued(connection_id);
+ }
}
void QuicConnection::OnSelfIssuedConnectionIdRetired(
const QuicConnectionId& connection_id) {
- QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER);
- visitor_->OnServerConnectionIdRetired(connection_id);
+ if (perspective_ == Perspective::IS_SERVER) {
+ visitor_->OnServerConnectionIdRetired(connection_id);
+ }
}
void QuicConnection::MaybeUpdateAckTimeout() {
@@ -6197,15 +6530,41 @@ bool QuicConnection::SendPathChallenge(
const QuicPathFrameBuffer& data_buffer,
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
- const QuicSocketAddress& /*effective_peer_address*/,
+ const QuicSocketAddress& effective_peer_address,
QuicPacketWriter* writer) {
+ if (connection_migration_use_new_cid_) {
+ {
+ QuicConnectionId client_cid, server_cid;
+ FindOnPathConnectionIds(self_address, effective_peer_address, &client_cid,
+ &server_cid);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &packet_creator_, peer_address, client_cid, server_cid,
+ connection_migration_use_new_cid_);
+ if (writer == writer_) {
+ ScopedPacketFlusher flusher(this);
+ // It's on current path, add the PATH_CHALLENGE the same way as other
+ // frames. This may cause connection to be closed.
+ packet_creator_.AddPathChallengeFrame(data_buffer);
+ } else {
+ std::unique_ptr<SerializedPacket> probing_packet =
+ packet_creator_.SerializePathChallengeConnectivityProbingPacket(
+ data_buffer);
+ QUICHE_DCHECK_EQ(IsRetransmittable(*probing_packet),
+ NO_RETRANSMITTABLE_DATA);
+ QUICHE_DCHECK_EQ(self_address, alternative_path_.self_address);
+ WritePacketUsingWriter(std::move(probing_packet), writer, self_address,
+ peer_address, /*measure_rtt=*/false);
+ }
+ }
+ return connected_;
+ }
if (writer == writer_) {
ScopedPacketFlusher flusher(this);
{
// It's on current path, add the PATH_CHALLENGE the same way as other
// frames.
- QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_,
- peer_address);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &packet_creator_, peer_address, /*update_connection_id=*/false);
// This may cause connection to be closed.
packet_creator_.AddPathChallengeFrame(data_buffer);
}
@@ -6236,26 +6595,75 @@ void QuicConnection::ValidatePath(
std::unique_ptr<QuicPathValidationContext> context,
std::unique_ptr<QuicPathValidator::ResultDelegate> result_delegate) {
QUICHE_DCHECK(use_path_validator_);
- if (perspective_ == Perspective::IS_CLIENT &&
+ if (!connection_migration_use_new_cid_ &&
+ perspective_ == Perspective::IS_CLIENT &&
!IsDefaultPath(context->self_address(), context->peer_address())) {
- alternative_path_ =
- PathState(context->self_address(), context->peer_address());
+ alternative_path_ = PathState(
+ context->self_address(), context->peer_address(),
+ default_path_.client_connection_id, default_path_.server_connection_id,
+ default_path_.stateless_reset_token_received,
+ default_path_.stateless_reset_token);
}
if (path_validator_.HasPendingPathValidation()) {
// Cancel and fail any earlier validation.
path_validator_.CancelPathValidation();
}
+ if (connection_migration_use_new_cid_ &&
+ perspective_ == Perspective::IS_CLIENT &&
+ !IsDefaultPath(context->self_address(), context->peer_address())) {
+ if (self_issued_cid_manager_ != nullptr) {
+ self_issued_cid_manager_->MaybeSendNewConnectionIds();
+ if (!connected_) {
+ return;
+ }
+ }
+ if ((self_issued_cid_manager_ != nullptr &&
+ !self_issued_cid_manager_->HasConnectionIdToConsume()) ||
+ (peer_issued_cid_manager_ != nullptr &&
+ !peer_issued_cid_manager_->HasUnusedConnectionId())) {
+ QUIC_DVLOG(1) << "Client cannot start new path validation as there is no "
+ "requried connection ID is available.";
+ result_delegate->OnPathValidationFailure(std::move(context));
+ return;
+ }
+ QuicConnectionId client_connection_id, server_connection_id;
+ StatelessResetToken stateless_reset_token;
+ bool stateless_reset_token_received = false;
+ if (self_issued_cid_manager_ != nullptr) {
+ client_connection_id =
+ *self_issued_cid_manager_->ConsumeOneConnectionId();
+ }
+ if (peer_issued_cid_manager_ != nullptr) {
+ const auto* connection_id_data =
+ peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+ server_connection_id = connection_id_data->connection_id;
+ stateless_reset_token_received = true;
+ stateless_reset_token = connection_id_data->stateless_reset_token;
+ }
+ alternative_path_ =
+ PathState(context->self_address(), context->peer_address(),
+ client_connection_id, server_connection_id,
+ stateless_reset_token_received, stateless_reset_token);
+ }
path_validator_.StartPathValidation(std::move(context),
std::move(result_delegate));
}
-bool QuicConnection::SendPathResponse(const QuicPathFrameBuffer& data_buffer,
- QuicSocketAddress peer_address_to_send) {
+bool QuicConnection::SendPathResponse(
+ const QuicPathFrameBuffer& data_buffer,
+ const QuicSocketAddress& peer_address_to_send,
+ const QuicSocketAddress& effective_peer_address) {
+ QuicConnectionId client_cid, server_cid;
+ if (connection_migration_use_new_cid_) {
+ FindOnPathConnectionIds(last_packet_destination_address_,
+ effective_peer_address, &client_cid, &server_cid);
+ }
// Send PATH_RESPONSE using the provided peer address. If the creator has been
// using a different peer address, it will flush before and after serializing
// the current PATH_RESPONSE.
- QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_,
- peer_address_to_send);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &packet_creator_, peer_address_to_send, client_cid, server_cid,
+ connection_migration_use_new_cid_);
QUIC_DVLOG(1) << ENDPOINT << "Send PATH_RESPONSE to " << peer_address_to_send;
if (default_path_.self_address == last_packet_destination_address_) {
// The PATH_CHALLENGE is received on the default socket. Respond on the same
@@ -6315,12 +6723,84 @@ void QuicConnection::CancelPathValidation() {
path_validator_.CancelPathValidation();
}
-void QuicConnection::MigratePath(const QuicSocketAddress& self_address,
+bool QuicConnection::UpdateConnectionIdsOnClientMigration(
+ const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address) {
+ QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT);
+ if (IsAlternativePath(self_address, peer_address)) {
+ // Client migration is after path validation.
+ default_path_.client_connection_id = alternative_path_.client_connection_id;
+ default_path_.server_connection_id = alternative_path_.server_connection_id;
+ default_path_.stateless_reset_token =
+ alternative_path_.stateless_reset_token;
+ default_path_.stateless_reset_token_received =
+ alternative_path_.stateless_reset_token_received;
+ return true;
+ }
+ // Client migration is without path validation.
+ if (self_issued_cid_manager_ != nullptr) {
+ self_issued_cid_manager_->MaybeSendNewConnectionIds();
+ if (!connected_) {
+ return false;
+ }
+ }
+ if ((self_issued_cid_manager_ != nullptr &&
+ !self_issued_cid_manager_->HasConnectionIdToConsume()) ||
+ (peer_issued_cid_manager_ != nullptr &&
+ !peer_issued_cid_manager_->HasUnusedConnectionId())) {
+ return false;
+ }
+ if (self_issued_cid_manager_ != nullptr) {
+ default_path_.client_connection_id =
+ *self_issued_cid_manager_->ConsumeOneConnectionId();
+ }
+ if (peer_issued_cid_manager_ != nullptr) {
+ const auto* connection_id_data =
+ peer_issued_cid_manager_->ConsumeOneUnusedConnectionId();
+ default_path_.server_connection_id = connection_id_data->connection_id;
+ default_path_.stateless_reset_token_received = true;
+ default_path_.stateless_reset_token =
+ connection_id_data->stateless_reset_token;
+ }
+ return true;
+}
+
+void QuicConnection::RetirePeerIssuedConnectionIdsNoLongerOnPath() {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 4, 5);
+ if (!connection_migration_use_new_cid_ ||
+ peer_issued_cid_manager_ == nullptr) {
+ return;
+ }
+ if (perspective_ == Perspective::IS_CLIENT) {
+ peer_issued_cid_manager_->MaybeRetireUnusedConnectionIds(
+ {default_path_.server_connection_id,
+ alternative_path_.server_connection_id});
+ } else {
+ peer_issued_cid_manager_->MaybeRetireUnusedConnectionIds(
+ {default_path_.client_connection_id,
+ alternative_path_.client_connection_id});
+ }
+}
+
+bool QuicConnection::MigratePath(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
QuicPacketWriter* writer,
bool owns_writer) {
if (!connected_) {
- return;
+ return false;
+ }
+ QUICHE_DCHECK(!version().UsesHttp3() || IsHandshakeConfirmed());
+
+ if (connection_migration_use_new_cid_) {
+ if (!UpdateConnectionIdsOnClientMigration(self_address, peer_address)) {
+ return false;
+ }
+ if (packet_creator_.GetServerConnectionId().length() !=
+ default_path_.server_connection_id.length()) {
+ packet_creator_.FlushCurrentPacket();
+ }
+ packet_creator_.SetClientConnectionId(default_path_.client_connection_id);
+ packet_creator_.SetServerConnectionId(default_path_.server_connection_id);
}
const auto self_address_change_type = QuicUtils::DetermineAddressChangeType(
@@ -6337,13 +6817,21 @@ void QuicConnection::MigratePath(const QuicSocketAddress& self_address,
UpdatePeerAddress(peer_address);
SetQuicPacketWriter(writer, owns_writer);
OnSuccessfulMigration(is_port_change);
+ return true;
+}
+
+void QuicConnection::OnPathValidationFailureAtClient() {
+ if (connection_migration_use_new_cid_) {
+ QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT);
+ alternative_path_.Clear();
+ }
}
std::vector<QuicConnectionId> QuicConnection::GetActiveServerConnectionIds()
const {
if (!support_multiple_connection_ids_ ||
self_issued_cid_manager_ == nullptr) {
- return {server_connection_id_};
+ return {ServerConnectionId()};
}
return self_issued_cid_manager_->GetUnretiredConnectionIds();
}
@@ -6354,14 +6842,14 @@ void QuicConnection::CreateConnectionIdManager() {
}
if (perspective_ == Perspective::IS_CLIENT) {
- if (!server_connection_id_.IsEmpty()) {
+ if (!ServerConnectionId().IsEmpty()) {
peer_issued_cid_manager_ =
std::make_unique<QuicPeerIssuedConnectionIdManager>(
- kMinNumOfActiveConnectionIds, server_connection_id_, clock_,
+ kMinNumOfActiveConnectionIds, ServerConnectionId(), clock_,
alarm_factory_, this);
}
} else {
- if (!server_connection_id_.IsEmpty()) {
+ if (!ServerConnectionId().IsEmpty()) {
self_issued_cid_manager_ = MakeSelfIssuedConnectionIdManager();
}
}
@@ -6450,6 +6938,9 @@ bool QuicConnection::IsAlternativePath(
void QuicConnection::PathState::Clear() {
self_address = QuicSocketAddress();
peer_address = QuicSocketAddress();
+ client_connection_id = {};
+ server_connection_id = {};
+ stateless_reset_token_received = false;
validated = false;
bytes_received_before_address_validation = 0;
bytes_sent_before_address_validation = 0;
@@ -6466,6 +6957,10 @@ QuicConnection::PathState& QuicConnection::PathState::operator=(
if (this != &other) {
self_address = other.self_address;
peer_address = other.peer_address;
+ client_connection_id = other.client_connection_id;
+ server_connection_id = other.server_connection_id;
+ stateless_reset_token_received = other.stateless_reset_token_received;
+ stateless_reset_token = other.stateless_reset_token;
validated = other.validated;
bytes_received_before_address_validation =
other.bytes_received_before_address_validation;
@@ -6508,10 +7003,12 @@ void QuicConnection::ReversePathValidationResultDelegate::
QUIC_DLOG(INFO) << "Successfully validated new path " << *context;
if (connection_->IsDefaultPath(context->self_address(),
context->peer_address())) {
+ QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 3, 6);
connection_->OnEffectivePeerMigrationValidated();
} else {
QUICHE_DCHECK(connection_->IsAlternativePath(
context->self_address(), context->effective_peer_address()));
+ QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 4, 6);
QUIC_DVLOG(1) << "Mark alternative peer address "
<< context->effective_peer_address() << " validated.";
connection_->alternative_path_.validated = true;
@@ -6528,13 +7025,29 @@ void QuicConnection::ReversePathValidationResultDelegate::
if (connection_->IsDefaultPath(context->self_address(),
context->peer_address())) {
// Only act upon validation failure on the default path.
+ QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 5, 6);
connection_->RestoreToLastValidatedPath(original_direct_peer_address_);
} else if (connection_->IsAlternativePath(
context->self_address(), context->effective_peer_address())) {
+ QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 6, 6);
connection_->alternative_path_.Clear();
}
}
+QuicConnection::ScopedRetransmissionTimeoutIndicator::
+ ScopedRetransmissionTimeoutIndicator(QuicConnection* connection)
+ : connection_(connection) {
+ QUICHE_DCHECK(!connection_->in_on_retransmission_time_out_)
+ << "ScopedRetransmissionTimeoutIndicator is not supposed to be nested";
+ connection_->in_on_retransmission_time_out_ = true;
+}
+
+QuicConnection::ScopedRetransmissionTimeoutIndicator::
+ ~ScopedRetransmissionTimeoutIndicator() {
+ QUICHE_DCHECK(connection_->in_on_retransmission_time_out_);
+ connection_->in_on_retransmission_time_out_ = false;
+}
+
void QuicConnection::RestoreToLastValidatedPath(
QuicSocketAddress original_direct_peer_address) {
QUIC_DLOG(INFO) << "Switch back to use the old peer address "
@@ -6562,7 +7075,7 @@ void QuicConnection::RestoreToLastValidatedPath(
}
UpdatePeerAddress(original_direct_peer_address);
- default_path_ = std::move(alternative_path_);
+ SetDefaultPathState(std::move(alternative_path_));
active_effective_peer_migration_type_ = NO_CHANGE;
++stats_.num_invalid_peer_migration;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h
index e2ba17bd9d8..b9567250637 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h
@@ -36,7 +36,6 @@
#include "quic/core/quic_alarm.h"
#include "quic/core/quic_alarm_factory.h"
#include "quic/core/quic_blocked_writer_interface.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_connection_id_manager.h"
#include "quic/core/quic_connection_stats.h"
@@ -58,6 +57,7 @@
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_socket_address.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -777,9 +777,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
const QuicSocketAddress& effective_peer_address() const {
return default_path_.peer_address;
}
- QuicConnectionId connection_id() const { return server_connection_id_; }
- QuicConnectionId client_connection_id() const {
- return client_connection_id_;
+ const QuicConnectionId& connection_id() const { return ServerConnectionId(); }
+ const QuicConnectionId& client_connection_id() const {
+ return ClientConnectionId();
}
void set_client_connection_id(QuicConnectionId client_connection_id);
const QuicClock* clock() const { return clock_; }
@@ -1211,11 +1211,17 @@ class QUIC_EXPORT_PRIVATE QuicConnection
void CancelPathValidation();
- void MigratePath(const QuicSocketAddress& self_address,
+ // Returns true if the migration succeeds, otherwise returns false (e.g., no
+ // available CIDs, connection disconnected, etc).
+ bool MigratePath(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
QuicPacketWriter* writer,
bool owns_writer);
+ // Called to clear the alternative_path_ when path validation failed on the
+ // client side.
+ void OnPathValidationFailureAtClient();
+
void SetSourceAddressTokenToSend(absl::string_view token);
void SendPing() {
@@ -1228,6 +1234,22 @@ class QUIC_EXPORT_PRIVATE QuicConnection
bool validate_client_address() const { return validate_client_addresses_; }
+ bool support_multiple_connection_ids() const {
+ return support_multiple_connection_ids_;
+ }
+
+ bool use_connection_id_on_default_path() const {
+ return use_connection_id_on_default_path_;
+ }
+
+ bool connection_migration_use_new_cid() const {
+ return connection_migration_use_new_cid_;
+ }
+
+ bool count_bytes_on_alternative_path_separately() const {
+ return count_bytes_on_alternative_path_separately_;
+ }
+
// Instantiates connection ID manager.
void CreateConnectionIdManager();
@@ -1331,10 +1353,20 @@ class QUIC_EXPORT_PRIVATE QuicConnection
};
struct QUIC_EXPORT_PRIVATE PathState {
+ PathState() = default;
+
PathState(const QuicSocketAddress& alternative_self_address,
- const QuicSocketAddress& alternative_peer_address)
+ const QuicSocketAddress& alternative_peer_address,
+ const QuicConnectionId& client_connection_id,
+ const QuicConnectionId& server_connection_id,
+ bool stateless_reset_token_received,
+ StatelessResetToken stateless_reset_token)
: self_address(alternative_self_address),
- peer_address(alternative_peer_address) {}
+ peer_address(alternative_peer_address),
+ client_connection_id(client_connection_id),
+ server_connection_id(server_connection_id),
+ stateless_reset_token(stateless_reset_token),
+ stateless_reset_token_received(stateless_reset_token_received) {}
PathState(PathState&& other);
@@ -1346,6 +1378,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicSocketAddress self_address;
// The actual peer address behind the proxy if there is any.
QuicSocketAddress peer_address;
+ QuicConnectionId client_connection_id;
+ QuicConnectionId server_connection_id;
+ StatelessResetToken stateless_reset_token;
+ bool stateless_reset_token_received = false;
// True if the peer address has been validated. Address is considered
// validated when 1) an address token of the peer address is received and
// validated, or 2) a HANDSHAKE packet has been successfully processed on
@@ -1419,6 +1455,41 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicSocketAddress original_direct_peer_address_;
};
+ // A class which sets and clears in_on_retransmission_time_out_ when entering
+ // and exiting OnRetransmissionTimeout, respectively.
+ class QUIC_EXPORT_PRIVATE ScopedRetransmissionTimeoutIndicator {
+ public:
+ // |connection| must outlive this indicator.
+ explicit ScopedRetransmissionTimeoutIndicator(QuicConnection* connection);
+
+ ~ScopedRetransmissionTimeoutIndicator();
+
+ private:
+ QuicConnection* connection_; // Not owned.
+ };
+
+ QuicConnectionId& ClientConnectionId() {
+ return use_connection_id_on_default_path_
+ ? default_path_.client_connection_id
+ : client_connection_id_;
+ }
+ const QuicConnectionId& ClientConnectionId() const {
+ return use_connection_id_on_default_path_
+ ? default_path_.client_connection_id
+ : client_connection_id_;
+ }
+ QuicConnectionId& ServerConnectionId() {
+ return use_connection_id_on_default_path_
+ ? default_path_.server_connection_id
+ : server_connection_id_;
+ }
+ const QuicConnectionId& ServerConnectionId() const {
+ return use_connection_id_on_default_path_
+ ? default_path_.server_connection_id
+ : server_connection_id_;
+ }
+ void SetServerConnectionId(const QuicConnectionId& server_connection_id);
+
// Notifies the visitor of the close and marks the connection as disconnected.
// Does not send a connection close frame to the peer. It should only be
// called by CloseConnection or OnConnectionCloseFrame, OnPublicResetPacket,
@@ -1438,6 +1509,42 @@ class QUIC_EXPORT_PRIVATE QuicConnection
void ReplaceInitialServerConnectionId(
const QuicConnectionId& new_server_connection_id);
+ // Given the server_connection_id find if there is already a corresponding
+ // client connection ID used on default/alternative path. If not, find if
+ // there is an unused connection ID.
+ void FindMatchingOrNewClientConnectionIdOrToken(
+ const PathState& default_path,
+ const PathState& alternative_path,
+ const QuicConnectionId& server_connection_id,
+ QuicConnectionId* client_connection_id,
+ bool* stateless_reset_token_received,
+ StatelessResetToken* stateless_reset_token);
+
+ // Returns true and sets connection IDs if (self_address, peer_address)
+ // corresponds to either the default path or alternative path. Returns false
+ // otherwise.
+ bool FindOnPathConnectionIds(const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ QuicConnectionId* client_connection_id,
+ QuicConnectionId* server_connection_id) const;
+
+ // Set default_path_ to the new_path_state and update the connection IDs in
+ // packet creator accordingly.
+ void SetDefaultPathState(PathState new_path_state);
+
+ // Returns true if header contains valid server connection ID.
+ bool ValidateServerConnectionId(const QuicPacketHeader& header) const;
+
+ // Update the connection IDs when client migrates with/without validation.
+ // Returns false if required connection ID is not available.
+ bool UpdateConnectionIdsOnClientMigration(
+ const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address);
+
+ // Retire active peer issued connection IDs after they are no longer used on
+ // any path.
+ void RetirePeerIssuedConnectionIdsNoLongerOnPath();
+
// Writes the given packet to socket, encrypted with packet's
// encryption_level. Returns true on successful write, and false if the writer
// was blocked and the write needs to be tried again. Notifies the
@@ -1598,7 +1705,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicPacketNumber GetLargestAckedPacket() const;
// Whether incoming_connection_ids_ contains connection_id.
- bool HasIncomingConnectionId(QuicConnectionId connection_id);
+ bool HasIncomingConnectionId(QuicConnectionId connection_id) const;
// Whether connection is limited by amplification factor.
bool LimitedByAmplificationFactor() const;
@@ -1671,7 +1778,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Send PATH_RESPONSE to the given peer address.
bool SendPathResponse(const QuicPathFrameBuffer& data_buffer,
- QuicSocketAddress peer_address_to_send);
+ const QuicSocketAddress& peer_address_to_send,
+ const QuicSocketAddress& effective_peer_address);
// Update both connection's and packet creator's peer address.
void UpdatePeerAddress(QuicSocketAddress peer_address);
@@ -1734,6 +1842,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// preferred_address transport parameter.
bool OnNewConnectionIdFrameInner(const QuicNewConnectionIdFrame& frame);
+ // Called to patch missing client connection ID on default/alternative paths
+ // when a new client connection ID is received.
+ void OnClientConnectionIdAvailable();
+
QuicFramer framer_;
// Contents received in the current packet, especially used to identify
@@ -1829,7 +1941,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Collection of coalesced packets which were received while processing
// the current packet.
- QuicCircularDeque<std::unique_ptr<QuicEncryptedPacket>>
+ quiche::QuicheCircularDeque<std::unique_ptr<QuicEncryptedPacket>>
received_coalesced_packets_;
// Maximum number of undecryptable packets the connection will store.
@@ -1937,6 +2049,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Source address of the last received packet.
QuicSocketAddress last_packet_source_address_;
+ // Destination connection ID of the last received packet. If this ID is the
+ // original server connection ID chosen by client and server replaces it with
+ // a different ID, last_packet_destination_connection_id_ is set to the
+ // replacement connection ID on the server side.
+ QuicConnectionId last_packet_destination_connection_id_;
+
// Set to false if the connection should not send truncated connection IDs to
// the peer, even if the peer supports it.
bool can_truncate_connection_ids_;
@@ -2036,12 +2154,15 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// saved and responded to.
// TODO(danzh) deprecate this field when deprecating
// --quic_send_path_response.
- QuicCircularDeque<QuicPathFrameBuffer> received_path_challenge_payloads_;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer>
+ received_path_challenge_payloads_;
// Buffer outstanding PATH_CHALLENGEs if socket write is blocked, future
// OnCanWrite will attempt to respond with PATH_RESPONSEs using the retained
// payload and peer addresses.
- QuicCircularDeque<PendingPathChallenge> pending_path_challenge_payloads_;
+ // TODO(fayang): remove this when deprecating quic_drop_unsent_path_response.
+ quiche::QuicheCircularDeque<PendingPathChallenge>
+ pending_path_challenge_payloads_;
// Set of connection IDs that should be accepted as destination on
// received packets. This is conceptually a set but is implemented as a
@@ -2054,6 +2175,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// |original_destination_connection_id_| for validation.
absl::optional<QuicConnectionId> original_destination_connection_id_;
+ // The connection ID that replaces original_destination_connection_id_.
+ QuicConnectionId original_destination_connection_id_replacement_;
+
// After we receive a RETRY packet, |retry_source_connection_id_| contains
// the source connection ID from that packet.
absl::optional<QuicConnectionId> retry_source_connection_id_;
@@ -2094,13 +2218,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
size_t anti_amplification_factor_ =
GetQuicFlag(FLAGS_quic_anti_amplification_factor);
- bool start_peer_migration_earlier_ =
- GetQuicReloadableFlag(quic_start_peer_migration_earlier);
-
- // latch --gfe2_reloadable_flag_quic_send_path_response and
- // --gfe2_reloadable_flag_quic_start_peer_migration_earlier.
- bool send_path_response_ = start_peer_migration_earlier_ &&
- GetQuicReloadableFlag(quic_send_path_response2);
+ // latch --gfe2_reloadable_flag_quic_send_path_response.
+ bool send_path_response_ = GetQuicReloadableFlag(quic_send_path_response2);
bool use_path_validator_ =
send_path_response_ &&
@@ -2130,6 +2249,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// True after the first 1-RTT packet has successfully decrypted.
bool have_decrypted_first_one_rtt_packet_ = false;
+ // True if we are currently processing OnRetransmissionTimeout.
+ bool in_on_retransmission_time_out_ = false;
+
const bool encrypted_control_frames_;
const bool use_encryption_level_context_;
@@ -2163,6 +2285,23 @@ class QUIC_EXPORT_PRIVATE QuicConnection
const bool donot_write_mid_packet_processing_ =
GetQuicReloadableFlag(quic_donot_write_mid_packet_processing);
+
+ bool use_connection_id_on_default_path_ =
+ GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2);
+
+ // Indicates whether we should proactively validate peer address on a
+ // PATH_CHALLENGE received.
+ bool should_proactively_validate_peer_address_on_path_challenge_ = false;
+
+ // Enable this via reloadable flag once this feature is complete.
+ bool connection_migration_use_new_cid_ = false;
+
+ const bool group_path_response_and_challenge_sending_closer_ =
+ GetQuicReloadableFlag(
+ quic_group_path_response_and_challenge_sending_closer);
+
+ const bool quic_deprecate_incoming_connection_ids_ =
+ GetQuicReloadableFlag(quic_deprecate_incoming_connection_ids);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc
index 303db8f2069..a8cb4c0f377 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc
@@ -18,7 +18,6 @@
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/quiche_endian.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc
index a8e8c542f5f..f7089b7ebfd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc
@@ -199,6 +199,22 @@ void QuicPeerIssuedConnectionIdManager::PrepareToRetireActiveConnectionId(
}
}
+void QuicPeerIssuedConnectionIdManager::MaybeRetireUnusedConnectionIds(
+ const std::vector<QuicConnectionId>& active_connection_ids_on_path) {
+ std::vector<QuicConnectionId> cids_to_retire;
+ for (const auto& cid_data : active_connection_id_data_) {
+ if (std::find(active_connection_ids_on_path.begin(),
+ active_connection_ids_on_path.end(),
+ cid_data.connection_id) ==
+ active_connection_ids_on_path.end()) {
+ cids_to_retire.push_back(cid_data.connection_id);
+ }
+ }
+ for (const auto& cid : cids_to_retire) {
+ PrepareToRetireActiveConnectionId(cid);
+ }
+}
+
bool QuicPeerIssuedConnectionIdManager::IsConnectionIdActive(
const QuicConnectionId& cid) const {
return FindConnectionIdData(active_connection_id_data_, cid) !=
@@ -263,7 +279,8 @@ QuicSelfIssuedConnectionIdManager::QuicSelfIssuedConnectionIdManager(
retire_connection_id_alarm_(alarm_factory->CreateAlarm(
new RetireSelfIssuedConnectionIdAlarmDelegate(this))),
last_connection_id_(initial_connection_id),
- next_connection_id_sequence_number_(1u) {
+ next_connection_id_sequence_number_(1u),
+ last_connection_id_consumed_by_self_sequence_number_(0u) {
active_connection_ids_.emplace_back(initial_connection_id, 0u);
}
@@ -386,4 +403,45 @@ void QuicSelfIssuedConnectionIdManager::MaybeSendNewConnectionIds() {
}
}
+bool QuicSelfIssuedConnectionIdManager::HasConnectionIdToConsume() const {
+ for (const auto& active_cid_data : active_connection_ids_) {
+ if (active_cid_data.second >
+ last_connection_id_consumed_by_self_sequence_number_) {
+ return true;
+ }
+ }
+ return false;
+}
+
+absl::optional<QuicConnectionId>
+QuicSelfIssuedConnectionIdManager::ConsumeOneConnectionId() {
+ for (const auto& active_cid_data : active_connection_ids_) {
+ if (active_cid_data.second >
+ last_connection_id_consumed_by_self_sequence_number_) {
+ // Since connection IDs in active_connection_ids_ has monotonically
+ // increasing sequence numbers, the returned connection ID has the
+ // smallest sequence number among all unconsumed active connection IDs.
+ last_connection_id_consumed_by_self_sequence_number_ =
+ active_cid_data.second;
+ return active_cid_data.first;
+ }
+ }
+ return absl::nullopt;
+}
+
+bool QuicSelfIssuedConnectionIdManager::IsConnectionIdInUse(
+ const QuicConnectionId& cid) const {
+ for (const auto& active_cid_data : active_connection_ids_) {
+ if (active_cid_data.first == cid) {
+ return true;
+ }
+ }
+ for (const auto& to_be_retired_cid_data : to_be_retired_connection_ids_) {
+ if (to_be_retired_cid_data.first == cid) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h
index b933a69f158..5e7fc8ccf72 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h
@@ -13,6 +13,7 @@
#include <cstddef>
#include <memory>
+#include "absl/types/optional.h"
#include "quic/core/frames/quic_new_connection_id_frame.h"
#include "quic/core/frames/quic_retire_connection_id_frame.h"
#include "quic/core/quic_alarm.h"
@@ -68,13 +69,19 @@ class QUIC_EXPORT_PRIVATE QuicPeerIssuedConnectionIdManager {
QuicErrorCode OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame,
std::string* error_detail);
+ bool HasUnusedConnectionId() const {
+ return !unused_connection_id_data_.empty();
+ }
+
// Returns the data associated with an unused connection Id. After the call,
// the Id is marked as used. Returns nullptr if there is no unused connection
// Id.
const QuicConnectionIdData* ConsumeOneUnusedConnectionId();
- // Add the connection Id to the pending retirement connection Id list.
- void PrepareToRetireActiveConnectionId(const QuicConnectionId& cid);
+ // Add each active connection Id that is no longer on path to the pending
+ // retirement connection Id list.
+ void MaybeRetireUnusedConnectionIds(
+ const std::vector<QuicConnectionId>& active_connection_ids_on_path);
bool IsConnectionIdActive(const QuicConnectionId& cid) const;
@@ -90,6 +97,10 @@ class QUIC_EXPORT_PRIVATE QuicPeerIssuedConnectionIdManager {
private:
friend class test::QuicConnectionIdManagerPeer;
+ // Add the connection Id to the pending retirement connection Id list and
+ // schedule an alarm if needed.
+ void PrepareToRetireActiveConnectionId(const QuicConnectionId& cid);
+
bool IsConnectionIdNew(const QuicNewConnectionIdFrame& frame);
void PrepareToRetireConnectionIdPriorTo(
@@ -135,6 +146,17 @@ class QUIC_EXPORT_PRIVATE QuicSelfIssuedConnectionIdManager {
// Sends new connection IDs if more can be sent.
void MaybeSendNewConnectionIds();
+ // The two functions are called on the client side to associate a client
+ // connection ID with a new probing/migration path when client uses
+ // non-empty connection ID.
+ bool HasConnectionIdToConsume() const;
+ absl::optional<QuicConnectionId> ConsumeOneConnectionId();
+
+ // Returns true if the given connection ID is issued by the
+ // QuicSelfIssuedConnectionIdManager and not retired locally yet. Called to
+ // tell if a received packet has a valid connection ID.
+ bool IsConnectionIdInUse(const QuicConnectionId& cid) const;
+
virtual QuicConnectionId GenerateNewConnectionId(
const QuicConnectionId& old_connection_id) const;
@@ -162,6 +184,8 @@ class QUIC_EXPORT_PRIVATE QuicSelfIssuedConnectionIdManager {
// State of the last issued connection Id.
QuicConnectionId last_connection_id_;
uint64_t next_connection_id_sequence_number_;
+ // The sequence number of last connection ID consumed.
+ uint64_t last_connection_id_consumed_by_self_sequence_number_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc
index 9c7daf0db5e..7baeb2b247e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc
@@ -126,8 +126,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
frame.stateless_reset_token);
// Connection migration succeed. Prepares to retire CID #0.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(0));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {TestConnectionId(1)});
cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(1));
ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet());
alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_);
@@ -150,8 +150,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
// Start to use CID #2 for alternative path.
peer_issued_cid_manager_.ConsumeOneUnusedConnectionId();
// Connection migration succeed. Prepares to retire CID #1.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(1));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {TestConnectionId(2)});
cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(2));
ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet());
alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_);
@@ -174,8 +174,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
// Start to use CID #3 for alternative path.
peer_issued_cid_manager_.ConsumeOneUnusedConnectionId();
// Connection migration succeed. Prepares to retire CID #2.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(2));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {TestConnectionId(3)});
cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(3));
ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet());
alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_);
@@ -214,8 +214,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
// Start to use CID #1 for alternative path.
peer_issued_cid_manager_.ConsumeOneUnusedConnectionId();
// Connection migration fails. Prepares to retire CID #1.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(1));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {initial_connection_id_});
// Actually retires CID #1.
ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet());
alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_);
@@ -238,8 +238,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
// Start to use CID #2 for alternative path.
peer_issued_cid_manager_.ConsumeOneUnusedConnectionId();
// Connection migration fails again. Prepares to retire CID #2.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(2));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {initial_connection_id_});
// Actually retires CID #2.
ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet());
alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_);
@@ -262,8 +262,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
// Start to use CID #3 for alternative path.
peer_issued_cid_manager_.ConsumeOneUnusedConnectionId();
// Connection migration succeed. Prepares to retire CID #0.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(0));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {TestConnectionId(3)});
// After CID #3 is default (i.e., when there is no pending frame to write
// associated with CID #0), #0 can actually be retired.
cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(3));
@@ -374,8 +374,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest,
// Outcome: (active: #0 #1 unused: None)
peer_issued_cid_manager_.ConsumeOneUnusedConnectionId();
// Prepare to retire CID #1 as path validation fails.
- peer_issued_cid_manager_.PrepareToRetireActiveConnectionId(
- TestConnectionId(1));
+ peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds(
+ {initial_connection_id_});
// Actually retires CID #1.
ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet());
alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_);
@@ -845,20 +845,36 @@ TEST_F(QuicSelfIssuedConnectionIdManagerTest,
QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
+ QuicConnectionId cid;
EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(3);
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
.Times(3)
.WillRepeatedly(Return(true));
QuicTime::Delta connection_id_expire_timeout = 3 * pto_delay_;
QuicRetireConnectionIdFrame retire_cid_frame;
+ EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid0));
+ EXPECT_FALSE(cid_manager_.HasConnectionIdToConsume());
+ EXPECT_FALSE(cid_manager_.ConsumeOneConnectionId().has_value());
// CID #1 is sent to peer.
cid_manager_.MaybeSendNewConnectionIds();
+ EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid1));
+ EXPECT_TRUE(cid_manager_.HasConnectionIdToConsume());
+ cid = *cid_manager_.ConsumeOneConnectionId();
+ EXPECT_EQ(cid1, cid);
+ EXPECT_FALSE(cid_manager_.HasConnectionIdToConsume());
// CID #0's retirement is scheduled and CID #2 is sent to peer.
retire_cid_frame.sequence_number = 0u;
cid_manager_.OnRetireConnectionIdFrame(retire_cid_frame, pto_delay_,
&error_details_);
+ EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid0));
+ EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid1));
+ EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid2));
+ EXPECT_TRUE(cid_manager_.HasConnectionIdToConsume());
+ cid = *cid_manager_.ConsumeOneConnectionId();
+ EXPECT_EQ(cid2, cid);
+ EXPECT_FALSE(cid_manager_.HasConnectionIdToConsume());
clock_.AdvanceTime(connection_id_expire_timeout * 0.1);
@@ -874,6 +890,9 @@ TEST_F(QuicSelfIssuedConnectionIdManagerTest,
EXPECT_CALL(cid_manager_visitor_, OnSelfIssuedConnectionIdRetired(cid0));
EXPECT_CALL(cid_manager_visitor_, OnSelfIssuedConnectionIdRetired(cid1));
alarm_factory_.FireAlarm(retire_self_issued_cid_alarm_);
+ EXPECT_FALSE(cid_manager_.IsConnectionIdInUse(cid0));
+ EXPECT_FALSE(cid_manager_.IsConnectionIdInUse(cid1));
+ EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid2));
EXPECT_THAT(cid_manager_.GetUnretiredConnectionIds(),
ElementsAre(cid2, cid3));
EXPECT_FALSE(retire_self_issued_cid_alarm_->IsSet());
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
index 3d1b3c422a8..fbaa20abd94 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
@@ -34,8 +34,9 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) {
os << " pto_count: " << s.pto_count;
os << " min_rtt_us: " << s.min_rtt_us;
os << " srtt_us: " << s.srtt_us;
- os << " max_packet_size: " << s.max_packet_size;
- os << " max_received_packet_size: " << s.max_received_packet_size;
+ os << " egress_mtu: " << s.egress_mtu;
+ os << " max_egress_mtu: " << s.max_egress_mtu;
+ os << " ingress_mtu: " << s.ingress_mtu;
os << " estimated_bandwidth: " << s.estimated_bandwidth;
os << " packets_reordered: " << s.packets_reordered;
os << " max_sequence_reordering: " << s.max_sequence_reordering;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
index 06b7f5868bd..39fd5b087a6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
@@ -103,8 +103,14 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
int64_t min_rtt_us = 0; // Minimum RTT in microseconds.
int64_t srtt_us = 0; // Smoothed RTT in microseconds.
int64_t cwnd_bootstrapping_rtt_us = 0; // RTT used in cwnd_bootstrapping.
- QuicByteCount max_packet_size = 0;
- QuicByteCount max_received_packet_size = 0;
+ // The connection's |long_term_mtu_| used for sending packets, populated by
+ // QuicConnection::GetStats().
+ QuicByteCount egress_mtu = 0;
+ // The maximum |long_term_mtu_| the connection ever used.
+ QuicByteCount max_egress_mtu = 0;
+ // Size of the largest packet received from the peer, populated by
+ // QuicConnection::GetStats().
+ QuicByteCount ingress_mtu = 0;
QuicBandwidth estimated_bandwidth = QuicBandwidth::Zero();
// Reordering stats for received packets.
@@ -209,6 +215,10 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
// which was canceled because the peer migrated again. Such migration is also
// counted as invalid peer migration.
size_t num_peer_migration_while_validating_default_path = 0;
+ // Number of NEW_CONNECTION_ID frames sent.
+ size_t num_new_connection_id_sent = 0;
+ // Number of RETIRE_CONNECTION_ID frames sent.
+ size_t num_retire_connection_id_sent = 0;
struct QUIC_NO_EXPORT TlsServerOperationStats {
bool success = false;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc
index e2fba5b8325..fe2ff6cab6e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc
@@ -21,10 +21,12 @@
#include "quic/core/crypto/quic_decrypter.h"
#include "quic/core/crypto/quic_encrypter.h"
#include "quic/core/frames/quic_connection_close_frame.h"
+#include "quic/core/frames/quic_new_connection_id_frame.h"
#include "quic/core/frames/quic_path_response_frame.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_constants.h"
#include "quic/core/quic_error_codes.h"
+#include "quic/core/quic_packet_creator.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_path_validator.h"
#include "quic/core/quic_simple_buffer_allocator.h"
@@ -33,6 +35,7 @@
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_flags.h"
+#include "quic/platform/api/quic_ip_address.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_reference_counted.h"
#include "quic/platform/api/quic_socket_address.h"
@@ -764,6 +767,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
void use_tagging_decrypter() { writer_->use_tagging_decrypter(); }
+ void SetClientConnectionId(const QuicConnectionId& client_connection_id) {
+ connection_.set_client_connection_id(client_connection_id);
+ writer_->framer()->framer()->SetExpectedClientConnectionIdLength(
+ client_connection_id.length());
+ }
+
void SetDecrypter(EncryptionLevel level,
std::unique_ptr<QuicDecrypter> decrypter) {
if (connection_.version().KnowsWhichDecrypterToUse()) {
@@ -1190,8 +1199,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
EncryptionLevel level) {
QuicPacketHeader header = ConstructPacketHeader(number, level);
QuicFrames frames;
- if (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) &&
- VersionHasIetfQuicFrames(version().transport_version) &&
+ if (VersionHasIetfQuicFrames(version().transport_version) &&
(level == ENCRYPTION_INITIAL || level == ENCRYPTION_HANDSHAKE)) {
frames.push_back(QuicFrame(QuicPingFrame()));
frames.push_back(QuicFrame(QuicPaddingFrame(100)));
@@ -1420,8 +1428,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
EXPECT_TRUE(connection_.connected());
}
- void PathProbeTestInit(Perspective perspective) {
+ void PathProbeTestInit(Perspective perspective,
+ bool receive_new_server_connection_id = true) {
set_perspective(perspective);
+ connection_.CreateConnectionIdManager();
EXPECT_EQ(connection_.perspective(), perspective);
if (perspective == Perspective::IS_SERVER) {
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
@@ -1453,6 +1463,17 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
kPeerAddress, ENCRYPTION_FORWARD_SECURE);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+ if (perspective == Perspective::IS_CLIENT &&
+ receive_new_server_connection_id) {
+ QuicNewConnectionIdFrame frame;
+ frame.connection_id = TestConnectionId(1234);
+ ASSERT_NE(frame.connection_id, connection_.connection_id());
+ frame.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame.connection_id);
+ frame.retire_prior_to = 0u;
+ frame.sequence_number = 1u;
+ connection_.OnNewConnectionIdFrame(frame);
+ }
}
void TestClientRetryHandling(bool invalid_retry_tag,
@@ -1691,13 +1712,8 @@ TEST_P(QuicConnectionTest, PeerPortChangeAtServer) {
EXPECT_CALL(visitor_, OnStreamFrame(_))
.WillOnce(Invoke(
[=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); }))
- .WillOnce(Invoke([=]() {
- EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) ||
- !GetParam().version.HasIetfQuicFrames()
- ? kNewPeerAddress
- : kPeerAddress),
- connection_.peer_address());
- }));
+ .WillOnce(Invoke(
+ [=]() { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); }));
QuicFrames frames;
frames.push_back(QuicFrame(frame1_));
ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress,
@@ -1765,13 +1781,8 @@ TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServer) {
EXPECT_CALL(visitor_, OnStreamFrame(_))
.WillOnce(Invoke(
[=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); }))
- .WillOnce(Invoke([=]() {
- EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) ||
- !GetParam().version.HasIetfQuicFrames()
- ? kNewPeerAddress
- : kPeerAddress),
- connection_.peer_address());
- }));
+ .WillOnce(Invoke(
+ [=]() { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); }));
QuicFrames frames;
frames.push_back(QuicFrame(frame1_));
ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress,
@@ -1866,6 +1877,83 @@ TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServer) {
EXPECT_EQ(1u, connection_.GetStats().num_validated_peer_migration);
}
+TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServerWithMissingConnectionId) {
+ set_perspective(Perspective::IS_SERVER);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+
+ QuicConnectionId client_cid0 = TestConnectionId(1);
+ QuicConnectionId client_cid1 = TestConnectionId(3);
+ QuicConnectionId server_cid1;
+ SetClientConnectionId(client_cid0);
+ connection_.CreateConnectionIdManager();
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Prevent packets from being coalesced.
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+
+ // Sends new server CID to client.
+ EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ .WillOnce(
+ Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, SendNewConnectionId(_));
+ connection_.OnHandshakeComplete();
+
+ // Clear direct_peer_address.
+ QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
+ // Clear effective_peer_address, it is the same as direct_peer_address for
+ // this test.
+ QuicConnectionPeer::SetEffectivePeerAddress(&connection_,
+ QuicSocketAddress());
+ EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
+
+ const QuicSocketAddress kNewPeerAddress =
+ QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2);
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame1_));
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress,
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ // Send some data to make connection has packets in flight.
+ connection_.SendStreamData3();
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+ // Process another packet with a different peer address on server side will
+ // start connection migration.
+ peer_creator_.SetServerConnectionId(server_cid1);
+ EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1);
+ // Do not propagate OnCanWrite() to session notifier.
+ EXPECT_CALL(visitor_, OnCanWrite()).Times(AtLeast(1u));
+
+ QuicFrames frames2;
+ frames2.push_back(QuicFrame(frame2_));
+ ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress,
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
+
+ // Writing path response & reverse path challenge is blocked due to missing
+ // client connection ID, i.e., packets_write_attempts is unchanged.
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+ // Receives new client CID from client would unblock write.
+ QuicNewConnectionIdFrame new_cid_frame;
+ new_cid_frame.connection_id = client_cid1;
+ new_cid_frame.sequence_number = 1u;
+ new_cid_frame.retire_prior_to = 0u;
+ connection_.OnNewConnectionIdFrame(new_cid_frame);
+ connection_.SendStreamData3();
+
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+}
+
TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
@@ -1983,17 +2071,38 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
set_perspective(Perspective::IS_SERVER);
- if (!connection_.validate_client_address()) {
+ if (!connection_.connection_migration_use_new_cid()) {
return;
}
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ SetClientConnectionId(TestConnectionId(1));
+ connection_.CreateConnectionIdManager();
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
// Prevent packets from being coalesced.
EXPECT_CALL(visitor_, GetHandshakeState())
.WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
QuicConnectionPeer::SetAddressValidated(&connection_);
+
+ QuicConnectionId client_cid0 = connection_.client_connection_id();
+ QuicConnectionId client_cid1 = TestConnectionId(2);
+ QuicConnectionId server_cid0 = connection_.connection_id();
+ QuicConnectionId server_cid1;
+ // Sends new server CID to client.
+ EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ .WillOnce(
+ Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.OnHandshakeComplete();
+ // Receives new client CID from client.
+ QuicNewConnectionIdFrame new_cid_frame;
+ new_cid_frame.connection_id = client_cid1;
+ new_cid_frame.sequence_number = 1u;
+ new_cid_frame.retire_prior_to = 0u;
+ connection_.OnNewConnectionIdFrame(new_cid_frame);
+ auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+ ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+ ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -2008,13 +2117,8 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
EXPECT_CALL(visitor_, OnStreamFrame(_))
.WillOnce(Invoke(
[=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); }))
- .WillOnce(Invoke([=]() {
- EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) ||
- !GetParam().version.HasIetfQuicFrames()
- ? kNewPeerAddress
- : kPeerAddress),
- connection_.peer_address());
- }));
+ .WillOnce(Invoke(
+ [=]() { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); }));
QuicFrames frames;
frames.push_back(QuicFrame(frame1_));
ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress,
@@ -2033,6 +2137,7 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
frames2.push_back(QuicFrame(frame2_));
QuicPaddingFrame padding;
frames2.push_back(QuicFrame(padding));
+ peer_creator_.SetServerConnectionId(server_cid1);
ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress,
ENCRYPTION_FORWARD_SECURE);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
@@ -2046,6 +2151,15 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
+ const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ const auto* alternative_path =
+ QuicConnectionPeer::GetAlternativePath(&connection_);
+ EXPECT_EQ(default_path->client_connection_id, client_cid1);
+ EXPECT_EQ(default_path->server_connection_id, server_cid1);
+ EXPECT_EQ(alternative_path->client_connection_id, client_cid0);
+ EXPECT_EQ(alternative_path->server_connection_id, server_cid0);
+ EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid1);
+ EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1);
for (size_t i = 0; i < QuicPathValidator::kMaxRetryTimes; ++i) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs));
@@ -2072,6 +2186,19 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
EXPECT_EQ(connection_.sent_packet_manager().GetSendAlgorithm(),
send_algorithm_);
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Verify that default_path_ is reverted and alternative_path_ is cleared.
+ EXPECT_EQ(default_path->client_connection_id, client_cid0);
+ EXPECT_EQ(default_path->server_connection_id, server_cid0);
+ EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+ EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+ auto* retire_peer_issued_cid_alarm =
+ connection_.GetRetirePeerIssuedConnectionIdAlarm();
+ ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+ EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/1u));
+ retire_peer_issued_cid_alarm->Fire();
+ EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+ EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
}
TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
@@ -2184,10 +2311,12 @@ class TestQuicPathValidationContext : public QuicPathValidationContext {
class TestValidationResultDelegate : public QuicPathValidator::ResultDelegate {
public:
- TestValidationResultDelegate(const QuicSocketAddress& expected_self_address,
+ TestValidationResultDelegate(QuicConnection* connection,
+ const QuicSocketAddress& expected_self_address,
const QuicSocketAddress& expected_peer_address,
bool* success)
: QuicPathValidator::ResultDelegate(),
+ connection_(connection),
expected_self_address_(expected_self_address),
expected_peer_address_(expected_peer_address),
success_(success) {}
@@ -2202,10 +2331,14 @@ class TestValidationResultDelegate : public QuicPathValidator::ResultDelegate {
std::unique_ptr<QuicPathValidationContext> context) override {
EXPECT_EQ(expected_self_address_, context->self_address());
EXPECT_EQ(expected_peer_address_, context->peer_address());
+ if (connection_->perspective() == Perspective::IS_CLIENT) {
+ connection_->OnPathValidationFailureAtClient();
+ }
*success_ = false;
}
private:
+ QuicConnection* connection_;
QuicSocketAddress expected_self_address_;
QuicSocketAddress expected_peer_address_;
bool* success_;
@@ -2291,7 +2424,8 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) {
std::make_unique<TestQuicPathValidationContext>(
connection_.self_address(), kNewPeerAddress, writer_.get()),
std::make_unique<TestValidationResultDelegate>(
- connection_.self_address(), kNewPeerAddress, &success));
+ &connection_, connection_.self_address(), kNewPeerAddress,
+ &success));
}
EXPECT_EQ((connection_.validate_client_address() ? 2 : 3) * bytes_sent,
QuicConnectionPeer::BytesSentOnAlternativePath(&connection_));
@@ -2836,8 +2970,7 @@ TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
TEST_P(QuicConnectionTest, RejectUnencryptedStreamData) {
// EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
if (!IsDefaultTestConfiguration() ||
- (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) &&
- VersionHasIetfQuicFrames(version().transport_version))) {
+ VersionHasIetfQuicFrames(version().transport_version)) {
return;
}
@@ -3169,20 +3302,6 @@ TEST_P(QuicConnectionTest, TooManySentPackets) {
ProcessFramePacket(QuicFrame(QuicPingFrame()));
- if (!GetQuicReloadableFlag(
- quic_close_connection_with_too_many_outstanding_packets)) {
- // When the flag is false, the ping packet processed above shouldn't cause
- // the connection to close. But the ack packet below will.
- EXPECT_TRUE(connection_.connected());
-
- // Ack packet 1, which leaves more than the limit outstanding.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-
- // Nack the first packet and ack the rest, leaving a huge gap.
- QuicAckFrame frame1 = ConstructAckFrame(num_packets, 1);
- ProcessAckPacket(&frame1);
- }
-
TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS);
}
@@ -3390,15 +3509,15 @@ TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
- // Parse the last packet and ensure it's the crypto stream frame.
- EXPECT_EQ(2u, writer_->frame_count());
- ASSERT_EQ(1u, writer_->padding_frames().size());
+ // Parse the last packet and ensure it contains a crypto stream frame.
+ EXPECT_LE(2u, writer_->frame_count());
+ ASSERT_LE(1u, writer_->padding_frames().size());
if (!QuicVersionUsesCryptoFrames(connection_.transport_version())) {
ASSERT_EQ(1u, writer_->stream_frames().size());
EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()),
writer_->stream_frames()[0]->stream_id);
} else {
- EXPECT_EQ(1u, writer_->crypto_frames().size());
+ EXPECT_LE(1u, writer_->crypto_frames().size());
}
}
@@ -7081,7 +7200,7 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
stats.bytes_retransmitted);
EXPECT_EQ(3u, stats.packets_retransmitted);
EXPECT_EQ(1u, stats.rto_count);
- EXPECT_EQ(kDefaultMaxPacketSize, stats.max_packet_size);
+ EXPECT_EQ(kDefaultMaxPacketSize, stats.egress_mtu);
}
TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
@@ -7787,8 +7906,7 @@ TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
ForceProcessFramePacket(QuicFrame(frame1_));
- if (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) &&
- VersionHasIetfQuicFrames(version().transport_version)) {
+ if (VersionHasIetfQuicFrames(version().transport_version)) {
// INITIAL packet should not contain STREAM frame.
TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
} else {
@@ -7810,8 +7928,7 @@ TEST_P(QuicConnectionTest, ClientReceivesRejOnNonCryptoStream) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
ForceProcessFramePacket(QuicFrame(frame1_));
- if (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) &&
- VersionHasIetfQuicFrames(version().transport_version)) {
+ if (VersionHasIetfQuicFrames(version().transport_version)) {
// INITIAL packet should not contain STREAM frame.
TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
} else {
@@ -8899,7 +9016,7 @@ TEST_P(QuicConnectionTest, ClientResponseToPathChallengeOnAlternativeSocket) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
// Receiving a PATH_CHALLENGE on the alternative path. Response to this
// PATH_CHALLENGE should be sent via the alternative writer.
@@ -9300,7 +9417,7 @@ TEST_P(QuicConnectionTest, ValidClientConnectionId) {
return;
}
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.set_client_connection_id(TestConnectionId(0x33));
+ SetClientConnectionId(TestConnectionId(0x33));
QuicPacketHeader header = ConstructPacketHeader(1, ENCRYPTION_FORWARD_SECURE);
header.destination_connection_id = TestConnectionId(0x33);
header.destination_connection_id_included = CONNECTION_ID_PRESENT;
@@ -9328,7 +9445,7 @@ TEST_P(QuicConnectionTest, InvalidClientConnectionId) {
if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
- connection_.set_client_connection_id(TestConnectionId(0x33));
+ SetClientConnectionId(TestConnectionId(0x33));
QuicPacketHeader header = ConstructPacketHeader(1, ENCRYPTION_FORWARD_SECURE);
header.destination_connection_id = TestConnectionId(0xbad);
header.destination_connection_id_included = CONNECTION_ID_PRESENT;
@@ -11162,8 +11279,7 @@ TEST_P(QuicConnectionTest, ProcessUndecryptablePacketsBasedOnEncryptionLevel) {
std::make_unique<TaggingEncrypter>(0x01));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
// Verify all ENCRYPTION_HANDSHAKE packets get processed.
- if (!GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) ||
- !VersionHasIetfQuicFrames(version().transport_version)) {
+ if (!VersionHasIetfQuicFrames(version().transport_version)) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(6);
}
connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
@@ -11750,7 +11866,7 @@ TEST_P(QuicConnectionTest, PathValidationOnNewSocketSuccess) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
EXPECT_EQ(0u, writer_->packets_write_attempts());
QuicFrames frames;
@@ -11784,30 +11900,39 @@ TEST_P(QuicConnectionTest, NewPathValidationCancelsPreviousOne) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
EXPECT_EQ(0u, writer_->packets_write_attempts());
// Start another path validation request.
const QuicSocketAddress kNewSelfAddress2(QuicIpAddress::Any4(), 12346);
EXPECT_NE(kNewSelfAddress2, connection_.self_address());
TestPacketWriter new_writer2(version(), &clock_, Perspective::IS_CLIENT);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AtLeast(1u))
- .WillOnce(Invoke([&]() {
- EXPECT_EQ(1u, new_writer2.packets_write_attempts());
- EXPECT_EQ(1u, new_writer2.path_challenge_frames().size());
- EXPECT_EQ(1u, new_writer2.padding_frames().size());
- EXPECT_EQ(kNewSelfAddress2.host(),
- new_writer2.last_write_source_address());
- }));
+ if (!connection_.connection_migration_use_new_cid()) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(1u))
+ .WillOnce(Invoke([&]() {
+ EXPECT_EQ(1u, new_writer2.packets_write_attempts());
+ EXPECT_EQ(1u, new_writer2.path_challenge_frames().size());
+ EXPECT_EQ(1u, new_writer2.padding_frames().size());
+ EXPECT_EQ(kNewSelfAddress2.host(),
+ new_writer2.last_write_source_address());
+ }));
+ }
bool success2 = false;
connection_.ValidatePath(
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress2, connection_.peer_address(), &new_writer2),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress2, connection_.peer_address(), &success2));
+ &connection_, kNewSelfAddress2, connection_.peer_address(),
+ &success2));
EXPECT_FALSE(success);
- EXPECT_TRUE(connection_.HasPendingPathValidation());
+ if (connection_.connection_migration_use_new_cid()) {
+ // There is no pening path validation as there is no available connection
+ // ID.
+ EXPECT_FALSE(connection_.HasPendingPathValidation());
+ } else {
+ EXPECT_TRUE(connection_.HasPendingPathValidation());
+ }
}
// Regression test for b/182571515.
@@ -11825,12 +11950,12 @@ TEST_P(QuicConnectionTest, PathValidationRetry) {
EXPECT_EQ(1u, writer_->padding_frames().size());
}));
bool success = true;
- connection_.ValidatePath(
- std::make_unique<TestQuicPathValidationContext>(
- connection_.self_address(), connection_.peer_address(),
- writer_.get()),
- std::make_unique<TestValidationResultDelegate>(
- connection_.self_address(), connection_.peer_address(), &success));
+ connection_.ValidatePath(std::make_unique<TestQuicPathValidationContext>(
+ connection_.self_address(),
+ connection_.peer_address(), writer_.get()),
+ std::make_unique<TestValidationResultDelegate>(
+ &connection_, connection_.self_address(),
+ connection_.peer_address(), &success));
EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_TRUE(connection_.HasPendingPathValidation());
@@ -11872,7 +11997,7 @@ TEST_P(QuicConnectionTest, PathValidationReceivesStatelessReset) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
EXPECT_EQ(0u, writer_->packets_write_attempts());
EXPECT_TRUE(connection_.HasPendingPathValidation());
@@ -11916,7 +12041,7 @@ TEST_P(QuicConnectionTest, SendPathChallengeUsingBlockedNewSocket) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
EXPECT_EQ(0u, writer_->packets_write_attempts());
new_writer.SetWritable();
@@ -11976,7 +12101,8 @@ TEST_P(QuicConnectionTest, SendPathChallengeUsingBlockedDefaultSocket) {
std::make_unique<TestQuicPathValidationContext>(
connection_.self_address(), kNewPeerAddress, writer_.get()),
std::make_unique<TestValidationResultDelegate>(
- connection_.self_address(), kNewPeerAddress, &success));
+ &connection_, connection_.self_address(), kNewPeerAddress,
+ &success));
}
EXPECT_EQ(1u, writer_->packets_write_attempts());
@@ -12020,7 +12146,7 @@ TEST_P(QuicConnectionTest, SendPathChallengeFailOnNewSocket) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
EXPECT_EQ(1u, new_writer.packets_write_attempts());
EXPECT_EQ(1u, new_writer.path_challenge_frames().size());
EXPECT_EQ(1u, new_writer.padding_frames().size());
@@ -12052,12 +12178,12 @@ TEST_P(QuicConnectionTest, SendPathChallengeFailOnDefaultPath) {
// packet creator.
bool success = false;
QuicConnection::ScopedPacketFlusher flusher(&connection_);
- connection_.ValidatePath(
- std::make_unique<TestQuicPathValidationContext>(
- connection_.self_address(), connection_.peer_address(),
- writer_.get()),
- std::make_unique<TestValidationResultDelegate>(
- connection_.self_address(), connection_.peer_address(), &success));
+ connection_.ValidatePath(std::make_unique<TestQuicPathValidationContext>(
+ connection_.self_address(),
+ connection_.peer_address(), writer_.get()),
+ std::make_unique<TestValidationResultDelegate>(
+ &connection_, connection_.self_address(),
+ connection_.peer_address(), &success));
}
EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_EQ(1u, writer_->path_challenge_frames().size());
@@ -12089,7 +12215,7 @@ TEST_P(QuicConnectionTest, SendPathChallengeFailOnAlternativePeerAddress) {
std::make_unique<TestQuicPathValidationContext>(
connection_.self_address(), kNewPeerAddress, writer_.get()),
std::make_unique<TestValidationResultDelegate>(
- connection_.self_address(), kNewPeerAddress, &success));
+ &connection_, connection_.self_address(), kNewPeerAddress, &success));
EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_FALSE(connection_.HasPendingPathValidation());
@@ -12120,7 +12246,7 @@ TEST_P(QuicConnectionTest,
std::make_unique<TestQuicPathValidationContext>(
connection_.self_address(), kNewPeerAddress, writer_.get()),
std::make_unique<TestValidationResultDelegate>(
- connection_.self_address(), kNewPeerAddress, &success));
+ &connection_, connection_.self_address(), kNewPeerAddress, &success));
EXPECT_TRUE(connection_.HasPendingPathValidation());
// Connection shouldn't be closed.
EXPECT_TRUE(connection_.connected());
@@ -12391,7 +12517,12 @@ TEST_P(QuicConnectionTest, FailToWritePathResponse) {
ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress,
ENCRYPTION_FORWARD_SECURE);
- EXPECT_EQ(
+ if (GetQuicReloadableFlag(quic_drop_unsent_path_response)) {
+ EXPECT_EQ(0u, QuicConnectionPeer::NumPendingPathChallengesToResponse(
+ &connection_));
+ return;
+ }
+ ASSERT_EQ(
1u, QuicConnectionPeer::NumPendingPathChallengesToResponse(&connection_));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
@@ -13444,6 +13575,9 @@ TEST_P(QuicConnectionTest, ServerHelloGetsReordered) {
}
TEST_P(QuicConnectionTest, MigratePath) {
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .Times(testing::AtMost(1))
+ .WillOnce(Return(HANDSHAKE_CONFIRMED));
EXPECT_CALL(visitor_, OnPathDegrading());
connection_.OnPathDegradingDetected();
const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Any4(), 12345);
@@ -13472,7 +13606,7 @@ TEST_P(QuicConnectionTest, MigrateToNewPathDuringProbing) {
std::make_unique<TestQuicPathValidationContext>(
kNewSelfAddress, connection_.peer_address(), &new_writer),
std::make_unique<TestValidationResultDelegate>(
- kNewSelfAddress, connection_.peer_address(), &success));
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
&connection_, kNewSelfAddress, connection_.peer_address()));
@@ -13568,7 +13702,6 @@ TEST_P(QuicConnectionTest, NewTokenFrameInstigateAcks) {
if (!version().HasIetfQuicFrames()) {
return;
}
- SetQuicReloadableFlag(quic_enable_token_based_address_validation, true);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicNewTokenFrame* new_token = new QuicNewTokenFrame();
@@ -13583,7 +13716,6 @@ TEST_P(QuicConnectionTest, ServerClosesConnectionOnNewTokenFrame) {
if (!version().HasIetfQuicFrames()) {
return;
}
- SetQuicReloadableFlag(quic_enable_token_based_address_validation, true);
set_perspective(Perspective::IS_SERVER);
QuicNewTokenFrame* new_token = new QuicNewTokenFrame();
EXPECT_CALL(visitor_, OnNewTokenReceived(_)).Times(0);
@@ -13686,8 +13818,7 @@ TEST_P(QuicConnectionTest,
// Regression test for b/177312785
TEST_P(QuicConnectionTest, PeerMigrateBeforeHandshakeConfirm) {
- if (!VersionHasIetfQuicFrames(version().transport_version) ||
- !GetQuicReloadableFlag(quic_start_peer_migration_earlier)) {
+ if (!VersionHasIetfQuicFrames(version().transport_version)) {
return;
}
set_perspective(Perspective::IS_SERVER);
@@ -13755,11 +13886,34 @@ TEST_P(QuicConnectionTest, TryToFlushAckWithAckQueued) {
TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
set_perspective(Perspective::IS_SERVER);
- if (!connection_.validate_client_address()) {
+ if (!connection_.connection_migration_use_new_cid()) {
return;
}
PathProbeTestInit(Perspective::IS_SERVER);
+ SetClientConnectionId(TestConnectionId(1));
+ connection_.CreateConnectionIdManager();
+ QuicConnectionId server_cid0 = connection_.connection_id();
+ QuicConnectionId client_cid0 = connection_.client_connection_id();
+ QuicConnectionId client_cid1 = TestConnectionId(2);
+ QuicConnectionId server_cid1;
+ // Sends new server CID to client.
+ EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ .WillOnce(
+ Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, SendNewConnectionId(_));
+ connection_.MaybeSendConnectionIdToClient();
+ // Receives new client CID from client.
+ QuicNewConnectionIdFrame new_cid_frame;
+ new_cid_frame.connection_id = client_cid1;
+ new_cid_frame.sequence_number = 1u;
+ new_cid_frame.retire_prior_to = 0u;
+ connection_.OnNewConnectionIdFrame(new_cid_frame);
+ auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+ ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+ ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
+
+ peer_creator_.SetServerConnectionId(server_cid1);
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
QuicPathFrameBuffer path_challenge_payload{0, 1, 2, 3, 4, 5, 6, 7};
@@ -13783,6 +13937,15 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
EXPECT_TRUE(connection_.HasPendingPathValidation());
+ const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ const auto* alternative_path =
+ QuicConnectionPeer::GetAlternativePath(&connection_);
+ EXPECT_EQ(default_path->client_connection_id, client_cid0);
+ EXPECT_EQ(default_path->server_connection_id, server_cid0);
+ EXPECT_EQ(alternative_path->client_connection_id, client_cid1);
+ EXPECT_EQ(alternative_path->server_connection_id, server_cid1);
+ EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+ EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
// Process another packet with a different peer address on server side will
// start connection migration.
@@ -13819,6 +13982,14 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
EXPECT_CALL(*send_algorithm_, PopulateConnectionStats(_)).Times(AnyNumber());
connection_.SetSendAlgorithm(send_algorithm_);
+ EXPECT_EQ(default_path->client_connection_id, client_cid1);
+ EXPECT_EQ(default_path->server_connection_id, server_cid1);
+ // The previous default path is kept as alternative path before reverse path
+ // validation finishes.
+ EXPECT_EQ(alternative_path->client_connection_id, client_cid0);
+ EXPECT_EQ(alternative_path->server_connection_id, server_cid0);
+ EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid1);
+ EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
@@ -13842,6 +14013,15 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
ProcessFramesPacketWithAddresses(frames3, kSelfAddress, kNewPeerAddress,
ENCRYPTION_FORWARD_SECURE);
EXPECT_EQ(NO_CHANGE, connection_.active_effective_peer_migration_type());
+ // Verify that alternative_path_ is cleared and the peer CID is retired.
+ EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty());
+ EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+ EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+ auto* retire_peer_issued_cid_alarm =
+ connection_.GetRetirePeerIssuedConnectionIdAlarm();
+ ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+ EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u));
+ retire_peer_issued_cid_alarm->Fire();
// Verify the anti-amplification limit is lifted by sending a packet larger
// than the anti-amplification limit.
@@ -13853,12 +14033,25 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
TEST_P(QuicConnectionTest,
PathValidationSucceedsBeforePeerIpAddressChangeAtServer) {
set_perspective(Perspective::IS_SERVER);
- if (!connection_.validate_client_address()) {
+ if (!connection_.connection_migration_use_new_cid()) {
return;
}
PathProbeTestInit(Perspective::IS_SERVER);
+ connection_.CreateConnectionIdManager();
+
+ QuicConnectionId server_cid0 = connection_.connection_id();
+ QuicConnectionId server_cid1;
+ // Sends new server CID to client.
+ EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ .WillOnce(
+ Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, SendNewConnectionId(_));
+ connection_.MaybeSendConnectionIdToClient();
+ auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+ ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
// Receive probing packet with new peer address.
+ peer_creator_.SetServerConnectionId(server_cid1);
const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback4(),
/*port=*/23456);
QuicPathFrameBuffer payload;
@@ -13883,6 +14076,12 @@ TEST_P(QuicConnectionTest,
ProcessFramesPacketWithAddresses(frames1, kSelfAddress, kNewPeerAddress,
ENCRYPTION_FORWARD_SECURE);
EXPECT_TRUE(connection_.HasPendingPathValidation());
+ const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ const auto* alternative_path =
+ QuicConnectionPeer::GetAlternativePath(&connection_);
+ EXPECT_EQ(default_path->server_connection_id, server_cid0);
+ EXPECT_EQ(alternative_path->server_connection_id, server_cid1);
+ EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
// Receive PATH_RESPONSE should mark the new peer address validated.
QuicFrames frames3;
@@ -13920,6 +14119,12 @@ TEST_P(QuicConnectionTest,
EXPECT_NE(connection_.sent_packet_manager().GetSendAlgorithm(),
send_algorithm_);
+ EXPECT_EQ(default_path->server_connection_id, server_cid1);
+ EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1);
+ // Verify that alternative_path_ is cleared.
+ EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+ EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+
// Switch to use the mock send algorithm.
send_algorithm_ = new StrictMock<MockSendAlgorithm>();
EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true));
@@ -14005,6 +14210,255 @@ TEST_P(QuicConnectionTest,
}
TEST_P(QuicConnectionTest,
+ PathValidationFailedOnClientDueToLackOfServerConnectionId) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_CLIENT,
+ /*receive_new_server_connection_id=*/false);
+
+ const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Loopback4(),
+ /*port=*/34567);
+
+ bool success;
+ connection_.ValidatePath(
+ std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), writer_.get()),
+ std::make_unique<TestValidationResultDelegate>(
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
+
+ EXPECT_FALSE(success);
+}
+
+TEST_P(QuicConnectionTest,
+ PathValidationFailedOnClientDueToLackOfClientConnectionIdTheSecondTime) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_CLIENT,
+ /*receive_new_server_connection_id=*/false);
+ SetClientConnectionId(TestConnectionId(1));
+
+ // Make sure server connection ID is available for the 1st validation.
+ QuicConnectionId server_cid0 = connection_.connection_id();
+ QuicConnectionId server_cid1 = TestConnectionId(2);
+ QuicConnectionId server_cid2 = TestConnectionId(4);
+ QuicConnectionId client_cid1;
+ QuicNewConnectionIdFrame frame1;
+ frame1.connection_id = server_cid1;
+ frame1.sequence_number = 1u;
+ frame1.retire_prior_to = 0u;
+ frame1.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame1.connection_id);
+ connection_.OnNewConnectionIdFrame(frame1);
+ const auto* packet_creator =
+ QuicConnectionPeer::GetPacketCreator(&connection_);
+ ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid0);
+
+ // Client will issue a new client connection ID to server.
+ EXPECT_CALL(visitor_, SendNewConnectionId(_))
+ .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) {
+ client_cid1 = frame.connection_id;
+ }));
+
+ const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345);
+ ASSERT_NE(kSelfAddress1, connection_.self_address());
+ bool success1;
+ connection_.ValidatePath(
+ std::make_unique<TestQuicPathValidationContext>(
+ kSelfAddress1, connection_.peer_address(), writer_.get()),
+ std::make_unique<TestValidationResultDelegate>(
+ &connection_, kSelfAddress1, connection_.peer_address(), &success1));
+
+ // Migrate upon 1st validation success.
+ TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT);
+ ASSERT_TRUE(connection_.MigratePath(kSelfAddress1, connection_.peer_address(),
+ &new_writer, /*owns_writer=*/false));
+ QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_);
+ const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ EXPECT_EQ(default_path->client_connection_id, client_cid1);
+ EXPECT_EQ(default_path->server_connection_id, server_cid1);
+ EXPECT_EQ(default_path->stateless_reset_token, frame1.stateless_reset_token);
+ EXPECT_TRUE(default_path->stateless_reset_token_received);
+ const auto* alternative_path =
+ QuicConnectionPeer::GetAlternativePath(&connection_);
+ EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty());
+ EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+ EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+ ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid1);
+
+ // Client will retire server connection ID on old default_path.
+ auto* retire_peer_issued_cid_alarm =
+ connection_.GetRetirePeerIssuedConnectionIdAlarm();
+ ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+ EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u));
+ retire_peer_issued_cid_alarm->Fire();
+
+ // Another server connection ID is available to client.
+ QuicNewConnectionIdFrame frame2;
+ frame2.connection_id = server_cid2;
+ frame2.sequence_number = 2u;
+ frame2.retire_prior_to = 1u;
+ frame2.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame2.connection_id);
+ connection_.OnNewConnectionIdFrame(frame2);
+
+ const QuicSocketAddress kSelfAddress2(QuicIpAddress::Loopback4(),
+ /*port=*/45678);
+ bool success2;
+ connection_.ValidatePath(
+ std::make_unique<TestQuicPathValidationContext>(
+ kSelfAddress2, connection_.peer_address(), writer_.get()),
+ std::make_unique<TestValidationResultDelegate>(
+ &connection_, kSelfAddress2, connection_.peer_address(), &success2));
+ // Since server does not retire any client connection ID yet, 2nd validation
+ // would fail due to lack of client connection ID.
+ EXPECT_FALSE(success2);
+}
+
+TEST_P(QuicConnectionTest, ServerConnectionIdRetiredUponPathValidationFailure) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_CLIENT);
+
+ // Make sure server connection ID is available for validation.
+ QuicNewConnectionIdFrame frame;
+ frame.connection_id = TestConnectionId(2);
+ frame.sequence_number = 1u;
+ frame.retire_prior_to = 0u;
+ frame.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame.connection_id);
+ connection_.OnNewConnectionIdFrame(frame);
+
+ const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Loopback4(),
+ /*port=*/34567);
+ bool success;
+ connection_.ValidatePath(
+ std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), writer_.get()),
+ std::make_unique<TestValidationResultDelegate>(
+ &connection_, kNewSelfAddress, connection_.peer_address(), &success));
+
+ auto* path_validator = QuicConnectionPeer::path_validator(&connection_);
+ path_validator->CancelPathValidation();
+ QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_);
+ EXPECT_FALSE(success);
+ const auto* alternative_path =
+ QuicConnectionPeer::GetAlternativePath(&connection_);
+ EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty());
+ EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty());
+ EXPECT_FALSE(alternative_path->stateless_reset_token_received);
+
+ // Client will retire server connection ID on alternative_path.
+ auto* retire_peer_issued_cid_alarm =
+ connection_.GetRetirePeerIssuedConnectionIdAlarm();
+ ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+ EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/1u));
+ retire_peer_issued_cid_alarm->Fire();
+}
+
+TEST_P(QuicConnectionTest,
+ MigratePathDirectlyFailedDueToLackOfServerConnectionId) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_CLIENT,
+ /*receive_new_server_connection_id=*/false);
+ const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345);
+ ASSERT_NE(kSelfAddress1, connection_.self_address());
+
+ TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT);
+ ASSERT_FALSE(connection_.MigratePath(kSelfAddress1,
+ connection_.peer_address(), &new_writer,
+ /*owns_writer=*/false));
+}
+
+TEST_P(QuicConnectionTest,
+ MigratePathDirectlyFailedDueToLackOfClientConnectionIdTheSecondTime) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_CLIENT,
+ /*receive_new_server_connection_id=*/false);
+ SetClientConnectionId(TestConnectionId(1));
+
+ // Make sure server connection ID is available for the 1st migration.
+ QuicNewConnectionIdFrame frame1;
+ frame1.connection_id = TestConnectionId(2);
+ frame1.sequence_number = 1u;
+ frame1.retire_prior_to = 0u;
+ frame1.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame1.connection_id);
+ connection_.OnNewConnectionIdFrame(frame1);
+
+ // Client will issue a new client connection ID to server.
+ QuicConnectionId new_client_connection_id;
+ EXPECT_CALL(visitor_, SendNewConnectionId(_))
+ .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) {
+ new_client_connection_id = frame.connection_id;
+ }));
+
+ // 1st migration is successful.
+ const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345);
+ ASSERT_NE(kSelfAddress1, connection_.self_address());
+ TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT);
+ ASSERT_TRUE(connection_.MigratePath(kSelfAddress1, connection_.peer_address(),
+ &new_writer,
+ /*owns_writer=*/false));
+ QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_);
+ const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ EXPECT_EQ(default_path->client_connection_id, new_client_connection_id);
+ EXPECT_EQ(default_path->server_connection_id, frame1.connection_id);
+ EXPECT_EQ(default_path->stateless_reset_token, frame1.stateless_reset_token);
+ EXPECT_TRUE(default_path->stateless_reset_token_received);
+
+ // Client will retire server connection ID on old default_path.
+ auto* retire_peer_issued_cid_alarm =
+ connection_.GetRetirePeerIssuedConnectionIdAlarm();
+ ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+ EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u));
+ retire_peer_issued_cid_alarm->Fire();
+
+ // Another server connection ID is available to client.
+ QuicNewConnectionIdFrame frame2;
+ frame2.connection_id = TestConnectionId(4);
+ frame2.sequence_number = 2u;
+ frame2.retire_prior_to = 1u;
+ frame2.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame2.connection_id);
+ connection_.OnNewConnectionIdFrame(frame2);
+
+ // Since server does not retire any client connection ID yet, 2nd migration
+ // would fail due to lack of client connection ID.
+ const QuicSocketAddress kSelfAddress2(QuicIpAddress::Loopback4(),
+ /*port=*/45678);
+ ASSERT_FALSE(connection_.MigratePath(kSelfAddress2,
+ connection_.peer_address(), &new_writer,
+ /*owns_writer=*/false));
+}
+
+TEST_P(QuicConnectionTest,
CloseConnectionAfterReceiveNewConnectionIdFromPeerUsingEmptyCID) {
if (!version().HasIetfQuicFrames()) {
return;
@@ -14098,7 +14552,7 @@ TEST_P(QuicConnectionTest,
}
QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
set_perspective(Perspective::IS_SERVER);
- connection_.set_client_connection_id(TestConnectionId(0));
+ SetClientConnectionId(TestConnectionId(0));
QuicNewConnectionIdFrame frame;
frame.sequence_number = 1u;
@@ -14129,9 +14583,71 @@ TEST_P(QuicConnectionTest,
TestConnectionId(2));
}
+TEST_P(
+ QuicConnectionTest,
+ ReplacePeerIssuedConnectionIdOnBothPathsTriggeredByNewConnectionIdFrame) {
+ if (!version().HasIetfQuicFrames() || !connection_.use_path_validator() ||
+ !connection_.use_connection_id_on_default_path() ||
+ !connection_.count_bytes_on_alternative_path_separately()) {
+ return;
+ }
+ QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
+ PathProbeTestInit(Perspective::IS_SERVER);
+ SetClientConnectionId(TestConnectionId(0));
+
+ // Populate alternative_path_ with probing packet.
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
+
+ std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+ QuicEncryptedPacket(probing_packet->encrypted_buffer,
+ probing_packet->encrypted_length),
+ clock_.Now()));
+ QuicIpAddress new_host;
+ new_host.FromString("1.1.1.1");
+ ProcessReceivedPacket(kSelfAddress,
+ QuicSocketAddress(new_host, /*port=*/23456), *received);
+
+ EXPECT_EQ(
+ TestConnectionId(0),
+ QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(&connection_));
+
+ QuicNewConnectionIdFrame frame;
+ frame.sequence_number = 1u;
+ frame.connection_id = TestConnectionId(1);
+ frame.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame.connection_id);
+ frame.retire_prior_to = 0u;
+
+ EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
+ auto* retire_peer_issued_cid_alarm =
+ connection_.GetRetirePeerIssuedConnectionIdAlarm();
+ ASSERT_FALSE(retire_peer_issued_cid_alarm->IsSet());
+
+ frame.sequence_number = 2u;
+ frame.connection_id = TestConnectionId(2);
+ frame.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame.connection_id);
+ frame.retire_prior_to = 1u; // CID associated with #1 will be retired.
+
+ EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
+ ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet());
+ EXPECT_EQ(connection_.client_connection_id(), TestConnectionId(0));
+
+ EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u));
+ retire_peer_issued_cid_alarm->Fire();
+ EXPECT_EQ(connection_.client_connection_id(), TestConnectionId(2));
+ EXPECT_EQ(connection_.packet_creator().GetDestinationConnectionId(),
+ TestConnectionId(2));
+ // Clean up alternative path connection ID.
+ EXPECT_EQ(
+ TestConnectionId(2),
+ QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(&connection_));
+}
+
TEST_P(QuicConnectionTest,
CloseConnectionAfterReceiveRetireConnectionIdWhenNoCIDIssued) {
- if (!version().HasIetfQuicFrames()) {
+ if (!version().HasIetfQuicFrames() ||
+ GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) {
return;
}
QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
@@ -14151,7 +14667,8 @@ TEST_P(QuicConnectionTest,
}
TEST_P(QuicConnectionTest, RetireConnectionIdFrameResultsInError) {
- if (!version().HasIetfQuicFrames()) {
+ if (!version().HasIetfQuicFrames() ||
+ GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) {
return;
}
QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
@@ -14175,8 +14692,40 @@ TEST_P(QuicConnectionTest, RetireConnectionIdFrameResultsInError) {
IsError(IETF_QUIC_PROTOCOL_VIOLATION));
}
+TEST_P(QuicConnectionTest,
+ ServerRetireSelfIssuedConnectionIdWithoutSendingNewConnectionIdBefore) {
+ if (!connection_.support_multiple_connection_ids()) {
+ return;
+ }
+ QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
+ set_perspective(Perspective::IS_SERVER);
+ connection_.CreateConnectionIdManager();
+
+ auto* retire_self_issued_cid_alarm =
+ connection_.GetRetireSelfIssuedConnectionIdAlarm();
+ ASSERT_FALSE(retire_self_issued_cid_alarm->IsSet());
+
+ QuicConnectionId cid0 = connection_id_;
+ QuicRetireConnectionIdFrame frame;
+ frame.sequence_number = 0u;
+ if (!GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2) ||
+ connection_.connection_migration_use_new_cid()) {
+ EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)).Times(2);
+ EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(2);
+ }
+ EXPECT_TRUE(connection_.OnRetireConnectionIdFrame(frame));
+ if (!GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) {
+ ASSERT_TRUE(retire_self_issued_cid_alarm->IsSet());
+ // cid0 is retired when the retire CID alarm fires.
+ if (!GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2))
+ EXPECT_CALL(visitor_, OnServerConnectionIdRetired(cid0));
+ retire_self_issued_cid_alarm->Fire();
+ }
+}
+
TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) {
- if (!version().HasIetfQuicFrames()) {
+ if (!version().HasIetfQuicFrames() ||
+ GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) {
return;
}
QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
@@ -14219,6 +14768,121 @@ TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) {
ElementsAre(cid1, cid2));
}
+TEST_P(QuicConnectionTest, PatchMissingClientConnectionIdOntoAlternativePath) {
+ if (!version().HasIetfQuicFrames() ||
+ !connection_.support_multiple_connection_ids() ||
+ !connection_.use_connection_id_on_default_path()) {
+ return;
+ }
+ set_perspective(Perspective::IS_SERVER);
+ connection_.CreateConnectionIdManager();
+ connection_.set_client_connection_id(TestConnectionId(1));
+
+ // Set up the state after path probing.
+ const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ auto* alternative_path = QuicConnectionPeer::GetAlternativePath(&connection_);
+ QuicIpAddress new_host;
+ new_host.FromString("12.12.12.12");
+ alternative_path->self_address = default_path->self_address;
+ alternative_path->peer_address = QuicSocketAddress(new_host, 12345);
+ alternative_path->server_connection_id = TestConnectionId(3);
+ ASSERT_TRUE(alternative_path->client_connection_id.IsEmpty());
+ ASSERT_FALSE(alternative_path->stateless_reset_token_received);
+
+ QuicNewConnectionIdFrame frame;
+ frame.sequence_number = 1u;
+ frame.connection_id = TestConnectionId(5);
+ frame.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame.connection_id);
+ frame.retire_prior_to = 0u;
+ // New ID is patched onto the alternative path when the needed
+ // NEW_CONNECTION_ID frame is received after PATH_CHALLENGE frame.
+ connection_.OnNewConnectionIdFrame(frame);
+
+ ASSERT_EQ(alternative_path->client_connection_id, frame.connection_id);
+ ASSERT_EQ(alternative_path->stateless_reset_token,
+ frame.stateless_reset_token);
+ ASSERT_TRUE(alternative_path->stateless_reset_token_received);
+}
+
+TEST_P(QuicConnectionTest, PatchMissingClientConnectionIdOntoDefaultPath) {
+ if (!version().HasIetfQuicFrames() ||
+ !connection_.support_multiple_connection_ids() ||
+ !connection_.use_connection_id_on_default_path()) {
+ return;
+ }
+ set_perspective(Perspective::IS_SERVER);
+ connection_.CreateConnectionIdManager();
+ connection_.set_client_connection_id(TestConnectionId(1));
+
+ // Set up the state after peer migration without probing.
+ auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+ auto* alternative_path = QuicConnectionPeer::GetAlternativePath(&connection_);
+ auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+ *alternative_path = std::move(*default_path);
+ QuicIpAddress new_host;
+ new_host.FromString("12.12.12.12");
+ default_path->self_address = default_path->self_address;
+ default_path->peer_address = QuicSocketAddress(new_host, 12345);
+ default_path->server_connection_id = TestConnectionId(3);
+ packet_creator->SetDefaultPeerAddress(default_path->peer_address);
+ packet_creator->SetServerConnectionId(default_path->server_connection_id);
+ packet_creator->SetClientConnectionId(default_path->client_connection_id);
+
+ ASSERT_FALSE(default_path->validated);
+ ASSERT_TRUE(default_path->client_connection_id.IsEmpty());
+ ASSERT_FALSE(default_path->stateless_reset_token_received);
+
+ QuicNewConnectionIdFrame frame;
+ frame.sequence_number = 1u;
+ frame.connection_id = TestConnectionId(5);
+ frame.stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(frame.connection_id);
+ frame.retire_prior_to = 0u;
+ // New ID is patched onto the default path when the needed
+ // NEW_CONNECTION_ID frame is received after PATH_CHALLENGE frame.
+ connection_.OnNewConnectionIdFrame(frame);
+
+ ASSERT_EQ(default_path->client_connection_id, frame.connection_id);
+ ASSERT_EQ(default_path->stateless_reset_token, frame.stateless_reset_token);
+ ASSERT_TRUE(default_path->stateless_reset_token_received);
+ ASSERT_EQ(packet_creator->GetDestinationConnectionId(), frame.connection_id);
+}
+
+TEST_P(QuicConnectionTest, ShouldGeneratePacketBlockedByMissingConnectionId) {
+ if (!version().HasIetfQuicFrames() ||
+ !connection_.support_multiple_connection_ids()) {
+ return;
+ }
+ set_perspective(Perspective::IS_SERVER);
+ connection_.set_client_connection_id(TestConnectionId(1));
+ connection_.CreateConnectionIdManager();
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ }
+
+ ASSERT_TRUE(
+ connection_.ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE));
+
+ QuicPacketCreator* packet_creator =
+ QuicConnectionPeer::GetPacketCreator(&connection_);
+ QuicIpAddress peer_host1;
+ peer_host1.FromString("12.12.12.12");
+ QuicSocketAddress peer_address1(peer_host1, 1235);
+
+ {
+ // No connection ID is available as context is created without any.
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ packet_creator, peer_address1, EmptyQuicConnectionId(),
+ EmptyQuicConnectionId(),
+ /*update_connection_id=*/true);
+ ASSERT_FALSE(connection_.ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE));
+ }
+ ASSERT_TRUE(
+ connection_.ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE));
+}
+
// Regression test for b/182571515
TEST_P(QuicConnectionTest, LostDataThenGetAcknowledged) {
set_perspective(Perspective::IS_SERVER);
@@ -14278,6 +14942,53 @@ TEST_P(QuicConnectionTest, LostDataThenGetAcknowledged) {
}
}
+TEST_P(QuicConnectionTest, PtoSendStreamData) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ set_perspective(Perspective::IS_SERVER);
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ use_tagging_decrypter();
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+ EXPECT_TRUE(connection_.HasPendingAcks());
+
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Send INITIAL 1.
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL);
+
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ SetDecrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<StrictTaggingDecrypter>(0x02));
+ // Send HANDSHAKE packets.
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
+
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(0x03));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ // Send half RTT packet with congestion control blocked.
+ EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(false));
+ connection_.SendStreamDataWithString(2, std::string(1500, 'a'), 0, NO_FIN);
+
+ ASSERT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ connection_.GetRetransmissionAlarm()->Fire();
+ if (GetQuicReloadableFlag(quic_donot_pto_half_rtt_data)) {
+ // Verify INITIAL and HANDSHAKE get retransmitted.
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+ } else {
+ // Application data preempts handshake data when PTO fires.
+ EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
index 1bb37035912..48d228bff31 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
@@ -8,10 +8,11 @@
#include <cstdint>
#include <string>
+#include "absl/container/flat_hash_map.h"
#include "quic/core/frames/quic_frame.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_types.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -163,7 +164,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// frame.
void WriteOrBufferQuicFrame(QuicFrame frame);
- QuicCircularDeque<QuicFrame> control_frames_;
+ quiche::QuicheCircularDeque<QuicFrame> control_frames_;
// Id of latest saved control frame. 0 if no control frame has been saved.
QuicControlFrameId last_control_frame_id_;
@@ -182,7 +183,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
DelegateInterface* delegate_;
// Last sent window update frame for each stream.
- QuicSmallMap<QuicStreamId, QuicControlFrameId, 10> window_update_frames_;
+ absl::flat_hash_map<QuicStreamId, QuicControlFrameId> window_update_frames_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
index fc9be1764a2..1dd68995e2f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
@@ -11,7 +11,7 @@
#include "absl/strings/string_view.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
#include "quic/platform/api/quic_flag_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
index 88fdda9d6c2..4e07f34b616 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
@@ -354,8 +354,7 @@ class QuicCryptoServerStreamTestWithFakeProofSource
};
// Regression test for b/35422225, in which multiple CHLOs arriving on the same
-// connection in close succession could cause a crash, especially when the use
-// of Mentat signing meant that it took a while for each CHLO to be processed.
+// connection in close succession could cause a crash.
TEST_F(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) {
Initialize();
GetFakeProofSource()->Activate();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h b/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h
index 286aeae6bf8..4d3aa2f17f3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h
@@ -8,10 +8,10 @@
#include <memory>
#include "absl/types/optional.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_time.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_mem_slice.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -80,7 +80,7 @@ class QUIC_EXPORT_PRIVATE QuicDatagramQueue {
const QuicClock* clock_;
QuicTime::Delta max_time_in_queue_ = QuicTime::Delta::Zero();
- QuicCircularDeque<Datagram> queue_;
+ quiche::QuicheCircularDeque<Datagram> queue_;
std::unique_ptr<Observer> observer_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc
index 0ed002a6850..e1a999c706a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc
@@ -26,7 +26,7 @@
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_stack_trace.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
@@ -331,9 +331,6 @@ QuicDispatcher::QuicDispatcher(
expected_server_connection_id_length_(
expected_server_connection_id_length),
should_update_expected_server_connection_id_length_(false) {
- if (use_reference_counted_session_map_) {
- QUIC_RESTART_FLAG_COUNT(quic_use_reference_counted_sesssion_map);
- }
QUIC_BUG_IF(quic_bug_12724_1, GetSupportedVersions().empty())
<< "Trying to create dispatcher without any supported versions";
QUIC_DLOG(INFO) << "Created QuicDispatcher with versions: "
@@ -341,15 +338,10 @@ QuicDispatcher::QuicDispatcher(
}
QuicDispatcher::~QuicDispatcher() {
- if (use_reference_counted_session_map_) {
- reference_counted_session_map_.clear();
- closed_ref_counted_session_list_.clear();
- if (support_multiple_cid_per_connection_) {
- num_sessions_in_session_map_ = 0;
- }
- } else {
- session_map_.clear();
- closed_session_list_.clear();
+ reference_counted_session_map_.clear();
+ closed_ref_counted_session_list_.clear();
+ if (support_multiple_cid_per_connection_) {
+ num_sessions_in_session_map_ = 0;
}
}
@@ -510,60 +502,45 @@ bool QuicDispatcher::MaybeDispatchPacket(
return true;
}
+ if (GetQuicReloadableFlag(quic_discard_packets_with_invalid_cid)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_discard_packets_with_invalid_cid);
+ if (packet_info.version_flag && packet_info.version.IsKnown() &&
+ !QuicUtils::IsConnectionIdLengthValidForVersion(
+ server_connection_id.length(),
+ packet_info.version.transport_version)) {
+ QUIC_DLOG(INFO) << "Packet with destination connection ID "
+ << server_connection_id << " is invalid with version "
+ << packet_info.version;
+ // Drop the packet silently.
+ QUIC_CODE_COUNT(quic_dropped_invalid_initial_connection_id);
+ return true;
+ }
+ }
+
// Packets with connection IDs for active connections are processed
// immediately.
- if (use_reference_counted_session_map_) {
- auto it = reference_counted_session_map_.find(server_connection_id);
- if (it != reference_counted_session_map_.end()) {
- QUICHE_DCHECK(
- !buffered_packets_.HasBufferedPackets(server_connection_id));
- if (packet_info.version_flag &&
- packet_info.version != it->second->version() &&
- packet_info.version == LegacyVersionForEncapsulation()) {
- // This packet is using the Legacy Version Encapsulation version but the
- // corresponding session isn't, attempt extraction of inner packet.
- ChloAlpnSniExtractor alpn_extractor;
- if (ChloExtractor::Extract(packet_info.packet, packet_info.version,
- config_->create_session_tag_indicators(),
- &alpn_extractor,
- server_connection_id.length())) {
- if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
- packet_info)) {
- return true;
- }
+ auto it = reference_counted_session_map_.find(server_connection_id);
+ if (it != reference_counted_session_map_.end()) {
+ QUICHE_DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id));
+ if (packet_info.version_flag &&
+ packet_info.version != it->second->version() &&
+ packet_info.version == LegacyVersionForEncapsulation()) {
+ // This packet is using the Legacy Version Encapsulation version but the
+ // corresponding session isn't, attempt extraction of inner packet.
+ ChloAlpnSniExtractor alpn_extractor;
+ if (ChloExtractor::Extract(packet_info.packet, packet_info.version,
+ config_->create_session_tag_indicators(),
+ &alpn_extractor,
+ server_connection_id.length())) {
+ if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
+ packet_info)) {
+ return true;
}
}
- it->second->ProcessUdpPacket(packet_info.self_address,
- packet_info.peer_address,
- packet_info.packet);
- return true;
- }
- } else {
- auto it = session_map_.find(server_connection_id);
- if (it != session_map_.end()) {
- QUICHE_DCHECK(
- !buffered_packets_.HasBufferedPackets(server_connection_id));
- if (packet_info.version_flag &&
- packet_info.version != it->second->version() &&
- packet_info.version == LegacyVersionForEncapsulation()) {
- // This packet is using the Legacy Version Encapsulation version but the
- // corresponding session isn't, attempt extraction of inner packet.
- ChloAlpnSniExtractor alpn_extractor;
- if (ChloExtractor::Extract(packet_info.packet, packet_info.version,
- config_->create_session_tag_indicators(),
- &alpn_extractor,
- server_connection_id.length())) {
- if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
- packet_info)) {
- return true;
- }
- }
- }
- it->second->ProcessUdpPacket(packet_info.self_address,
- packet_info.peer_address,
- packet_info.packet);
- return true;
}
+ it->second->ProcessUdpPacket(packet_info.self_address,
+ packet_info.peer_address, packet_info.packet);
+ return true;
}
if (packet_info.version.IsKnown()) {
// We did not find the connection ID, check if we've replaced it.
@@ -575,28 +552,15 @@ bool QuicDispatcher::MaybeDispatchPacket(
QuicConnectionId replaced_connection_id = MaybeReplaceServerConnectionId(
server_connection_id, packet_info.version);
if (replaced_connection_id != server_connection_id) {
- if (use_reference_counted_session_map_) {
- // Search for the replacement.
- auto it2 = reference_counted_session_map_.find(replaced_connection_id);
- if (it2 != reference_counted_session_map_.end()) {
- QUICHE_DCHECK(
- !buffered_packets_.HasBufferedPackets(replaced_connection_id));
- it2->second->ProcessUdpPacket(packet_info.self_address,
- packet_info.peer_address,
- packet_info.packet);
- return true;
- }
- } else {
- // Search for the replacement.
- auto it2 = session_map_.find(replaced_connection_id);
- if (it2 != session_map_.end()) {
- QUICHE_DCHECK(
- !buffered_packets_.HasBufferedPackets(replaced_connection_id));
- it2->second->ProcessUdpPacket(packet_info.self_address,
- packet_info.peer_address,
- packet_info.packet);
- return true;
- }
+ // Search for the replacement.
+ auto it2 = reference_counted_session_map_.find(replaced_connection_id);
+ if (it2 != reference_counted_session_map_.end()) {
+ QUICHE_DCHECK(
+ !buffered_packets_.HasBufferedPackets(replaced_connection_id));
+ it2->second->ProcessUdpPacket(packet_info.self_address,
+ packet_info.peer_address,
+ packet_info.packet);
+ return true;
}
}
}
@@ -812,9 +776,9 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id,
QuicConnection* connection,
- QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) {
+ QuicErrorCode /*error*/,
+ const std::string& /*error_details*/,
+ ConnectionCloseSource /*source*/) {
write_blocked_list_.erase(connection);
QuicTimeWaitListManager::TimeWaitAction action =
QuicTimeWaitListManager::SEND_STATELESS_RESET;
@@ -823,14 +787,8 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id,
action = QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS;
} else {
if (!connection->IsHandshakeComplete()) {
- const bool fix_dispatcher_sent_error_code =
- GetQuicReloadableFlag(quic_fix_dispatcher_sent_error_code) &&
- source == ConnectionCloseSource::FROM_SELF;
// TODO(fayang): Do not serialize connection close packet if the
// connection is closed by the client.
- if (fix_dispatcher_sent_error_code) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_dispatcher_sent_error_code);
- }
if (!connection->version().HasIetfInvariantHeader()) {
QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed);
} else {
@@ -845,10 +803,8 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id,
server_connection_id, connection->version(), helper_.get(),
time_wait_list_manager_.get());
terminator.CloseConnection(
- fix_dispatcher_sent_error_code ? error : QUIC_HANDSHAKE_FAILED,
- fix_dispatcher_sent_error_code
- ? error_details
- : "Connection is closed by server before handshake confirmed",
+ QUIC_HANDSHAKE_FAILED,
+ "Connection is closed by server before handshake confirmed",
connection->version().HasIetfInvariantHeader(),
connection->GetActiveServerConnectionIds());
} else {
@@ -862,11 +818,8 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id,
: GOOGLE_QUIC_PACKET,
/*version_flag=*/true,
connection->version().HasLengthPrefixedConnectionIds(),
- connection->version(),
- fix_dispatcher_sent_error_code ? error : QUIC_HANDSHAKE_FAILED,
- fix_dispatcher_sent_error_code
- ? error_details
- : "Connection is closed by server before handshake confirmed",
+ connection->version(), QUIC_HANDSHAKE_FAILED,
+ "Connection is closed by server before handshake confirmed",
// Although it is our intention to send termination packets, the
// |action| argument is not used by this call to
// StatelesslyTerminateConnection().
@@ -898,18 +851,12 @@ void QuicDispatcher::StopAcceptingNewConnections() {
void QuicDispatcher::PerformActionOnActiveSessions(
std::function<void(QuicSession*)> operation) const {
- if (use_reference_counted_session_map_) {
- absl::flat_hash_set<QuicSession*> visited_session;
- visited_session.reserve(reference_counted_session_map_.size());
- for (auto const& kv : reference_counted_session_map_) {
- QuicSession* session = kv.second.get();
- if (visited_session.insert(session).second) {
- operation(session);
- }
- }
- } else {
- for (auto const& kv : session_map_) {
- operation(kv.second.get());
+ absl::flat_hash_set<QuicSession*> visited_session;
+ visited_session.reserve(reference_counted_session_map_.size());
+ for (auto const& kv : reference_counted_session_map_) {
+ QuicSession* session = kv.second.get();
+ if (visited_session.insert(session).second) {
+ operation(session);
}
}
}
@@ -917,7 +864,6 @@ void QuicDispatcher::PerformActionOnActiveSessions(
// Get a snapshot of all sessions.
std::vector<std::shared_ptr<QuicSession>> QuicDispatcher::GetSessionsSnapshot()
const {
- QUICHE_DCHECK(use_reference_counted_session_map_);
std::vector<std::shared_ptr<QuicSession>> snapshot;
snapshot.reserve(reference_counted_session_map_.size());
absl::flat_hash_set<QuicSession*> visited_session;
@@ -937,29 +883,16 @@ std::unique_ptr<QuicPerPacketContext> QuicDispatcher::GetPerPacketContext()
}
void QuicDispatcher::DeleteSessions() {
- if (use_reference_counted_session_map_) {
- if (!write_blocked_list_.empty()) {
- for (const auto& session : closed_ref_counted_session_list_) {
- if (write_blocked_list_.erase(session->connection()) != 0) {
- QUIC_BUG(quic_bug_12724_2)
- << "QuicConnection was in WriteBlockedList before destruction "
- << session->connection()->connection_id();
- }
+ if (!write_blocked_list_.empty()) {
+ for (const auto& session : closed_ref_counted_session_list_) {
+ if (write_blocked_list_.erase(session->connection()) != 0) {
+ QUIC_BUG(quic_bug_12724_2)
+ << "QuicConnection was in WriteBlockedList before destruction "
+ << session->connection()->connection_id();
}
}
- closed_ref_counted_session_list_.clear();
- } else {
- if (!write_blocked_list_.empty()) {
- for (const std::unique_ptr<QuicSession>& session : closed_session_list_) {
- if (write_blocked_list_.erase(session->connection()) != 0) {
- QUIC_BUG(quic_bug_12724_3)
- << "QuicConnection was in WriteBlockedList before destruction "
- << session->connection()->connection_id();
- }
- }
- }
- closed_session_list_.clear();
}
+ closed_ref_counted_session_list_.clear();
}
void QuicDispatcher::OnCanWrite() {
@@ -995,28 +928,15 @@ bool QuicDispatcher::HasPendingWrites() const {
}
void QuicDispatcher::Shutdown() {
- if (use_reference_counted_session_map_) {
- while (!reference_counted_session_map_.empty()) {
- QuicSession* session =
- reference_counted_session_map_.begin()->second.get();
- session->connection()->CloseConnection(
- QUIC_PEER_GOING_AWAY, "Server shutdown imminent",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- // Validate that the session removes itself from the session map on close.
- QUICHE_DCHECK(reference_counted_session_map_.empty() ||
- reference_counted_session_map_.begin()->second.get() !=
- session);
- }
- } else {
- while (!session_map_.empty()) {
- QuicSession* session = session_map_.begin()->second.get();
- session->connection()->CloseConnection(
- QUIC_PEER_GOING_AWAY, "Server shutdown imminent",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- // Validate that the session removes itself from the session map on close.
- QUICHE_DCHECK(session_map_.empty() ||
- session_map_.begin()->second.get() != session);
- }
+ while (!reference_counted_session_map_.empty()) {
+ QuicSession* session = reference_counted_session_map_.begin()->second.get();
+ session->connection()->CloseConnection(
+ QUIC_PEER_GOING_AWAY, "Server shutdown imminent",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ // Validate that the session removes itself from the session map on close.
+ QUICHE_DCHECK(reference_counted_session_map_.empty() ||
+ reference_counted_session_map_.begin()->second.get() !=
+ session);
}
DeleteSessions();
}
@@ -1025,72 +945,41 @@ void QuicDispatcher::OnConnectionClosed(QuicConnectionId server_connection_id,
QuicErrorCode error,
const std::string& error_details,
ConnectionCloseSource source) {
- if (use_reference_counted_session_map_) {
- auto it = reference_counted_session_map_.find(server_connection_id);
- if (it == reference_counted_session_map_.end()) {
- QUIC_BUG(quic_bug_10287_3)
- << "ConnectionId " << server_connection_id
- << " does not exist in the session map. Error: "
- << QuicErrorCodeToString(error);
- QUIC_BUG(quic_bug_10287_4) << QuicStackTrace();
- return;
- }
+ auto it = reference_counted_session_map_.find(server_connection_id);
+ if (it == reference_counted_session_map_.end()) {
+ QUIC_BUG(quic_bug_10287_3) << "ConnectionId " << server_connection_id
+ << " does not exist in the session map. Error: "
+ << QuicErrorCodeToString(error);
+ QUIC_BUG(quic_bug_10287_4) << QuicStackTrace();
+ return;
+ }
- QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR)
- << "Closing connection (" << server_connection_id
- << ") due to error: " << QuicErrorCodeToString(error)
- << ", with details: " << error_details;
-
- QuicConnection* connection = it->second->connection();
- if (ShouldDestroySessionAsynchronously()) {
- // Set up alarm to fire immediately to bring destruction of this session
- // out of current call stack.
- if (closed_ref_counted_session_list_.empty()) {
- delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(),
- QuicTime::Delta::Zero());
- }
- closed_ref_counted_session_list_.push_back(std::move(it->second));
+ QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR)
+ << "Closing connection (" << server_connection_id
+ << ") due to error: " << QuicErrorCodeToString(error)
+ << ", with details: " << error_details;
+
+ QuicConnection* connection = it->second->connection();
+ if (ShouldDestroySessionAsynchronously()) {
+ // Set up alarm to fire immediately to bring destruction of this session
+ // out of current call stack.
+ if (closed_ref_counted_session_list_.empty()) {
+ delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(),
+ QuicTime::Delta::Zero());
}
- CleanUpSession(it->first, connection, error, error_details, source);
- if (support_multiple_cid_per_connection_) {
- QUIC_RESTART_FLAG_COUNT_N(
- quic_dispatcher_support_multiple_cid_per_connection_v2, 1, 2);
- for (const QuicConnectionId& cid :
- connection->GetActiveServerConnectionIds()) {
- reference_counted_session_map_.erase(cid);
- }
- --num_sessions_in_session_map_;
- } else {
- reference_counted_session_map_.erase(it);
+ closed_ref_counted_session_list_.push_back(std::move(it->second));
+ }
+ CleanUpSession(it->first, connection, error, error_details, source);
+ if (support_multiple_cid_per_connection_) {
+ QUIC_RESTART_FLAG_COUNT_N(
+ quic_dispatcher_support_multiple_cid_per_connection_v2, 1, 2);
+ for (const QuicConnectionId& cid :
+ connection->GetActiveServerConnectionIds()) {
+ reference_counted_session_map_.erase(cid);
}
+ --num_sessions_in_session_map_;
} else {
- auto it = session_map_.find(server_connection_id);
- if (it == session_map_.end()) {
- QUIC_BUG(quic_bug_10287_5)
- << "ConnectionId " << server_connection_id
- << " does not exist in the session map. Error: "
- << QuicErrorCodeToString(error);
- QUIC_BUG(quic_bug_10287_6) << QuicStackTrace();
- return;
- }
-
- QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR)
- << "Closing connection (" << server_connection_id
- << ") due to error: " << QuicErrorCodeToString(error)
- << ", with details: " << error_details;
-
- QuicConnection* connection = it->second->connection();
- if (ShouldDestroySessionAsynchronously()) {
- // Set up alarm to fire immediately to bring destruction of this session
- // out of current call stack.
- if (closed_session_list_.empty()) {
- delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(),
- QuicTime::Delta::Zero());
- }
- closed_session_list_.push_back(std::move(it->second));
- }
- CleanUpSession(it->first, connection, error, error_details, source);
- session_map_.erase(it);
+ reference_counted_session_map_.erase(it);
}
}
@@ -1126,6 +1015,7 @@ void QuicDispatcher::OnNewConnectionIdSent(
<< server_connection_id << " new_connection_id: " << new_connection_id;
return;
}
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 5, 5);
auto insertion_result = reference_counted_session_map_.insert(
std::make_pair(new_connection_id, it->second));
QUICHE_DCHECK(insertion_result.second);
@@ -1250,28 +1140,18 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
}
QUIC_DLOG(INFO) << "Created new session for " << server_connection_id;
- if (use_reference_counted_session_map_) {
- auto insertion_result = reference_counted_session_map_.insert(
- std::make_pair(server_connection_id,
- std::shared_ptr<QuicSession>(std::move(session))));
- if (!insertion_result.second) {
- QUIC_BUG(quic_bug_12724_5)
- << "Tried to add a session to session_map with existing connection "
- "id: "
- << server_connection_id;
- } else if (support_multiple_cid_per_connection_) {
- ++num_sessions_in_session_map_;
- }
- DeliverPacketsToSession(packets, insertion_result.first->second.get());
- } else {
- auto insertion_result = session_map_.insert(
- std::make_pair(server_connection_id, std::move(session)));
- QUIC_BUG_IF(quic_bug_12724_6, !insertion_result.second)
+ auto insertion_result = reference_counted_session_map_.insert(
+ std::make_pair(server_connection_id,
+ std::shared_ptr<QuicSession>(std::move(session))));
+ if (!insertion_result.second) {
+ QUIC_BUG(quic_bug_12724_5)
<< "Tried to add a session to session_map with existing connection "
"id: "
<< server_connection_id;
- DeliverPacketsToSession(packets, insertion_result.first->second.get());
+ } else if (support_multiple_cid_per_connection_) {
+ ++num_sessions_in_session_map_;
}
+ DeliverPacketsToSession(packets, insertion_result.first->second.get());
}
}
@@ -1370,28 +1250,18 @@ void QuicDispatcher::ProcessChlo(const std::vector<std::string>& alpns,
<< packet_info->destination_connection_id;
QuicSession* session_ptr;
- if (use_reference_counted_session_map_) {
- auto insertion_result =
- reference_counted_session_map_.insert(std::make_pair(
- packet_info->destination_connection_id,
- std::shared_ptr<QuicSession>(std::move(session.release()))));
- if (!insertion_result.second) {
- QUIC_BUG(quic_bug_10287_9)
- << "Tried to add a session to session_map with existing "
- "connection id: "
- << packet_info->destination_connection_id;
- } else if (support_multiple_cid_per_connection_) {
- ++num_sessions_in_session_map_;
- }
- session_ptr = insertion_result.first->second.get();
- } else {
- auto insertion_result = session_map_.insert(std::make_pair(
- packet_info->destination_connection_id, std::move(session)));
- QUIC_BUG_IF(quic_bug_12724_8, !insertion_result.second)
- << "Tried to add a session to session_map with existing connection id: "
+ auto insertion_result = reference_counted_session_map_.insert(std::make_pair(
+ packet_info->destination_connection_id,
+ std::shared_ptr<QuicSession>(std::move(session.release()))));
+ if (!insertion_result.second) {
+ QUIC_BUG(quic_bug_10287_9)
+ << "Tried to add a session to session_map with existing "
+ "connection id: "
<< packet_info->destination_connection_id;
- session_ptr = insertion_result.first->second.get();
+ } else if (support_multiple_cid_per_connection_) {
+ ++num_sessions_in_session_map_;
}
+ session_ptr = insertion_result.first->second.get();
std::list<BufferedPacket> packets =
buffered_packets_.DeliverPackets(packet_info->destination_connection_id)
.buffered_packets;
@@ -1449,7 +1319,7 @@ bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) {
void QuicDispatcher::MaybeResetPacketsWithNoVersion(
const ReceivedPacketInfo& packet_info) {
QUICHE_DCHECK(!packet_info.version_flag);
- if (GetQuicReloadableFlag(quic_fix_stateless_reset) &&
+ if (GetQuicRestartFlag(quic_fix_stateless_reset2) &&
packet_info.form != GOOGLE_QUIC_PACKET) {
// Drop IETF packets smaller than the minimal stateless reset length.
if (packet_info.packet.length() <=
@@ -1481,9 +1351,7 @@ size_t QuicDispatcher::NumSessions() const {
if (support_multiple_cid_per_connection_) {
return num_sessions_in_session_map_;
}
- return use_reference_counted_session_map_
- ? reference_counted_session_map_.size()
- : session_map_.size();
+ return reference_counted_session_map_.size();
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h
index 81749543d4d..053f856da98 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h
@@ -166,10 +166,6 @@ class QUIC_NO_EXPORT QuicDispatcher
bool accept_new_connections() const { return accept_new_connections_; }
- bool use_reference_counted_session_map() const {
- return use_reference_counted_session_map_;
- }
-
bool support_multiple_cid_per_connection() const {
return support_multiple_cid_per_connection_;
}
@@ -457,10 +453,7 @@ class QUIC_NO_EXPORT QuicDispatcher
// destination connection ID length of all IETF long headers.
bool should_update_expected_server_connection_id_length_;
- const bool use_reference_counted_session_map_ =
- GetQuicRestartFlag(quic_use_reference_counted_sesssion_map);
const bool support_multiple_cid_per_connection_ =
- use_reference_counted_session_map_ &&
GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2) &&
GetQuicRestartFlag(
quic_dispatcher_support_multiple_cid_per_connection_v2);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
index 3df8a76965d..5a7a709f91b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
@@ -167,6 +167,7 @@ class TestDispatcher : public QuicDispatcher {
std::string custom_packet_context_;
+ using QuicDispatcher::MaybeDispatchPacket;
using QuicDispatcher::SetAllowShortInitialServerConnectionIds;
using QuicDispatcher::writer;
@@ -1101,6 +1102,31 @@ TEST_P(QuicDispatcherTestAllVersions,
ProcessFirstFlight(client_address, EmptyQuicConnectionId());
}
+TEST_P(QuicDispatcherTestAllVersions,
+ DropPacketWithKnownVersionAndInvalidInitialConnectionId) {
+ SetQuicReloadableFlag(quic_discard_packets_with_invalid_cid, true);
+ CreateTimeWaitListManager();
+
+ QuicSocketAddress server_address;
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+
+ // dispatcher_ should drop this packet with invalid connection ID.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ .Times(0);
+ absl::string_view cid_str = "123456789abcdefg123456789abcdefg";
+ QuicConnectionId invalid_connection_id(cid_str.data(), cid_str.length());
+ QuicReceivedPacket packet("packet", 6, QuicTime::Zero());
+ ReceivedPacketInfo packet_info(server_address, client_address, packet);
+ packet_info.version_flag = true;
+ packet_info.version = version_;
+ packet_info.destination_connection_id = invalid_connection_id;
+
+ ASSERT_TRUE(dispatcher_->MaybeDispatchPacket(packet_info));
+}
+
void QuicDispatcherTestBase::
TestVersionNegotiationForUnknownVersionInvalidShortInitialConnectionId(
const QuicConnectionId& server_connection_id,
@@ -1976,7 +2002,6 @@ class QuicDispatcherSupportMultipleConnectionIdPerConnectionTest
public:
QuicDispatcherSupportMultipleConnectionIdPerConnectionTest()
: QuicDispatcherTestBase(crypto_test_utils::ProofSourceForTesting()) {
- SetQuicRestartFlag(quic_use_reference_counted_sesssion_map, true);
SetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2, true);
SetQuicRestartFlag(quic_dispatcher_support_multiple_cid_per_connection_v2,
true);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
index 32816b869cf..9fa422f578c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
@@ -459,8 +459,12 @@ enum QuicErrorCode {
// Received multiple close offset.
QUIC_STREAM_MULTIPLE_OFFSET = 130,
- // Internal error codes for HTTP/3 errors.
+ // HTTP/3 errors.
+
+ // Frame payload larger than what HttpDecoder is willing to buffer.
QUIC_HTTP_FRAME_TOO_LARGE = 131,
+ // Malformed HTTP/3 frame, or PUSH_PROMISE or CANCEL_PUSH received (which is
+ // an error because MAX_PUSH_ID is never sent).
QUIC_HTTP_FRAME_ERROR = 132,
// A frame that is never allowed on a request stream is received.
QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM = 133,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h
index 910db544eff..df0df50f3fc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h
@@ -4,77 +4,135 @@
// This file is autogenerated by the QUICHE Copybara export script.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_abort_qpack_on_stream_reset, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_accept_empty_stream_frame_with_no_fin, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ack_delay_alarm_granularity, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_alps_include_scheme_in_origin, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_and_tls_allow_sni_without_dots, false)
+#ifdef QUIC_FLAG
+
+QUIC_FLAG(FLAGS_quic_restart_flag_dont_fetch_quic_private_keys_from_leto, false)
+
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_offload_pacing_to_usps2, false)
+// A testonly reloadable flag that will always default to false.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_false, false)
+// A testonly reloadable flag that will always default to true.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_true, true)
+// A testonly restart flag that will always default to false.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_false, false)
+// A testonly restart flag that will always default to true.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_true, true)
+// Fix QUIC BBRv2\'s bandwidth_lo modes to better approximate packet conservation.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fix_bw_lo_mode2, false)
+// If true, GFE will consider SNI values which do not contain dots (instead of throwing them away - see b/176998377).
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_and_tls_allow_sni_without_dots, true)
+// If true, QUIC BBRv2\'s PROBE_BW mode will not reduce cwnd below BDP+ack_height.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_avoid_too_low_probe_bw_cwnd, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fix_bw_lo_mode, false)
+// If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false)
+// If true, QuicBatchWriterBase will mark the writer as blocked when the write status is WRITE_STATUS_BLOCKED_DATA_BUFFERED.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_batch_writer_fix_write_blocked, true)
+// If true, QuicGsoBatchWriter will support release time if it is available and the process has the permission to do so.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_support_release_time_for_gso, false)
+// If true, TlsHandshaker::AdvanceHandshake will retry SSL_do_handshake when entered early data.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_retry_handshake_on_early_data, true)
+// If true, TlsServerHandshaker will install a packet flusher when async operation completes.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_packet_flusher_on_async_op_done, true)
+// If true, TlsServerHandshaker will use handshake hints(if present) to speed up handshakes.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_server_use_handshake_hints, true)
+// If true, abort async QPACK header decompression in QuicSpdyStream::Reset() and in QuicSpdyStream::OnStreamReset().
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_abort_qpack_on_stream_reset, true)
+// If true, ack frequency frame can be sent from server to client.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_can_send_ack_frequency, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_close_connection_with_too_many_outstanding_packets, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_support_multiple_cids_v2, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_count_bytes_on_alternative_path_seperately, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_crypto_postpone_cert_validate_for_server, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true)
+// If true, allow client to enable BBRv2 on server via connection option \'B2ON\'.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false)
+// If true, close read side but not write side in QuicSpdyStream::OnStreamReset().
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, true)
+// If true, default on PTO which unifies TLP + RTO loss recovery.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_on_pto, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr_v2, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_delay_initial_ack, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_server_blackhole_detection, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_draft_29, false)
+// If true, default-enable 5RTO blachole detection.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true)
+// If true, determine stateless reset packet length based on the received packet length.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_fix_stateless_reset2, false)
+// If true, disable QUIC version Q043.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q043, false)
+// If true, disable QUIC version Q046.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q046, false)
+// If true, disable QUIC version Q050.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q050, false)
+// If true, disable QUIC version h3-29.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_draft_29, false)
+// If true, disable QUIC version h3-T051.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_t051, false)
+// If true, disable blackhole detection on server side.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_server_blackhole_detection, false)
+// If true, discard INITIAL packet if the key has been dropped.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_discard_initial_packet_with_key_dropped, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_do_not_synthesize_source_cid_for_short_header, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_write_mid_packet_processing, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_alps_client, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_alps_server, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_token_based_address_validation, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_version_rfcv1, false)
+// If true, do not bundle 2nd ACK with connection close if there is an ACK queued.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_single_ack_in_packet2, false)
+// If true, do not count bytes sent/received on the alternative path into the bytes sent/received on the default path.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_count_bytes_on_alternative_path_seperately, true)
+// If true, do not send control frames before encryption is established.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_encrypted_control_frames, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_encrypted_goaway, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_dispatcher_sent_error_code, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_key_update_on_first_packet, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_stateless_reset, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_willing_and_able_to_write2, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_h3_datagram, false)
+// If true, do not send stream data when PTO fires.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_pto_half_rtt_data, true)
+// If true, do not write stream data and control frames in the middle of packet processing.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_write_mid_packet_processing, true)
+// If true, drop unsent PATH_RESPONSEs and rely on peer\'s retry.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_drop_unsent_path_response, true)
+// If true, enable QUIC version h3 (RFCv1).
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_version_rfcv1, false)
+// If true, enable server retransmittable on wire PING.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true)
+// If true, include stream information in idle timeout connection close detail.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, true)
+// If true, increase the size of stream sequencer buffer block container on demand.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false)
+// If true, pass the received PATH_RESPONSE payload to path validator to move forward the path validation.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_preempt_stream_data_with_handshake_packet, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_reject_unexpected_ietf_frame_types, true)
+// If true, quic connection sends/recieives NewConnectionId & RetireConnectionId frames.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_support_multiple_cids_v4, true)
+// If true, quic dispatcher discards packets with invalid server connection ID.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_discard_packets_with_invalid_cid, false)
+// If true, quic dispatcher supports one connection to use multiple connection IDs.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_dispatcher_support_multiple_cid_per_connection_v2, true)
+// If true, require handshake confirmation for QUIC connections, functionally disabling 0-rtt handshakes.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_require_handshake_confirmation, false)
+// If true, send PATH_RESPONSE upon receiving PATH_CHALLENGE regardless of perspective. --gfe2_reloadable_flag_quic_start_peer_migration_earlier has to be true before turn on this flag.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_path_response2, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_tls_crypto_error_code, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_single_ack_in_packet2, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_false, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_true, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_use_normalized_sni_for_cert_selectioon, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_use_per_handshaker_proof_source, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_retry_handshake_on_early_data, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, false)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unify_stop_sending, true)
+// If true, set burst token to 2 in cwnd bootstrapping experiment.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false)
+// If true, signal error in HttpDecoder upon receiving a PUSH_PROMISE or CANCEL_PUSH frame.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_error_on_http3_push, true)
+// If true, stop resetting ideal_next_packet_send_time_ in pacing sender.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false)
+// If true, time_wait_list can support multiple connection IDs.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_time_wait_list_support_multiple_cid_v2, true)
+// If true, treat old (pre-draft02) PRIORITY_UPDATE frame as unknown frame.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ignore_old_priority_update_frame, true)
+// If true, upon receiving path challenge, send path response and reverse path challenge in the same function.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_group_path_response_and_challenge_sending_closer, false)
+// If true, use BBRv2 as the default congestion controller. Takes precedence over --quic_default_to_bbr.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr_v2, false)
+// If true, use ScopedEncryptionLevelContext when sending data.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_encryption_level_context, true)
+// If true, use WriteOrBufferDataAtLevel to send crypto data. Existing WriteOrBufferData is used to send application data.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_write_or_buffer_data_at_level, false)
-QUIC_FLAG(FLAGS_quic_restart_flag_dont_fetch_quic_private_keys_from_leto, false)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_dispatcher_support_multiple_cid_per_connection_v2, true)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_offload_pacing_to_usps2, false)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_session_tickets_always_enabled, true)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_support_release_time_for_gso, false)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_false, false)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_true, true)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_time_wait_list_support_multiple_cid_v2, true)
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_use_reference_counted_sesssion_map, true)
+// If true, use new connection ID in connection migration.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_migration_use_new_cid_v2, false)
+// If true, use the connection ID and stateless reset token on default PathState.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_connection_id_on_default_path_v2, true)
+// If true, uses conservative cwnd gain and pacing gain when cwnd gets bootstrapped.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false)
+// If true, validate that peer owns the new address once the server detects peer migration or is probed from that address, and also apply anti-amplification limit while sending to that address.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3, false)
+// If ture, replace the incoming_connection_ids check with original_destination_connection_id check.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_deprecate_incoming_connection_ids, true)
+// When the STMP connection option is sent by the client, timestamps in the QUIC ACK frame are sent and processed.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false)
+// When true, QuicSpdySession supports draft-ietf-masque-h3-datagram.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_h3_datagram, false)
+// When true, defaults to BBR congestion control instead of Cubic.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
+// When true, makes the QUIC BBRv2 bw_lo modes more similar to standard BBRv2.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fix_bw_lo_mode, true)
+// When true, set the initial congestion control window from connection options in QuicSentPacketManager rather than TcpCubicSenderBytes.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, false)
+
+#endif
+
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
index c5de97be541..e186ce33ecb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
@@ -49,7 +49,7 @@
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_map_util.h"
#include "quic/platform/api/quic_stack_trace.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
@@ -435,10 +435,6 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
version_ = supported_versions_[0];
QUICHE_DCHECK(version_.IsKnown())
<< ParsedQuicVersionVectorToString(supported_versions_);
- if (do_not_synthesize_source_cid_for_short_header_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_do_not_synthesize_source_cid_for_short_header, 1, 3);
- }
}
QuicFramer::~QuicFramer() {}
@@ -1309,9 +1305,9 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket(
size_t received_packet_length,
StatelessResetToken stateless_reset_token) {
QUIC_DVLOG(1) << "Building IETF stateless reset packet.";
- if (GetQuicReloadableFlag(quic_fix_stateless_reset)) {
+ if (GetQuicRestartFlag(quic_fix_stateless_reset2)) {
if (received_packet_length <= GetMinStatelessResetPacketLength()) {
- QUIC_BUG(362045737_1)
+ QUICHE_DLOG(ERROR)
<< "Tried to build stateless reset packet with received packet "
"length "
<< received_packet_length;
@@ -1344,7 +1340,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket(
QUIC_BUG(362045737_3) << "Failed to write stateless reset token";
return nullptr;
}
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_stateless_reset);
+ QUIC_RESTART_FLAG_COUNT(quic_fix_stateless_reset2);
return std::make_unique<QuicEncryptedPacket>(buffer.release(), len,
/*owns_buffer=*/true);
}
@@ -2774,7 +2770,6 @@ bool QuicFramer::ProcessAndValidateIetfConnectionIdLength(
bool QuicFramer::ValidateReceivedConnectionIds(const QuicPacketHeader& header) {
bool skip_server_connection_id_validation =
- do_not_synthesize_source_cid_for_short_header_ &&
perspective_ == Perspective::IS_CLIENT &&
header.form == IETF_QUIC_SHORT_HEADER_PACKET;
if (!skip_server_connection_id_validation &&
@@ -2786,13 +2781,8 @@ bool QuicFramer::ValidateReceivedConnectionIds(const QuicPacketHeader& header) {
}
bool skip_client_connection_id_validation =
- do_not_synthesize_source_cid_for_short_header_ &&
perspective_ == Perspective::IS_SERVER &&
header.form == IETF_QUIC_SHORT_HEADER_PACKET;
- if (skip_client_connection_id_validation) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_do_not_synthesize_source_cid_for_short_header, 2, 3);
- }
if (!skip_client_connection_id_validation &&
version_.SupportsClientConnectionIds() &&
!QuicUtils::IsConnectionIdValidForVersion(
@@ -2829,15 +2819,6 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader,
header->destination_connection_id_included = CONNECTION_ID_PRESENT;
header->source_connection_id_included =
header->version_flag ? CONNECTION_ID_PRESENT : CONNECTION_ID_ABSENT;
- if (!do_not_synthesize_source_cid_for_short_header_ &&
- header->source_connection_id_included == CONNECTION_ID_ABSENT) {
- QUICHE_DCHECK(header->source_connection_id.IsEmpty());
- if (perspective_ == Perspective::IS_CLIENT) {
- header->source_connection_id = last_serialized_server_connection_id_;
- } else {
- header->source_connection_id = last_serialized_client_connection_id_;
- }
- }
if (!ValidateReceivedConnectionIds(*header)) {
return false;
@@ -2925,13 +2906,6 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader,
set_detailed_error("Client connection ID not supported in this version.");
return false;
}
- if (!do_not_synthesize_source_cid_for_short_header_) {
- if (perspective_ == Perspective::IS_CLIENT) {
- header->source_connection_id = last_serialized_server_connection_id_;
- } else {
- header->source_connection_id = last_serialized_client_connection_id_;
- }
- }
}
return ValidateReceivedConnectionIds(*header);
@@ -3232,20 +3206,14 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader,
set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
- if (reject_unexpected_ietf_frame_types_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_reject_unexpected_ietf_frame_types, 1,
- 2);
- if (!IsIetfFrameTypeExpectedForEncryptionLevel(frame_type,
- decrypted_level)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_reject_unexpected_ietf_frame_types, 2,
- 2);
- set_detailed_error(absl::StrCat(
- "IETF frame type ",
- QuicIetfFrameTypeString(static_cast<QuicIetfFrameType>(frame_type)),
- " is unexpected at encryption level ",
- EncryptionLevelToString(decrypted_level)));
- return RaiseError(IETF_QUIC_PROTOCOL_VIOLATION);
- }
+ if (!IsIetfFrameTypeExpectedForEncryptionLevel(frame_type,
+ decrypted_level)) {
+ set_detailed_error(absl::StrCat(
+ "IETF frame type ",
+ QuicIetfFrameTypeString(static_cast<QuicIetfFrameType>(frame_type)),
+ " is unexpected at encryption level ",
+ EncryptionLevelToString(decrypted_level)));
+ return RaiseError(IETF_QUIC_PROTOCOL_VIOLATION);
}
current_received_frame_type_ = frame_type;
@@ -4872,10 +4840,8 @@ bool QuicFramer::DecryptPayload(size_t udp_packet_length,
if ((current_key_phase_first_received_packet_number_.IsInitialized() &&
header.packet_number >
current_key_phase_first_received_packet_number_) ||
- (GetQuicReloadableFlag(quic_fix_key_update_on_first_packet) &&
- !current_key_phase_first_received_packet_number_.IsInitialized() &&
+ (!current_key_phase_first_received_packet_number_.IsInitialized() &&
!key_update_performed_)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_key_update_on_first_packet);
if (!next_decrypter_) {
next_decrypter_ =
visitor_->AdvanceKeysAndCreateCurrentOneRttDecrypter();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h
index e27c7f0727e..2920db351c4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h
@@ -634,6 +634,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
Perspective perspective() const { return perspective_; }
+ QuicStreamFrameDataProducer* data_producer() const { return data_producer_; }
+
void set_data_producer(QuicStreamFrameDataProducer* data_producer) {
data_producer_ = data_producer;
}
@@ -714,10 +716,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
drop_incoming_retry_packets_ = drop_incoming_retry_packets;
}
- bool do_not_synthesize_source_cid_for_short_header() const {
- return do_not_synthesize_source_cid_for_short_header_;
- }
-
private:
friend class test::QuicFramerPeer;
@@ -1174,14 +1172,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// Indicates whether received RETRY packets should be dropped.
bool drop_incoming_retry_packets_ = false;
- bool reject_unexpected_ietf_frame_types_ =
- GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types);
-
- // Indicates whether source connection ID should be synthesized when read
- // short header packet.
- const bool do_not_synthesize_source_cid_for_short_header_ =
- GetQuicReloadableFlag(quic_do_not_synthesize_source_cid_for_short_header);
-
// The length in bytes of the last packet number written to an IETF-framed
// packet.
size_t last_written_packet_number_length_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc
index 048a4b72ffb..63a1ad5ed4f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc
@@ -34,7 +34,6 @@
#include "quic/test_tools/quic_framer_peer.h"
#include "quic/test_tools/quic_test_utils.h"
#include "quic/test_tools/simple_data_producer.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/test_tools/quiche_test_utils.h"
using testing::_;
@@ -1479,9 +1478,6 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(FramerTestConnectionId(),
visitor_.header_->destination_connection_id);
- if (!framer_.do_not_synthesize_source_cid_for_short_header()) {
- EXPECT_EQ(TestConnectionId(0x33), visitor_.header_->source_connection_id);
- }
}
// In short header packets from client to server, the client connection ID
@@ -1515,9 +1511,6 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToServer) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(FramerTestConnectionId(),
visitor_.header_->destination_connection_id);
- if (!framer_.do_not_synthesize_source_cid_for_short_header()) {
- EXPECT_EQ(TestConnectionId(0x33), visitor_.header_->source_connection_id);
- }
}
TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
@@ -1567,9 +1560,6 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD));
ASSERT_TRUE(visitor_.header_.get());
- if (!framer_.do_not_synthesize_source_cid_for_short_header()) {
- EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->source_connection_id);
- }
EXPECT_FALSE(visitor_.header_->reset_flag);
EXPECT_FALSE(visitor_.header_->version_flag);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
@@ -9248,7 +9238,7 @@ TEST_P(QuicFramerTest, BuildPublicResetPacketWithEndpointId) {
}
TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
- if (GetQuicReloadableFlag(quic_fix_stateless_reset)) {
+ if (GetQuicRestartFlag(quic_fix_stateless_reset2)) {
// clang-format off
unsigned char packet[] = {
// 1st byte 01XX XXXX
@@ -9282,13 +9272,12 @@ TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
// Packets with length <= minimal stateless reset does not trigger stateless
// reset.
- EXPECT_QUIC_BUG(
- std::unique_ptr<QuicEncryptedPacket> data2(
- framer_.BuildIetfStatelessResetPacket(
- FramerTestConnectionId(),
- QuicFramer::GetMinStatelessResetPacketLength(),
- kTestStatelessResetToken)),
- "Tried to build stateless reset packet with received packet length");
+ std::unique_ptr<QuicEncryptedPacket> data2(
+ framer_.BuildIetfStatelessResetPacket(
+ FramerTestConnectionId(),
+ QuicFramer::GetMinStatelessResetPacketLength(),
+ kTestStatelessResetToken));
+ ASSERT_FALSE(data2);
// Do not send stateless reset >= minimal stateless reset + 1 + max
// connection ID length.
@@ -15230,7 +15219,6 @@ TEST_P(QuicFramerTest, KeyUpdateOnFirstReceivedPacket) {
// Key update is only used in QUIC+TLS.
return;
}
- SetQuicReloadableFlag(quic_fix_key_update_on_first_packet, true);
ASSERT_TRUE(framer_.version().KnowsWhichDecrypterToUse());
// Doesn't use SetDecrypterLevel since we want to use StrictTaggingDecrypter
// instead of TestDecrypter.
@@ -15262,8 +15250,7 @@ TEST_P(QuicFramerTest, KeyUpdateOnFirstReceivedPacket) {
}
TEST_P(QuicFramerTest, ErrorWhenUnexpectedFrameTypeEncountered) {
- if (!GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) ||
- !VersionHasIetfQuicFrames(framer_.transport_version()) ||
+ if (!VersionHasIetfQuicFrames(framer_.transport_version()) ||
!QuicVersionHasLongHeaderLengths(framer_.transport_version()) ||
!framer_.version().HasLongHeaderLengths()) {
return;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h b/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h
index ba27aa9d8f5..274c2e384df 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h
@@ -8,12 +8,12 @@
#include <algorithm>
#include "absl/types/optional.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_interval.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_logging.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -137,7 +137,7 @@ class QuicIntervalDequePeer;
// // cached_index -> 1
// // container -> {{2, [25, 30)}, {3, [35, 50)}}
-template <class T, class C = QUIC_NO_EXPORT QuicCircularDeque<T>>
+template <class T, class C = QUIC_NO_EXPORT quiche::QuicheCircularDeque<T>>
class QUIC_NO_EXPORT QuicIntervalDeque {
public:
class QUIC_NO_EXPORT Iterator {
@@ -363,7 +363,7 @@ void QuicIntervalDeque<T, C>::PushBackUniversal(U&& item) {
// Adding an empty interval is a bug.
if (interval.Empty()) {
QUIC_BUG(quic_bug_10862_3)
- << "Trying to save empty interval to QuicCircularDeque.";
+ << "Trying to save empty interval to quiche::QuicheCircularDeque.";
return;
}
container_.push_back(std::forward<U>(item));
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc
index 27dbb9b48a8..11d2293bee5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc
@@ -7,7 +7,6 @@
#include "quic/core/crypto/crypto_protocol.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_bug_tracker.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc
index 1d855f2f55d..2f74d3ac7e7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc
@@ -9,7 +9,6 @@
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace test {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h
index 14c26dc8d73..5bbd875180b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h
@@ -148,7 +148,7 @@ struct QUIC_EXPORT_PRIVATE BufferedWrite {
// multiple packets at once via ::sendmmsg.
//
// Example:
-// QuicCircularDeque<BufferedWrite> buffered_writes;
+// quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
// ... (Populate buffered_writes) ...
//
// QuicMMsgHdr mhdr(
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc
index 84259583063..588c2be8480 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc
@@ -12,9 +12,9 @@
#include <string>
-#include "quic/core/quic_circular_deque.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_mock_syscall_wrapper.h"
+#include "common/quiche_circular_deque.h"
using testing::_;
using testing::InSequence;
@@ -28,8 +28,8 @@ class QuicLinuxSocketUtilsTest : public QuicTest {
protected:
WriteResult TestWriteMultiplePackets(
int fd,
- const QuicCircularDeque<BufferedWrite>::const_iterator& first,
- const QuicCircularDeque<BufferedWrite>::const_iterator& last,
+ const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator& first,
+ const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator& last,
int* num_packets_sent) {
QuicMMsgHdr mhdr(
first, last, kCmsgSpaceForIp,
@@ -171,7 +171,7 @@ TEST_F(QuicLinuxSocketUtilsTest, QuicMsgHdr) {
}
TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) {
- QuicCircularDeque<BufferedWrite> buffered_writes;
+ quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
char packet_buf1[1024];
char packet_buf2[512];
buffered_writes.emplace_back(
@@ -205,7 +205,7 @@ TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) {
TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) {
int num_packets_sent;
- QuicCircularDeque<BufferedWrite> buffered_writes;
+ quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)).Times(0);
@@ -216,7 +216,7 @@ TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) {
TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) {
int num_packets_sent;
- QuicCircularDeque<BufferedWrite> buffered_writes;
+ quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(),
QuicSocketAddress(QuicIpAddress::Any4(), 0));
@@ -235,7 +235,7 @@ TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) {
TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) {
int num_packets_sent;
- QuicCircularDeque<BufferedWrite> buffered_writes;
+ quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(),
QuicSocketAddress(QuicIpAddress::Any4(), 0));
@@ -254,7 +254,7 @@ TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) {
TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteSuccess) {
int num_packets_sent;
- QuicCircularDeque<BufferedWrite> buffered_writes;
+ quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
const int kNumBufferedWrites = 10;
static_assert(kNumBufferedWrites < 256, "Must be less than 256");
std::vector<std::string> buffer_holder;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc
index 42aebe5ce4b..cbca89dae55 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc
@@ -15,10 +15,12 @@
#include "absl/base/optimization.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
#include "quic/core/crypto/crypto_protocol.h"
#include "quic/core/frames/quic_frame.h"
#include "quic/core/frames/quic_path_challenge_frame.h"
#include "quic/core/frames/quic_stream_frame.h"
+#include "quic/core/quic_chaos_protector.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_constants.h"
#include "quic/core/quic_data_writer.h"
@@ -32,7 +34,6 @@
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_server_stats.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace {
@@ -133,7 +134,8 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
flusher_attached_(false),
fully_pad_crypto_handshake_packets_(true),
latched_hard_max_packet_length_(0),
- max_datagram_frame_size_(0) {
+ max_datagram_frame_size_(0),
+ chaos_protection_enabled_(false) {
SetMaxPacketLength(kDefaultMaxPacketSize);
if (!framer_->version().UsesTls()) {
// QUIC+TLS negotiates the maximum datagram frame size via the
@@ -159,21 +161,21 @@ bool QuicPacketCreator::CanSetMaxPacketLength() const {
}
void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
- QUICHE_DCHECK(CanSetMaxPacketLength());
+ QUICHE_DCHECK(CanSetMaxPacketLength()) << ENDPOINT;
// Avoid recomputing |max_plaintext_size_| if the length does not actually
// change.
if (length == max_packet_length_) {
return;
}
- QUIC_DVLOG(1) << "Updating packet creator max packet length from "
+ QUIC_DVLOG(1) << ENDPOINT << "Updating packet creator max packet length from "
<< max_packet_length_ << " to " << length;
max_packet_length_ = length;
max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
QUIC_BUG_IF(quic_bug_12398_2, max_plaintext_size_ - PacketHeaderSize() <
MinPlaintextPacketSize(framer_->version()))
- << "Attempted to set max packet length too small";
+ << ENDPOINT << "Attempted to set max packet length too small";
}
void QuicPacketCreator::SetMaxDatagramFrameSize(
@@ -192,7 +194,7 @@ void QuicPacketCreator::SetMaxDatagramFrameSize(
}
void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
- QUICHE_DCHECK(CanSetMaxPacketLength());
+ QUICHE_DCHECK(CanSetMaxPacketLength()) << ENDPOINT;
if (length > max_packet_length_) {
QUIC_BUG(quic_bug_10752_2)
<< ENDPOINT
@@ -204,11 +206,12 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) {
// Please note: this would not guarantee to fit next packet if the size of
// packet header increases (e.g., encryption level changes).
- QUIC_DLOG(INFO) << length << " is too small to fit packet header";
+ QUIC_DLOG(INFO) << ENDPOINT << length
+ << " is too small to fit packet header";
RemoveSoftMaxPacketLength();
return;
}
- QUIC_DVLOG(1) << "Setting soft max packet length to: " << length;
+ QUIC_DVLOG(1) << ENDPOINT << "Setting soft max packet length to: " << length;
latched_hard_max_packet_length_ = max_packet_length_;
max_packet_length_ = length;
max_plaintext_size_ = framer_->GetMaxPlaintextSize(length);
@@ -218,18 +221,18 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
// A packet that is already open might send kQuicVersionSize bytes less than the
// maximum packet size if we stop sending version before it is serialized.
void QuicPacketCreator::StopSendingVersion() {
- QUICHE_DCHECK(send_version_in_packet_);
- QUICHE_DCHECK(!version().HasIetfInvariantHeader());
+ QUICHE_DCHECK(send_version_in_packet_) << ENDPOINT;
+ QUICHE_DCHECK(!version().HasIetfInvariantHeader()) << ENDPOINT;
send_version_in_packet_ = false;
if (packet_size_ > 0) {
- QUICHE_DCHECK_LT(kQuicVersionSize, packet_size_);
+ QUICHE_DCHECK_LT(kQuicVersionSize, packet_size_) << ENDPOINT;
packet_size_ -= kQuicVersionSize;
}
}
void QuicPacketCreator::SetDiversificationNonce(
const DiversificationNonce& nonce) {
- QUICHE_DCHECK(!have_diversification_nonce_);
+ QUICHE_DCHECK(!have_diversification_nonce_) << ENDPOINT;
have_diversification_nonce_ = true;
diversification_nonce_ = nonce;
}
@@ -240,14 +243,16 @@ void QuicPacketCreator::UpdatePacketNumberLength(
if (!queued_frames_.empty()) {
// Don't change creator state if there are frames queued.
QUIC_BUG(quic_bug_10752_3)
- << "Called UpdatePacketNumberLength with " << queued_frames_.size()
+ << ENDPOINT << "Called UpdatePacketNumberLength with "
+ << queued_frames_.size()
<< " queued_frames. First frame type:" << queued_frames_.front().type
<< " last frame type:" << queued_frames_.back().type;
return;
}
const QuicPacketNumber next_packet_number = NextSendingPacketNumber();
- QUICHE_DCHECK_LE(least_packet_awaited_by_peer, next_packet_number);
+ QUICHE_DCHECK_LE(least_packet_awaited_by_peer, next_packet_number)
+ << ENDPOINT;
const uint64_t current_delta =
next_packet_number - least_packet_awaited_by_peer;
const uint64_t delta = std::max(current_delta, max_packets_in_flight);
@@ -273,7 +278,8 @@ void QuicPacketCreator::SkipNPacketNumbers(
if (!queued_frames_.empty()) {
// Don't change creator state if there are frames queued.
QUIC_BUG(quic_bug_10752_4)
- << "Called SkipNPacketNumbers with " << queued_frames_.size()
+ << ENDPOINT << "Called SkipNPacketNumbers with "
+ << queued_frames_.size()
<< " queued_frames. First frame type:" << queued_frames_.front().type
<< " last frame type:" << queued_frames_.back().type;
return;
@@ -281,7 +287,7 @@ void QuicPacketCreator::SkipNPacketNumbers(
if (packet_.packet_number > packet_.packet_number + count) {
// Skipping count packet numbers causes packet number wrapping around,
// reject it.
- QUIC_LOG(WARNING) << "Skipping " << count
+ QUIC_LOG(WARNING) << ENDPOINT << "Skipping " << count
<< " packet numbers causes packet number wrapping "
"around, least_packet_awaited_by_peer: "
<< least_packet_awaited_by_peer
@@ -300,7 +306,7 @@ bool QuicPacketCreator::ConsumeCryptoDataToFillCurrentPacket(
bool needs_full_padding,
TransmissionType transmission_type,
QuicFrame* frame) {
- QUIC_DVLOG(2) << "ConsumeCryptoDataToFillCurrentPacket " << level
+ QUIC_DVLOG(2) << ENDPOINT << "ConsumeCryptoDataToFillCurrentPacket " << level
<< " write_length " << write_length << " offset " << offset
<< (needs_full_padding ? " needs_full_padding" : "") << " "
<< transmission_type;
@@ -338,7 +344,7 @@ bool QuicPacketCreator::ConsumeDataToFillCurrentPacket(
const std::string error_details =
"Client hello won't fit in a single packet.";
QUIC_BUG(quic_bug_10752_5)
- << error_details << " Constructed stream frame length: "
+ << ENDPOINT << error_details << " Constructed stream frame length: "
<< frame->stream_frame.data_length << " CHLO length: " << data_size;
delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details);
return false;
@@ -422,16 +428,17 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
GetSourceConnectionIdLength(), kIncludeVersion,
IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER,
GetRetryTokenLengthLength(), GetLengthLength(), offset) ||
- latched_hard_max_packet_length_ > 0);
+ latched_hard_max_packet_length_ > 0)
+ << ENDPOINT;
QUIC_BUG_IF(quic_bug_12398_3, !HasRoomForStreamFrame(id, offset, data_size))
- << "No room for Stream frame, BytesFree: " << BytesFree()
+ << ENDPOINT << "No room for Stream frame, BytesFree: " << BytesFree()
<< " MinStreamFrameSize: "
<< QuicFramer::GetMinStreamFrameSize(framer_->transport_version(), id,
offset, true, data_size);
QUIC_BUG_IF(quic_bug_12398_4, data_size == 0 && !fin)
- << "Creating a stream frame for stream ID:" << id
+ << ENDPOINT << "Creating a stream frame for stream ID:" << id
<< " with no data or fin.";
size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
framer_->transport_version(), id, offset,
@@ -472,7 +479,7 @@ void QuicPacketCreator::FlushCurrentPacket() {
external_buffer.release_buffer = nullptr;
}
- QUICHE_DCHECK_EQ(nullptr, packet_.encrypted_buffer);
+ QUICHE_DCHECK_EQ(nullptr, packet_.encrypted_buffer) << ENDPOINT;
if (!SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize)) {
return;
}
@@ -480,7 +487,8 @@ void QuicPacketCreator::FlushCurrentPacket() {
}
void QuicPacketCreator::OnSerializedPacket() {
- QUIC_BUG_IF(quic_bug_12398_5, packet_.encrypted_buffer == nullptr);
+ QUIC_BUG_IF(quic_bug_12398_5, packet_.encrypted_buffer == nullptr)
+ << ENDPOINT;
SerializedPacket packet(std::move(packet_));
ClearPacket();
@@ -499,10 +507,10 @@ void QuicPacketCreator::ClearPacket() {
packet_.has_message = false;
packet_.fate = SEND_TO_WRITER;
QUIC_BUG_IF(quic_bug_12398_6, packet_.release_encrypted_buffer != nullptr)
- << "packet_.release_encrypted_buffer should be empty";
+ << ENDPOINT << "packet_.release_encrypted_buffer should be empty";
packet_.release_encrypted_buffer = nullptr;
- QUICHE_DCHECK(packet_.retransmittable_frames.empty());
- QUICHE_DCHECK(packet_.nonretransmittable_frames.empty());
+ QUICHE_DCHECK(packet_.retransmittable_frames.empty()) << ENDPOINT;
+ QUICHE_DCHECK(packet_.nonretransmittable_frames.empty()) << ENDPOINT;
packet_.largest_acked.Clear();
needs_full_padding_ = false;
}
@@ -515,6 +523,7 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket(
QUIC_BUG_IF(quic_bug_12398_7, packet.encryption_level != ENCRYPTION_INITIAL);
QUIC_BUG_IF(quic_bug_12398_8, packet.nonretransmittable_frames.empty() &&
packet.retransmittable_frames.empty())
+ << ENDPOINT
<< "Attempt to serialize empty ENCRYPTION_INITIAL packet in coalesced "
"packet";
ScopedPacketContextSwitcher switcher(
@@ -523,13 +532,15 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket(
packet.packet_number_length, packet.encryption_level, &packet_);
for (const QuicFrame& frame : packet.nonretransmittable_frames) {
if (!AddFrame(frame, packet.transmission_type)) {
- QUIC_BUG(quic_bug_10752_6) << "Failed to serialize frame: " << frame;
+ QUIC_BUG(quic_bug_10752_6)
+ << ENDPOINT << "Failed to serialize frame: " << frame;
return 0;
}
}
for (const QuicFrame& frame : packet.retransmittable_frames) {
if (!AddFrame(frame, packet.transmission_type)) {
- QUIC_BUG(quic_bug_10752_7) << "Failed to serialize frame: " << frame;
+ QUIC_BUG(quic_bug_10752_7)
+ << ENDPOINT << "Failed to serialize frame: " << frame;
return 0;
}
}
@@ -539,7 +550,7 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket(
if (!AddFrame(QuicFrame(QuicPaddingFrame(padding_size)),
packet.transmission_type)) {
QUIC_BUG(quic_bug_10752_8)
- << "Failed to add padding of size " << padding_size
+ << ENDPOINT << "Failed to add padding of size " << padding_size
<< " when serializing ENCRYPTION_INITIAL "
"packet in coalesced packet";
return 0;
@@ -566,8 +577,9 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
TransmissionType transmission_type,
size_t* num_bytes_consumed) {
// TODO(b/167222597): consider using ScopedSerializationFailureHandler.
- QUICHE_DCHECK(queued_frames_.empty());
- QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
+ QUICHE_DCHECK(queued_frames_.empty()) << ENDPOINT;
+ QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id))
+ << ENDPOINT;
// Write out the packet header
QuicPacketHeader header;
FillPacketHeader(&header);
@@ -590,13 +602,13 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
QuicDataWriter writer(kMaxOutgoingPacketSize, encrypted_buffer);
size_t length_field_offset = 0;
if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) {
- QUIC_BUG(quic_bug_10752_9) << "AppendPacketHeader failed";
+ QUIC_BUG(quic_bug_10752_9) << ENDPOINT << "AppendPacketHeader failed";
return;
}
// Create a Stream frame with the remaining space.
QUIC_BUG_IF(quic_bug_12398_9, iov_offset == write_length && !fin)
- << "Creating a stream frame with no data or fin.";
+ << ENDPOINT << "Creating a stream frame with no data or fin.";
const size_t remaining_data_size = write_length - iov_offset;
size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
framer_->transport_version(), id, stream_offset,
@@ -631,18 +643,18 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
// into one method that takes a QuicStreamFrame, if warranted.
bool omit_frame_length = !needs_padding;
if (!framer_->AppendTypeByte(QuicFrame(frame), omit_frame_length, &writer)) {
- QUIC_BUG(quic_bug_10752_10) << "AppendTypeByte failed";
+ QUIC_BUG(quic_bug_10752_10) << ENDPOINT << "AppendTypeByte failed";
return;
}
if (!framer_->AppendStreamFrame(frame, omit_frame_length, &writer)) {
- QUIC_BUG(quic_bug_10752_11) << "AppendStreamFrame failed";
+ QUIC_BUG(quic_bug_10752_11) << ENDPOINT << "AppendStreamFrame failed";
return;
}
if (needs_padding &&
plaintext_bytes_written < MinPlaintextPacketSize(framer_->version()) &&
!writer.WritePaddingBytes(MinPlaintextPacketSize(framer_->version()) -
plaintext_bytes_written)) {
- QUIC_BUG(quic_bug_10752_12) << "Unable to add padding bytes";
+ QUIC_BUG(quic_bug_10752_12) << ENDPOINT << "Unable to add padding bytes";
return;
}
@@ -655,14 +667,15 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
QUICHE_DCHECK(packet_.encryption_level == ENCRYPTION_FORWARD_SECURE ||
packet_.encryption_level == ENCRYPTION_ZERO_RTT)
- << packet_.encryption_level;
+ << ENDPOINT << packet_.encryption_level;
size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header),
writer.length(), kMaxOutgoingPacketSize, encrypted_buffer);
if (encrypted_length == 0) {
QUIC_BUG(quic_bug_10752_13)
- << "Failed to encrypt packet number " << header.packet_number;
+ << ENDPOINT << "Failed to encrypt packet number "
+ << header.packet_number;
return;
}
// TODO(ianswett): Optimize the storage so RetransmitableFrames can be
@@ -724,7 +737,6 @@ size_t QuicPacketCreator::ExpansionOnNewFrameWithLastFrame(
}
size_t QuicPacketCreator::BytesFree() const {
- QUICHE_DCHECK_GE(max_plaintext_size_, PacketSize());
return max_plaintext_size_ -
std::min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame());
}
@@ -743,22 +755,51 @@ bool QuicPacketCreator::AddPaddedSavedFrame(
return false;
}
+absl::optional<size_t>
+QuicPacketCreator::MaybeBuildDataPacketWithChaosProtection(
+ const QuicPacketHeader& header,
+ char* buffer) {
+ if (!chaos_protection_enabled_ ||
+ packet_.encryption_level != ENCRYPTION_INITIAL ||
+ !framer_->version().UsesCryptoFrames() || queued_frames_.size() != 2u ||
+ queued_frames_[0].type != CRYPTO_FRAME ||
+ queued_frames_[1].type != PADDING_FRAME ||
+ // Do not perform chaos protection if we do not have a known number of
+ // padding bytes to work with.
+ queued_frames_[1].padding_frame.num_padding_bytes <= 0 ||
+ // Chaos protection relies on the framer using a crypto data producer,
+ // which is always the case in practice.
+ framer_->data_producer() == nullptr) {
+ return absl::nullopt;
+ }
+ const QuicCryptoFrame& crypto_frame = *queued_frames_[0].crypto_frame;
+ if (packet_.encryption_level != crypto_frame.level) {
+ QUIC_BUG(chaos frame level)
+ << ENDPOINT << packet_.encryption_level << " != " << crypto_frame.level;
+ return absl::nullopt;
+ }
+ QuicChaosProtector chaos_protector(
+ crypto_frame, queued_frames_[1].padding_frame.num_padding_bytes,
+ packet_size_, framer_, random_);
+ return chaos_protector.BuildDataPacket(header, buffer);
+}
+
bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
size_t encrypted_buffer_len) {
if (packet_.encrypted_buffer != nullptr) {
const std::string error_details =
"Packet's encrypted buffer is not empty before serialization";
- QUIC_BUG(quic_bug_10752_14) << error_details;
+ QUIC_BUG(quic_bug_10752_14) << ENDPOINT << error_details;
delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
error_details);
return false;
}
ScopedSerializationFailureHandler handler(this);
- QUICHE_DCHECK_LT(0u, encrypted_buffer_len);
+ QUICHE_DCHECK_LT(0u, encrypted_buffer_len) << ENDPOINT;
QUIC_BUG_IF(quic_bug_12398_10,
queued_frames_.empty() && pending_padding_bytes_ == 0)
- << "Attempt to serialize empty packet";
+ << ENDPOINT << "Attempt to serialize empty packet";
QuicPacketHeader header;
// FillPacketHeader increments packet_number_.
FillPacketHeader(&header);
@@ -789,15 +830,25 @@ bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
return false;
}
- QUICHE_DCHECK_GE(max_plaintext_size_, packet_size_);
+ QUICHE_DCHECK_GE(max_plaintext_size_, packet_size_) << ENDPOINT;
// Use the packet_size_ instead of the buffer size to ensure smaller
// packet sizes are properly used.
- size_t length =
- framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer.buffer,
- packet_size_, packet_.encryption_level);
+
+ size_t length;
+ absl::optional<size_t> length_with_chaos_protection =
+ MaybeBuildDataPacketWithChaosProtection(header, encrypted_buffer.buffer);
+ if (length_with_chaos_protection.has_value()) {
+ length = length_with_chaos_protection.value();
+ } else {
+ length = framer_->BuildDataPacket(header, queued_frames_,
+ encrypted_buffer.buffer, packet_size_,
+ packet_.encryption_level);
+ }
+
if (length == 0) {
QUIC_BUG(quic_bug_10752_16)
- << "Failed to serialize " << QuicFramesToString(queued_frames_)
+ << ENDPOINT << "Failed to serialize "
+ << QuicFramesToString(queued_frames_)
<< " at encryption_level: " << packet_.encryption_level
<< ", needs_full_padding_: " << needs_full_padding_
<< ", pending_padding_bytes_: " << pending_padding_bytes_
@@ -818,7 +869,7 @@ bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
// Because of possible truncation, we can't be confident that our
// packet size calculation worked correctly.
if (!possibly_truncated_by_length) {
- QUICHE_DCHECK_EQ(packet_size_, length);
+ QUICHE_DCHECK_EQ(packet_size_, length) << ENDPOINT;
}
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
@@ -826,7 +877,8 @@ bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
encrypted_buffer_len, encrypted_buffer.buffer);
if (encrypted_length == 0) {
QUIC_BUG(quic_bug_10752_17)
- << "Failed to encrypt packet number " << packet_.packet_number;
+ << ENDPOINT << "Failed to encrypt packet number "
+ << packet_.packet_number;
return false;
}
@@ -843,6 +895,7 @@ std::unique_ptr<SerializedPacket>
QuicPacketCreator::SerializeConnectivityProbingPacket() {
QUIC_BUG_IF(quic_bug_12398_11,
VersionHasIetfQuicFrames(framer_->transport_version()))
+ << ENDPOINT
<< "Must not be version 99 to serialize padded ping connectivity probe";
RemoveSoftMaxPacketLength();
QuicPacketHeader header;
@@ -855,14 +908,15 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() {
std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
size_t length = BuildConnectivityProbingPacket(
header, buffer.get(), max_plaintext_size_, packet_.encryption_level);
- QUICHE_DCHECK(length);
+ QUICHE_DCHECK(length) << ENDPOINT;
- QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE);
+ QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE)
+ << ENDPOINT;
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
kMaxOutgoingPacketSize, buffer.get());
- QUICHE_DCHECK(encrypted_length);
+ QUICHE_DCHECK(encrypted_length) << ENDPOINT;
std::unique_ptr<SerializedPacket> serialize_packet(new SerializedPacket(
header.packet_number, header.packet_number_length, buffer.release(),
@@ -882,6 +936,7 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
const QuicPathFrameBuffer& payload) {
QUIC_BUG_IF(quic_bug_12398_12,
!VersionHasIetfQuicFrames(framer_->transport_version()))
+ << ENDPOINT
<< "Must be version 99 to serialize path challenge connectivity probe, "
"is version "
<< framer_->transport_version();
@@ -896,14 +951,15 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
size_t length =
BuildPaddedPathChallengePacket(header, buffer.get(), max_plaintext_size_,
payload, packet_.encryption_level);
- QUICHE_DCHECK(length);
+ QUICHE_DCHECK(length) << ENDPOINT;
- QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE);
+ QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE)
+ << ENDPOINT;
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
kMaxOutgoingPacketSize, buffer.get());
- QUICHE_DCHECK(encrypted_length);
+ QUICHE_DCHECK(encrypted_length) << ENDPOINT;
std::unique_ptr<SerializedPacket> serialize_packet(
new SerializedPacket(header.packet_number, header.packet_number_length,
@@ -921,10 +977,11 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
std::unique_ptr<SerializedPacket>
QuicPacketCreator::SerializePathResponseConnectivityProbingPacket(
- const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
+ const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded) {
QUIC_BUG_IF(quic_bug_12398_13,
!VersionHasIetfQuicFrames(framer_->transport_version()))
+ << ENDPOINT
<< "Must be version 99 to serialize path response connectivity probe, is "
"version "
<< framer_->transport_version();
@@ -939,14 +996,15 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket(
size_t length =
BuildPathResponsePacket(header, buffer.get(), max_plaintext_size_,
payloads, is_padded, packet_.encryption_level);
- QUICHE_DCHECK(length);
+ QUICHE_DCHECK(length) << ENDPOINT;
- QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE);
+ QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE)
+ << ENDPOINT;
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
kMaxOutgoingPacketSize, buffer.get());
- QUICHE_DCHECK(encrypted_length);
+ QUICHE_DCHECK(encrypted_length) << ENDPOINT;
std::unique_ptr<SerializedPacket> serialize_packet(
new SerializedPacket(header.packet_number, header.packet_number_length,
@@ -968,7 +1026,8 @@ size_t QuicPacketCreator::BuildPaddedPathChallengePacket(
size_t packet_length,
const QuicPathFrameBuffer& payload,
EncryptionLevel level) {
- QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version()));
+ QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version()))
+ << ENDPOINT;
QuicFrames frames;
// Write a PATH_CHALLENGE frame, which has a random 8-byte payload
@@ -991,15 +1050,17 @@ size_t QuicPacketCreator::BuildPathResponsePacket(
const QuicPacketHeader& header,
char* buffer,
size_t packet_length,
- const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
+ const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded,
EncryptionLevel level) {
if (payloads.empty()) {
QUIC_BUG(quic_bug_12398_14)
+ << ENDPOINT
<< "Attempt to generate connectivity response with no request payloads";
return 0;
}
- QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version()));
+ QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version()))
+ << ENDPOINT;
std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames;
for (const QuicPathFrameBuffer& payload : payloads) {
@@ -1052,12 +1113,12 @@ size_t QuicPacketCreator::SerializeCoalescedPacket(
size_t buffer_len) {
if (HasPendingFrames()) {
QUIC_BUG(quic_bug_10752_18)
- << "Try to serialize coalesced packet with pending frames";
+ << ENDPOINT << "Try to serialize coalesced packet with pending frames";
return 0;
}
RemoveSoftMaxPacketLength();
QUIC_BUG_IF(quic_bug_12398_15, coalesced.length() == 0)
- << "Attempt to serialize empty coalesced packet";
+ << ENDPOINT << "Attempt to serialize empty coalesced packet";
size_t packet_length = 0;
if (coalesced.initial_packet() != nullptr) {
// Padding coalesced packet containing initial packet to full.
@@ -1073,6 +1134,7 @@ size_t QuicPacketCreator::SerializeCoalescedPacket(
*coalesced.initial_packet(), padding_size, buffer, buffer_len);
if (initial_length == 0) {
QUIC_BUG(quic_bug_10752_19)
+ << ENDPOINT
<< "Failed to reserialize ENCRYPTION_INITIAL packet in "
"coalesced packet";
return 0;
@@ -1141,7 +1203,8 @@ QuicConnectionIdIncluded QuicPacketCreator::GetSourceConnectionIdIncluded()
QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength()
const {
QUICHE_DCHECK(QuicUtils::IsConnectionIdValidForVersion(server_connection_id_,
- transport_version()));
+ transport_version()))
+ << ENDPOINT;
return GetDestinationConnectionIdIncluded() == CONNECTION_ID_PRESENT
? static_cast<QuicConnectionIdLength>(
GetDestinationConnectionId().length())
@@ -1150,7 +1213,8 @@ QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength()
QuicConnectionIdLength QuicPacketCreator::GetSourceConnectionIdLength() const {
QUICHE_DCHECK(QuicUtils::IsConnectionIdValidForVersion(server_connection_id_,
- transport_version()));
+ transport_version()))
+ << ENDPOINT;
return GetSourceConnectionIdIncluded() == CONNECTION_ID_PRESENT
? static_cast<QuicConnectionIdLength>(
GetSourceConnectionId().length())
@@ -1201,8 +1265,10 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame(
QUIC_BUG_IF(quic_bug_12398_16, IsControlFrame(frame.type) &&
!GetControlFrameId(frame) &&
frame.type != PING_FRAME)
+ << ENDPOINT
<< "Adding a control frame with no control frame id: " << frame;
- QUICHE_DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) << frame;
+ QUICHE_DCHECK(QuicUtils::IsRetransmittableFrame(frame.type))
+ << ENDPOINT << frame;
MaybeBundleAckOpportunistically();
if (HasPendingFrames()) {
if (AddFrame(frame, next_transmission_type_)) {
@@ -1210,7 +1276,7 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame(
return true;
}
}
- QUICHE_DCHECK(!HasPendingFrames());
+ QUICHE_DCHECK(!HasPendingFrames()) << ENDPOINT;
if (frame.type != PING_FRAME && frame.type != CONNECTION_CLOSE_FRAME &&
!delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
@@ -1219,7 +1285,7 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame(
}
const bool success = AddFrame(frame, next_transmission_type_);
QUIC_BUG_IF(quic_bug_10752_20, !success)
- << "Failed to add frame:" << frame
+ << ENDPOINT << "Failed to add frame:" << frame
<< " transmission_type:" << next_transmission_type_;
return success;
}
@@ -1229,13 +1295,14 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id,
QuicStreamOffset offset,
StreamSendingState state) {
QUIC_BUG_IF(quic_bug_10752_21, !flusher_attached_)
+ << ENDPOINT
<< "Packet flusher is not attached when "
"generator tries to write stream data.";
bool has_handshake = QuicUtils::IsCryptoStreamId(transport_version(), id);
MaybeBundleAckOpportunistically();
bool fin = state != NO_FIN;
QUIC_BUG_IF(quic_bug_12398_17, has_handshake && fin)
- << "Handshake packets should never send a fin";
+ << ENDPOINT << "Handshake packets should never send a fin";
// To make reasoning about crypto frames easier, we don't combine them with
// other retransmittable frames in a single packet.
if (has_handshake && HasPendingRetransmittableFrames()) {
@@ -1250,7 +1317,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id,
}
if (!fin && (write_length == 0)) {
- QUIC_BUG(quic_bug_10752_22) << "Attempt to consume empty data without FIN.";
+ QUIC_BUG(quic_bug_10752_22)
+ << ENDPOINT << "Attempt to consume empty data without FIN.";
return QuicConsumedData(0, false);
}
// We determine if we can enter the fast path before executing
@@ -1273,7 +1341,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id,
next_transmission_type_, &frame)) {
// The creator is always flushed if there's not enough room for a new
// stream frame before ConsumeData, so ConsumeData should always succeed.
- QUIC_BUG(quic_bug_10752_23) << "Failed to ConsumeData, stream:" << id;
+ QUIC_BUG(quic_bug_10752_23)
+ << ENDPOINT << "Failed to ConsumeData, stream:" << id;
return QuicConsumedData(0, false);
}
@@ -1285,7 +1354,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id,
AddRandomPadding();
}
QUICHE_DCHECK(total_bytes_consumed == write_length ||
- (bytes_consumed > 0 && HasPendingFrames()));
+ (bytes_consumed > 0 && HasPendingFrames()))
+ << ENDPOINT;
if (total_bytes_consumed == write_length) {
// We're done writing the data. Exit the loop.
@@ -1320,7 +1390,8 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath(
QuicStreamOffset offset,
bool fin,
size_t total_bytes_consumed) {
- QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
+ QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id))
+ << ENDPOINT;
if (AttemptingToSendUnencryptedStreamData()) {
return QuicConsumedData(total_bytes_consumed,
fin && (total_bytes_consumed == write_length));
@@ -1337,7 +1408,7 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath(
if (bytes_consumed == 0) {
const std::string error_details =
"Failed in CreateAndSerializeStreamFrame.";
- QUIC_BUG(quic_bug_10752_24) << error_details;
+ QUIC_BUG(quic_bug_10752_24) << ENDPOINT << error_details;
delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
error_details);
break;
@@ -1352,9 +1423,10 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath(
size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level,
size_t write_length,
QuicStreamOffset offset) {
- QUIC_DVLOG(2) << "ConsumeCryptoData " << level << " write_length "
+ QUIC_DVLOG(2) << ENDPOINT << "ConsumeCryptoData " << level << " write_length "
<< write_length << " offset " << offset;
QUIC_BUG_IF(quic_bug_10752_25, !flusher_attached_)
+ << ENDPOINT
<< "Packet flusher is not attached when "
"generator tries to write crypto data.";
MaybeBundleAckOpportunistically();
@@ -1381,7 +1453,7 @@ size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level,
// assuming here that they won't occupy so much of the packet that a
// CRYPTO frame won't fit.
QUIC_BUG(quic_bug_10752_26)
- << "Failed to ConsumeCryptoData at level " << level;
+ << ENDPOINT << "Failed to ConsumeCryptoData at level " << level;
return 0;
}
total_bytes_consumed += frame.crypto_frame->data_length;
@@ -1398,6 +1470,7 @@ void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) {
// MTU discovery frames must be sent by themselves.
if (!CanSetMaxPacketLength()) {
QUIC_BUG(quic_bug_10752_27)
+ << ENDPOINT
<< "MTU discovery packets should only be sent when no other "
<< "frames needs to be sent.";
return;
@@ -1416,7 +1489,7 @@ void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) {
// The only reason AddFrame can fail is that the packet is too full to fit in
// a ping. This is not possible for any sane MTU.
QUIC_BUG_IF(quic_bug_10752_28, !success)
- << "Failed to send path MTU target_mtu:" << target_mtu
+ << ENDPOINT << "Failed to send path MTU target_mtu:" << target_mtu
<< " transmission_type:" << next_transmission_type_;
// Reset the packet length back.
@@ -1435,12 +1508,13 @@ void QuicPacketCreator::MaybeBundleAckOpportunistically() {
const bool flushed =
FlushAckFrame(delegate_->MaybeBundleAckOpportunistically());
QUIC_BUG_IF(quic_bug_10752_29, !flushed)
- << "Failed to flush ACK frame. encryption_level:"
+ << ENDPOINT << "Failed to flush ACK frame. encryption_level:"
<< packet_.encryption_level;
}
bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) {
QUIC_BUG_IF(quic_bug_10752_30, !flusher_attached_)
+ << ENDPOINT
<< "Packet flusher is not attached when "
"generator tries to send ACK frame.";
// MaybeBundleAckOpportunistically could be called nestedly when sending a
@@ -1448,16 +1522,18 @@ bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) {
QUIC_BUG_IF(quic_bug_12398_18,
GetQuicReloadableFlag(quic_single_ack_in_packet2) &&
!frames.empty() && has_ack())
- << "Trying to flush " << frames << " when there is ACK queued";
+ << ENDPOINT << "Trying to flush " << frames
+ << " when there is ACK queued";
for (const auto& frame : frames) {
- QUICHE_DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME);
+ QUICHE_DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME)
+ << ENDPOINT;
if (HasPendingFrames()) {
if (AddFrame(frame, next_transmission_type_)) {
// There is pending frames and current frame fits.
continue;
}
}
- QUICHE_DCHECK(!HasPendingFrames());
+ QUICHE_DCHECK(!HasPendingFrames()) << ENDPOINT;
// There is no pending frames, consult the delegate whether a packet can be
// generated.
if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
@@ -1465,7 +1541,8 @@ bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) {
return false;
}
const bool success = AddFrame(frame, next_transmission_type_);
- QUIC_BUG_IF(quic_bug_10752_31, !success) << "Failed to flush " << frame;
+ QUIC_BUG_IF(quic_bug_10752_31, !success)
+ << ENDPOINT << "Failed to flush " << frame;
}
return true;
}
@@ -1488,7 +1565,7 @@ void QuicPacketCreator::Flush() {
if (GetQuicFlag(FLAGS_quic_export_write_path_stats_at_server)) {
if (!write_start_packet_number_.IsInitialized()) {
QUIC_BUG(quic_bug_10752_32)
- << "write_start_packet_number is not initialized";
+ << ENDPOINT << "write_start_packet_number is not initialized";
return;
}
QUIC_SERVER_HISTOGRAM_COUNTS(
@@ -1522,6 +1599,7 @@ void QuicPacketCreator::SetTransmissionType(TransmissionType type) {
MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id,
QuicMemSliceSpan message) {
QUIC_BUG_IF(quic_bug_10752_33, !flusher_attached_)
+ << ENDPOINT
<< "Packet flusher is not attached when "
"generator tries to add message frame.";
MaybeBundleAckOpportunistically();
@@ -1535,7 +1613,8 @@ MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id,
QuicMessageFrame* frame = new QuicMessageFrame(message_id, message);
const bool success = AddFrame(QuicFrame(frame), next_transmission_type_);
if (!success) {
- QUIC_BUG(quic_bug_10752_34) << "Failed to send message " << message_id;
+ QUIC_BUG(quic_bug_10752_34)
+ << ENDPOINT << "Failed to send message " << message_id;
delete frame;
return MESSAGE_STATUS_INTERNAL_ERROR;
}
@@ -1564,7 +1643,8 @@ void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) {
header->reset_flag = false;
header->version_flag = IncludeVersionInHeader();
if (IncludeNonceInPublicHeader()) {
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
+ QUICHE_DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective())
+ << ENDPOINT;
header->nonce = &diversification_nonce_;
} else {
header->nonce = nullptr;
@@ -1640,7 +1720,8 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
frame.type != MESSAGE_FRAME && frame.type != NEW_TOKEN_FRAME &&
frame.type != RETIRE_CONNECTION_ID_FRAME &&
frame.type != ACK_FREQUENCY_FRAME))
- << frame.type << " not allowed at " << packet_.encryption_level;
+ << ENDPOINT << frame.type << " not allowed at "
+ << packet_.encryption_level;
if (frame.type == STREAM_FRAME) {
if (MaybeCoalesceStreamFrame(frame.stream_frame)) {
@@ -1656,7 +1737,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
QUICHE_DCHECK(frame.type != ACK_FRAME || (!frame.ack_frame->packets.Empty() &&
frame.ack_frame->packets.Max() ==
frame.ack_frame->largest_acked))
- << "Invalid ACK frame: " << frame;
+ << ENDPOINT << "Invalid ACK frame: " << frame;
size_t frame_len = GetSerializedFrameLength(frame);
if (frame_len == 0 && RemoveSoftMaxPacketLength()) {
@@ -1664,7 +1745,8 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
frame_len = GetSerializedFrameLength(frame);
}
if (frame_len == 0) {
- QUIC_DVLOG(1) << "Flushing because current open packet is full when adding "
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Flushing because current open packet is full when adding "
<< frame;
FlushCurrentPacket();
return false;
@@ -1672,7 +1754,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
if (queued_frames_.empty()) {
packet_size_ = PacketHeaderSize();
}
- QUICHE_DCHECK_LT(0u, packet_size_);
+ QUICHE_DCHECK_LT(0u, packet_size_) << ENDPOINT;
packet_size_ += ExpansionOnNewFrame() + frame_len;
@@ -1749,12 +1831,14 @@ bool QuicPacketCreator::MaybeCoalesceStreamFrame(const QuicStreamFrame& frame) {
// The back of retransmittable frames must be the same as the original
// queued frames' back.
- QUICHE_DCHECK_EQ(packet_.retransmittable_frames.back().type, STREAM_FRAME);
+ QUICHE_DCHECK_EQ(packet_.retransmittable_frames.back().type, STREAM_FRAME)
+ << ENDPOINT;
QuicStreamFrame* retransmittable =
&packet_.retransmittable_frames.back().stream_frame;
- QUICHE_DCHECK_EQ(retransmittable->stream_id, frame.stream_id);
+ QUICHE_DCHECK_EQ(retransmittable->stream_id, frame.stream_id) << ENDPOINT;
QUICHE_DCHECK_EQ(retransmittable->offset + retransmittable->data_length,
- frame.offset);
+ frame.offset)
+ << ENDPOINT;
retransmittable->data_length = candidate->data_length;
retransmittable->fin = candidate->fin;
packet_size_ += frame.data_length;
@@ -1771,7 +1855,7 @@ bool QuicPacketCreator::RemoveSoftMaxPacketLength() {
if (!CanSetMaxPacketLength()) {
return false;
}
- QUIC_DVLOG(1) << "Restoring max packet length to: "
+ QUIC_DVLOG(1) << ENDPOINT << "Restoring max packet length to: "
<< latched_hard_max_packet_length_;
SetMaxPacketLength(latched_hard_max_packet_length_);
// Reset latched_max_packet_length_.
@@ -1814,7 +1898,7 @@ void QuicPacketCreator::MaybeAddPadding() {
bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)),
packet_.transmission_type);
QUIC_BUG_IF(quic_bug_10752_36, !success)
- << "Failed to add padding_bytes: " << padding_bytes
+ << ENDPOINT << "Failed to add padding_bytes: " << padding_bytes
<< " transmission_type: " << packet_.transmission_type;
}
@@ -1848,9 +1932,11 @@ bool QuicPacketCreator::StreamFrameIsClientHello(
void QuicPacketCreator::SetServerConnectionIdIncluded(
QuicConnectionIdIncluded server_connection_id_included) {
QUICHE_DCHECK(server_connection_id_included == CONNECTION_ID_PRESENT ||
- server_connection_id_included == CONNECTION_ID_ABSENT);
+ server_connection_id_included == CONNECTION_ID_ABSENT)
+ << ENDPOINT;
QUICHE_DCHECK(framer_->perspective() == Perspective::IS_SERVER ||
- server_connection_id_included != CONNECTION_ID_ABSENT);
+ server_connection_id_included != CONNECTION_ID_ABSENT)
+ << ENDPOINT;
server_connection_id_included_ = server_connection_id_included;
}
@@ -1862,7 +1948,8 @@ void QuicPacketCreator::SetServerConnectionId(
void QuicPacketCreator::SetClientConnectionId(
QuicConnectionId client_connection_id) {
QUICHE_DCHECK(client_connection_id.IsEmpty() ||
- framer_->version().SupportsClientConnectionIds());
+ framer_->version().SupportsClientConnectionIds())
+ << ENDPOINT;
client_connection_id_ = client_connection_id;
}
@@ -1928,7 +2015,8 @@ QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const {
const QuicPacketLength largest_payload =
largest_frame - std::min(largest_frame, kQuicFrameTypeSize);
// This must always be less than or equal to GetCurrentLargestMessagePayload.
- QUICHE_DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload());
+ QUICHE_DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload())
+ << ENDPOINT;
return largest_payload;
}
@@ -1940,7 +2028,7 @@ bool QuicPacketCreator::AttemptingToSendUnencryptedStreamData() {
const std::string error_details =
absl::StrCat("Cannot send stream data with level: ",
EncryptionLevelToString(packet_.encryption_level));
- QUIC_BUG(quic_bug_10752_37) << error_details;
+ QUIC_BUG(quic_bug_10752_37) << ENDPOINT << error_details;
delegate_->OnUnrecoverableError(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
error_details);
return true;
@@ -2005,19 +2093,56 @@ void QuicPacketCreator::SetDefaultPeerAddress(QuicSocketAddress address) {
}
}
+#define ENDPOINT2 \
+ (creator_->framer_->perspective() == Perspective::IS_SERVER ? "Server: " \
+ : "Client: ")
+
+QuicPacketCreator::ScopedPeerAddressContext::ScopedPeerAddressContext(
+ QuicPacketCreator* creator,
+ QuicSocketAddress address,
+ bool update_connection_id)
+ : ScopedPeerAddressContext(creator,
+ address,
+ EmptyQuicConnectionId(),
+ EmptyQuicConnectionId(),
+ update_connection_id) {}
+
QuicPacketCreator::ScopedPeerAddressContext::ScopedPeerAddressContext(
QuicPacketCreator* creator,
- QuicSocketAddress address)
- : creator_(creator), old_peer_address_(creator_->packet_.peer_address) {
- QUIC_BUG_IF(quic_bug_12398_19,
- !creator_->packet_.peer_address.IsInitialized())
- << "Context is used before seralized packet's peer address is "
+ QuicSocketAddress address,
+ const QuicConnectionId& client_connection_id,
+ const QuicConnectionId& server_connection_id,
+ bool update_connection_id)
+ : creator_(creator),
+ old_peer_address_(creator_->packet_.peer_address),
+ old_client_connection_id_(creator_->GetClientConnectionId()),
+ old_server_connection_id_(creator_->GetServerConnectionId()),
+ update_connection_id_(update_connection_id) {
+ QUIC_BUG_IF(quic_bug_12398_19, !old_peer_address_.IsInitialized())
+ << ENDPOINT2
+ << "Context is used before serialized packet's peer address is "
"initialized.";
creator_->SetDefaultPeerAddress(address);
+ if (update_connection_id_) {
+ // Flush current packet if connection ID length changes.
+ if (address == old_peer_address_ &&
+ ((client_connection_id.length() !=
+ old_client_connection_id_.length()) ||
+ (server_connection_id.length() !=
+ old_server_connection_id_.length()))) {
+ creator_->FlushCurrentPacket();
+ }
+ creator_->SetClientConnectionId(client_connection_id);
+ creator_->SetServerConnectionId(server_connection_id);
+ }
}
QuicPacketCreator::ScopedPeerAddressContext::~ScopedPeerAddressContext() {
creator_->SetDefaultPeerAddress(old_peer_address_);
+ if (update_connection_id_) {
+ creator_->SetClientConnectionId(old_client_connection_id_);
+ creator_->SetServerConnectionId(old_server_connection_id_);
+ }
}
QuicPacketCreator::ScopedSerializationFailureHandler::
@@ -2034,16 +2159,19 @@ QuicPacketCreator::ScopedSerializationFailureHandler::
if (creator_->packet_.encrypted_buffer == nullptr) {
const std::string error_details = "Failed to SerializePacket.";
- QUIC_BUG(quic_bug_10752_38) << error_details;
+ QUIC_BUG(quic_bug_10752_38) << ENDPOINT2 << error_details;
creator_->delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
error_details);
}
}
+#undef ENDPOINT2
+
void QuicPacketCreator::set_encryption_level(EncryptionLevel level) {
QUICHE_DCHECK(level == packet_.encryption_level || !HasPendingFrames())
- << "Cannot update encryption level from " << packet_.encryption_level
- << " to " << level << " when we already have pending frames: "
+ << ENDPOINT << "Cannot update encryption level from "
+ << packet_.encryption_level << " to " << level
+ << " when we already have pending frames: "
<< QuicFramesToString(queued_frames_);
packet_.encryption_level = level;
}
@@ -2054,6 +2182,7 @@ void QuicPacketCreator::AddPathChallengeFrame(
// AddFrame(). Sort out test helper functions and peer class that don't
// enforce this check.
QUIC_BUG_IF(quic_bug_10752_39, !flusher_attached_)
+ << ENDPOINT
<< "Packet flusher is not attached when "
"generator tries to write stream data.";
// Write a PATH_CHALLENGE frame, which has a random 8-byte payload.
@@ -2094,13 +2223,13 @@ bool QuicPacketCreator::AddPaddedFrameWithRetry(const QuicFrame& frame) {
}
}
// Frame was not queued but queued frames were flushed.
- QUICHE_DCHECK(!HasPendingFrames());
+ QUICHE_DCHECK(!HasPendingFrames()) << ENDPOINT;
if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
return false;
}
bool success = AddPaddedSavedFrame(frame, NOT_RETRANSMISSION);
- QUIC_BUG_IF(quic_bug_12398_20, !success);
+ QUIC_BUG_IF(quic_bug_12398_20, !success) << ENDPOINT;
return true;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
index 5e0c65e35fc..d4a58055282 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
@@ -22,13 +22,15 @@
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
#include "quic/core/frames/quic_stream_frame.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_coalesced_packet.h"
+#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_framer.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_export.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
namespace test {
@@ -83,18 +85,28 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
virtual void OnStreamFrameCoalesced(const QuicStreamFrame& /*frame*/) {}
};
- // Set the peer address which the serialized packet will be sent to during the
- // scope of this object. Upon exiting the scope, the original peer address is
- // restored.
+ // Set the peer address and connection IDs with which the serialized packet
+ // will be sent to during the scope of this object. Upon exiting the scope,
+ // the original peer address and connection IDs are restored.
class QUIC_EXPORT_PRIVATE ScopedPeerAddressContext {
public:
ScopedPeerAddressContext(QuicPacketCreator* creator,
- QuicSocketAddress address);
+ QuicSocketAddress address,
+ bool update_connection_id);
+
+ ScopedPeerAddressContext(QuicPacketCreator* creator,
+ QuicSocketAddress address,
+ const QuicConnectionId& client_connection_id,
+ const QuicConnectionId& server_connection_id,
+ bool update_connection_id);
~ScopedPeerAddressContext();
private:
QuicPacketCreator* creator_;
QuicSocketAddress old_peer_address_;
+ QuicConnectionId old_client_connection_id_;
+ QuicConnectionId old_server_connection_id_;
+ bool update_connection_id_;
};
QuicPacketCreator(QuicConnectionId server_connection_id,
@@ -247,7 +259,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// |payloads| is cleared.
std::unique_ptr<SerializedPacket>
SerializePathResponseConnectivityProbingPacket(
- const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
+ const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded);
// Add PATH_RESPONSE to current packet, flush before or afterwards if needed.
@@ -261,6 +273,16 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Returns a dummy packet that is valid but contains no useful information.
static SerializedPacket NoPacket();
+ // Returns the server connection ID to send over the wire.
+ const QuicConnectionId& GetServerConnectionId() const {
+ return server_connection_id_;
+ }
+
+ // Returns the client connection ID to send over the wire.
+ const QuicConnectionId& GetClientConnectionId() const {
+ return client_connection_id_;
+ }
+
// Returns the destination connection ID to send over the wire.
QuicConnectionId GetDestinationConnectionId() const;
@@ -287,6 +309,11 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
void set_encryption_level(EncryptionLevel level);
EncryptionLevel encryption_level() { return packet_.encryption_level; }
+ // Sets whether initial packets are protected with chaos.
+ void set_chaos_protection_enabled(bool chaos_protection_enabled) {
+ chaos_protection_enabled_ = chaos_protection_enabled;
+ }
+
// packet number of the last created packet, or 0 if no packets have been
// created.
QuicPacketNumber packet_number() const { return packet_.packet_number; }
@@ -444,7 +471,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
const QuicPacketHeader& header,
char* buffer,
size_t packet_length,
- const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
+ const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded,
EncryptionLevel level);
@@ -487,6 +514,13 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
QuicPacketCreator* creator_; // Unowned.
};
+ // Attempts to build a data packet with chaos protection. If this packet isn't
+ // supposed to be protected or if serialization fails then absl::nullopt is
+ // returned. Otherwise returns the serialized length.
+ absl::optional<size_t> MaybeBuildDataPacketWithChaosProtection(
+ const QuicPacketHeader& header,
+ char* buffer);
+
// Creates a stream frame which fits into the current open packet. If
// |data_size| is 0 and fin is true, the expected behavior is to consume
// the fin.
@@ -671,6 +705,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// accept. There is no limit for QUIC_CRYPTO connections, but QUIC+TLS
// negotiates this during the handshake.
QuicByteCount max_datagram_frame_size_;
+
+ // Whether to attempt protecting initial packets with chaos.
+ bool chaos_protection_enabled_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc
index 5986bd2890f..57d1018d94c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc
@@ -19,6 +19,7 @@
#include "quic/core/crypto/quic_decrypter.h"
#include "quic/core/crypto/quic_encrypter.h"
#include "quic/core/frames/quic_stream_frame.h"
+#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_data_writer.h"
#include "quic/core/quic_simple_buffer_allocator.h"
#include "quic/core/quic_types.h"
@@ -34,13 +35,14 @@
#include "quic/test_tools/simple_quic_framer.h"
#include "common/test_tools/quiche_test_utils.h"
-using testing::_;
-using testing::DoAll;
-using testing::InSequence;
-using testing::Invoke;
-using testing::Return;
-using testing::SaveArg;
-using testing::StrictMock;
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::StrictMock;
namespace quic {
namespace test {
@@ -269,6 +271,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
n * 2;
}
+ void TestChaosProtection(bool enabled);
+
static constexpr QuicStreamOffset kOffset = 0u;
char buffer_[kMaxOutgoingPacketSize];
@@ -751,7 +755,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponseUnpadded) {
};
// clang-format on
std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
size_t length = creator_.BuildPathResponsePacket(
header, buffer.get(), ABSL_ARRAYSIZE(packet), payloads,
@@ -798,7 +802,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponsePadded) {
};
// clang-format on
std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
size_t length = creator_.BuildPathResponsePacket(
header, buffer.get(), ABSL_ARRAYSIZE(packet), payloads,
@@ -848,7 +852,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesUnpadded) {
// clang-format on
std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
payloads.push_back(payload1);
payloads.push_back(payload2);
@@ -902,7 +906,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesPadded) {
// clang-format on
std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
payloads.push_back(payload1);
payloads.push_back(payload2);
@@ -987,7 +991,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
std::unique_ptr<SerializedPacket> encrypted(
@@ -1017,7 +1021,7 @@ TEST_P(QuicPacketCreatorTest,
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
std::unique_ptr<SerializedPacket> encrypted(
@@ -1047,7 +1051,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
payloads.push_back(payload1);
@@ -1080,7 +1084,7 @@ TEST_P(QuicPacketCreatorTest,
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
payloads.push_back(payload1);
@@ -1113,7 +1117,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
payloads.push_back(payload1);
payloads.push_back(payload2);
@@ -1149,7 +1153,7 @@ TEST_P(QuicPacketCreatorTest,
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- QuicCircularDeque<QuicPathFrameBuffer> payloads;
+ quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
payloads.push_back(payload1);
payloads.push_back(payload2);
@@ -1311,7 +1315,7 @@ TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) {
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
}
- std::string data("a");
+ std::string data("Hello World!");
if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
QuicStreamFrame stream_frame(
QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
@@ -1338,15 +1342,51 @@ TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) {
} else {
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
}
- if (client_framer_.version().HasHeaderProtection()) {
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- }
EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
ProcessPacket(serialized);
EXPECT_EQ(GetParam().version_serialization, header.version_flag);
}
+void QuicPacketCreatorTest::TestChaosProtection(bool enabled) {
+ if (!GetParam().version.UsesCryptoFrames()) {
+ return;
+ }
+ MockRandom mock_random(2);
+ QuicPacketCreatorPeer::SetRandom(&creator_, &mock_random);
+ creator_.set_chaos_protection_enabled(enabled);
+ std::string data("ChAoS_ThEoRy!");
+ producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data);
+ frames_.push_back(
+ QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length())));
+ frames_.push_back(QuicFrame(QuicPaddingFrame(33)));
+ SerializedPacket serialized = SerializeAllFrames(frames_);
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ if (enabled) {
+ EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)).Times(AtLeast(2));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(AtLeast(2));
+ EXPECT_CALL(framer_visitor_, OnPingFrame(_)).Times(AtLeast(1));
+ } else {
+ EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)).Times(1);
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(1);
+ EXPECT_CALL(framer_visitor_, OnPingFrame(_)).Times(0);
+ }
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ ProcessPacket(serialized);
+}
+
+TEST_P(QuicPacketCreatorTest, ChaosProtectionEnabled) {
+ TestChaosProtection(/*enabled=*/true);
+}
+
+TEST_P(QuicPacketCreatorTest, ChaosProtectionDisabled) {
+ TestChaosProtection(/*enabled=*/false);
+}
+
TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) {
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
@@ -1954,17 +1994,7 @@ TEST_P(QuicPacketCreatorTest, RetryToken) {
creator_.SetRetryToken(
std::string(retry_token_bytes, sizeof(retry_token_bytes)));
- std::string data("a");
- if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
- QuicStreamFrame stream_frame(
- QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
- /*fin=*/false, 0u, absl::string_view());
- frames_.push_back(QuicFrame(stream_frame));
- } else {
- producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data);
- frames_.push_back(
- QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length())));
- }
+ frames_.push_back(QuicFrame(QuicPingFrame()));
SerializedPacket serialized = SerializeAllFrames(frames_);
QuicPacketHeader header;
@@ -1976,11 +2006,7 @@ TEST_P(QuicPacketCreatorTest, RetryToken) {
EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _));
EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
.WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
- if (QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
- EXPECT_CALL(framer_visitor_, OnCryptoFrame(_));
- } else {
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
- }
+ EXPECT_CALL(framer_visitor_, OnPingFrame(_));
if (client_framer_.version().HasHeaderProtection()) {
EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
}
@@ -2261,6 +2287,32 @@ TEST_P(QuicPacketCreatorTest, SoftMaxPacketLength) {
EXPECT_TRUE(creator_.HasPendingFrames());
}
+TEST_P(QuicPacketCreatorTest,
+ ChangingEncryptionLevelRemovesSoftMaxPacketLength) {
+ if (!client_framer_.version().CanSendCoalescedPackets()) {
+ return;
+ }
+ // First set encryption level to forward secure which has the shortest header.
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ const QuicByteCount previous_max_packet_length = creator_.max_packet_length();
+ const size_t min_acceptable_packet_size =
+ GetPacketHeaderOverhead(client_framer_.transport_version()) +
+ QuicPacketCreator::MinPlaintextPacketSize(client_framer_.version()) +
+ GetEncryptionOverhead();
+ // Then set the soft max packet length to the lowest allowed value.
+ creator_.SetSoftMaxPacketLength(min_acceptable_packet_size);
+ // Make sure that the low value was accepted.
+ EXPECT_EQ(creator_.max_packet_length(), min_acceptable_packet_size);
+ // Now set the encryption level to handshake which increases the header size.
+ creator_.set_encryption_level(ENCRYPTION_HANDSHAKE);
+ // Make sure that adding a frame removes the the soft max packet length.
+ QuicAckFrame ack_frame(InitAckFrame(1));
+ frames_.push_back(QuicFrame(&ack_frame));
+ SerializedPacket serialized = SerializeAllFrames(frames_);
+ EXPECT_EQ(serialized.encryption_level, ENCRYPTION_HANDSHAKE);
+ EXPECT_EQ(creator_.max_packet_length(), previous_max_packet_length);
+}
+
class MockDelegate : public QuicPacketCreator::DelegateInterface {
public:
MockDelegate() {}
@@ -3811,8 +3863,12 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ExtraPaddingNeeded) {
TEST_F(QuicPacketCreatorMultiplePacketsTest,
PeerAddressContextWithSameAddress) {
+ QuicConnectionId client_connection_id = TestConnectionId(1);
+ QuicConnectionId server_connection_id = TestConnectionId(2);
QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
creator_.SetDefaultPeerAddress(peer_addr);
+ creator_.SetClientConnectionId(client_connection_id);
+ creator_.SetServerConnectionId(server_connection_id);
// Send some stream data.
MakeIOVector("foo", &iov_);
EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
@@ -3824,8 +3880,12 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest,
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
{
- // Set a different address via context which should trigger flush.
- QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr);
+ // Set the same address via context which should not trigger flush.
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &creator_, peer_addr, client_connection_id, server_connection_id,
+ /*update_connection_id=*/true);
+ ASSERT_EQ(client_connection_id, creator_.GetClientConnectionId());
+ ASSERT_EQ(server_connection_id, creator_.GetServerConnectionId());
EXPECT_TRUE(creator_.HasPendingFrames());
// Queue another STREAM_FRAME.
QuicConsumedData consumed = creator_.ConsumeData(
@@ -3874,8 +3934,14 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest,
}));
EXPECT_TRUE(creator_.HasPendingFrames());
{
+ QuicConnectionId client_connection_id = TestConnectionId(1);
+ QuicConnectionId server_connection_id = TestConnectionId(2);
// Set a different address via context which should trigger flush.
- QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr1);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &creator_, peer_addr1, client_connection_id, server_connection_id,
+ /*update_connection_id=*/true);
+ ASSERT_EQ(client_connection_id, creator_.GetClientConnectionId());
+ ASSERT_EQ(server_connection_id, creator_.GetServerConnectionId());
EXPECT_FALSE(creator_.HasPendingFrames());
// Queue another STREAM_FRAME.
QuicConsumedData consumed = creator_.ConsumeData(
@@ -3891,9 +3957,15 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest,
TEST_F(QuicPacketCreatorMultiplePacketsTest,
NestedPeerAddressContextWithDifferentAddress) {
+ QuicConnectionId client_connection_id1 = creator_.GetClientConnectionId();
+ QuicConnectionId server_connection_id1 = creator_.GetServerConnectionId();
QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
creator_.SetDefaultPeerAddress(peer_addr);
- QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &creator_, peer_addr, client_connection_id1, server_connection_id1,
+ /*update_connection_id=*/true);
+ ASSERT_EQ(client_connection_id1, creator_.GetClientConnectionId());
+ ASSERT_EQ(server_connection_id1, creator_.GetServerConnectionId());
// Send some stream data.
MakeIOVector("foo", &iov_);
@@ -3913,9 +3985,14 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest,
ASSERT_EQ(1u, packet.retransmittable_frames.size());
EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ QuicConnectionId client_connection_id2 = TestConnectionId(3);
+ QuicConnectionId server_connection_id2 = TestConnectionId(4);
// Set up another context with a different address.
- QuicPacketCreator::ScopedPeerAddressContext context(&creator_,
- peer_addr1);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &creator_, peer_addr1, client_connection_id2, server_connection_id2,
+ /*update_connection_id=*/true);
+ ASSERT_EQ(client_connection_id2, creator_.GetClientConnectionId());
+ ASSERT_EQ(server_connection_id2, creator_.GetServerConnectionId());
MakeIOVector("foo", &iov_);
EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
.WillRepeatedly(Return(true));
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc
index 5cc593f41bf..d625b5dcb6a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc
@@ -15,7 +15,6 @@
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h
index 5187c61def4..56f83594b8f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h
@@ -249,4 +249,11 @@ QUIC_PROTOCOL_FLAG(
true,
"If true, QUIC QPACK decoder includes 32-bytes overheader per entry while "
"comparing request/response header size against its upper limit.")
+
+QUIC_PROTOCOL_FLAG(
+ bool,
+ quic_reject_retry_token_in_initial_packet,
+ false,
+ "If true, always reject retry_token received in INITIAL packets")
+
#endif
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc
index a1b78a4fb86..079778cd5d8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc
@@ -205,11 +205,7 @@ QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay(
// before sending an ack.
QuicTime::Delta ack_delay = std::min(
local_max_ack_delay_, rtt_stats.min_rtt() * ack_decimation_delay_);
- if (GetQuicReloadableFlag(quic_ack_delay_alarm_granularity)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_ack_delay_alarm_granularity);
- ack_delay = std::max(ack_delay, kAlarmGranularity);
- }
- return ack_delay;
+ return std::max(ack_delay, kAlarmGranularity);
}
void QuicReceivedPacketManager::MaybeUpdateAckFrequency(
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc
index 3cfa0ce0a43..da586c67a3d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc
@@ -397,9 +397,6 @@ TEST_F(QuicReceivedPacketManagerTest, SendDelayedAckDecimation) {
}
TEST_F(QuicReceivedPacketManagerTest, SendDelayedAckDecimationMin1ms) {
- if (!GetQuicReloadableFlag(quic_ack_delay_alarm_granularity)) {
- return;
- }
EXPECT_FALSE(HasPendingAck());
// Seed the min_rtt with a kAlarmGranularity signal.
rtt_stats_.UpdateRtt(kAlarmGranularity, QuicTime::Delta::Zero(),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
index 13e2396fd86..781f6f95b90 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
@@ -19,7 +19,6 @@
#include "quic/core/congestion_control/send_algorithm_interface.h"
#include "quic/core/congestion_control/uber_loss_algorithm.h"
#include "quic/core/proto/cached_network_parameters_proto.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_sustained_bandwidth_recorder.h"
#include "quic/core/quic_time.h"
@@ -28,6 +27,7 @@
#include "quic/core/quic_unacked_packet_map.h"
#include "quic/platform/api/quic_containers.h"
#include "quic/platform/api/quic_export.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -673,7 +673,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// The history of outstanding max_ack_delays sent to peer. Outstanding means
// a max_ack_delay is sent as part of the last acked AckFrequencyFrame or
// an unacked AckFrequencyFrame after that.
- QuicCircularDeque<std::pair<QuicTime::Delta, /*sequence_number=*/uint64_t>>
+ quiche::QuicheCircularDeque<
+ std::pair<QuicTime::Delta, /*sequence_number=*/uint64_t>>
in_use_sent_ack_delays_;
// Latest received ack frame.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
index 7c7aa4d077f..1bcb9dcb7bd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
@@ -25,7 +25,7 @@
#include "quic/platform/api/quic_map_util.h"
#include "quic/platform/api/quic_server_stats.h"
#include "quic/platform/api/quic_stack_trace.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
using spdy::SpdyPriority;
@@ -686,11 +686,8 @@ bool QuicSession::WillingAndAbleToWrite() const {
if (HasPendingHandshake()) {
return true;
}
- if (GetQuicReloadableFlag(quic_fix_willing_and_able_to_write2)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_willing_and_able_to_write2);
- if (!IsEncryptionEstablished()) {
- return false;
- }
+ if (!IsEncryptionEstablished()) {
+ return false;
}
}
if (control_frame_manager_.WillingToWrite() ||
@@ -773,10 +770,24 @@ QuicConsumedData QuicSession::WritevData(
perspective() == Perspective::IS_CLIENT);
QUIC_BUG_IF(quic_bug_12435_3, type == NOT_RETRANSMISSION)
<< ENDPOINT << "Try to send new data on stream " << id
- << "before 1-RTT keys are available while 0-RTT is rejected.";
+ << "before 1-RTT keys are available while 0-RTT is rejected. "
+ "Version: "
+ << ParsedQuicVersionToString(version());
+ } else if (version().UsesTls() || perspective() == Perspective::IS_SERVER) {
+ QUIC_BUG(quic_bug_10866_2)
+ << ENDPOINT << "Try to send data of stream " << id
+ << " before encryption is established. Version: "
+ << ParsedQuicVersionToString(version());
} else {
- QUIC_BUG(quic_bug_10866_2) << ENDPOINT << "Try to send data of stream "
- << id << " before encryption is established.";
+ // In QUIC crypto, this could happen when the client sends full CHLO and
+ // 0-RTT request, then receives an inchoate REJ and sends an inchoate
+ // CHLO. The client then gets the ACK of the inchoate CHLO or the client
+ // gets the full REJ and needs to verify the proof (before it sends the
+ // full CHLO), such that there is no outstanding crypto data.
+ // Retransmission alarm fires in TLP mode which tries to retransmit the
+ // 0-RTT request (without encryption).
+ QUIC_DLOG(INFO) << ENDPOINT << "Try to send data of stream " << id
+ << " before encryption is established.";
}
return QuicConsumedData(0, false);
}
@@ -920,15 +931,12 @@ void QuicSession::SendGoAway(QuicErrorCode error_code,
const std::string& reason) {
// GOAWAY frame is not supported in IETF QUIC.
QUICHE_DCHECK(!VersionHasIetfQuicFrames(transport_version()));
- if (GetQuicReloadableFlag(quic_encrypted_goaway)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_encrypted_goaway, 1, 2);
- if (!IsEncryptionEstablished()) {
- QUIC_CODE_COUNT(quic_goaway_before_encryption_established);
- connection_->CloseConnection(
- error_code, reason,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
+ if (!IsEncryptionEstablished()) {
+ QUIC_CODE_COUNT(quic_goaway_before_encryption_established);
+ connection_->CloseConnection(
+ error_code, reason,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
}
if (transport_goaway_sent_) {
return;
@@ -1666,10 +1674,7 @@ void QuicSession::OnTlsHandshakeComplete() {
// Server sends HANDSHAKE_DONE to signal confirmation of the handshake
// to the client.
control_frame_manager_.WriteOrBufferHandshakeDone();
- if (GetQuicReloadableFlag(quic_enable_token_based_address_validation) &&
- connection()->version().HasIetfQuicFrames()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_token_based_address_validation,
- 1, 2);
+ if (connection()->version().HasIetfQuicFrames()) {
MaybeSendAddressToken();
}
}
@@ -1775,6 +1780,11 @@ void QuicSession::OnHandshakeCallbackDone() {
}
}
+bool QuicSession::PacketFlusherAttached() const {
+ QUICHE_DCHECK(connection_->connected());
+ return connection()->packet_creator().PacketFlusherAttached();
+}
+
void QuicSession::OnCryptoHandshakeMessageSent(
const CryptoHandshakeMessage& /*message*/) {}
@@ -2096,12 +2106,14 @@ void QuicSession::SendAckFrequency(const QuicAckFrequencyFrame& frame) {
}
void QuicSession::SendNewConnectionId(const QuicNewConnectionIdFrame& frame) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 1, 5);
control_frame_manager_.WriteOrBufferNewConnectionId(
frame.connection_id, frame.sequence_number, frame.retire_prior_to,
frame.stateless_reset_token);
}
void QuicSession::SendRetireConnectionId(uint64_t sequence_number) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 2, 5);
control_frame_manager_.WriteOrBufferRetireConnectionId(sequence_number);
}
@@ -2495,11 +2507,6 @@ QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
return connection_->GetGuaranteedLargestMessagePayload();
}
-void QuicSession::SendStopSending(QuicRstStreamErrorCode code,
- QuicStreamId stream_id) {
- control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
-}
-
QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
if (VersionHasIetfQuicFrames(transport_version())) {
return ietf_streamid_manager_.next_outgoing_bidirectional_stream_id();
@@ -2609,15 +2616,19 @@ bool QuicSession::HasPendingPathValidation() const {
return connection_->HasPendingPathValidation();
}
-void QuicSession::MigratePath(const QuicSocketAddress& self_address,
+bool QuicSession::MigratePath(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
QuicPacketWriter* writer,
bool owns_writer) {
- connection_->MigratePath(self_address, peer_address, writer, owns_writer);
+ return connection_->MigratePath(self_address, peer_address, writer,
+ owns_writer);
}
bool QuicSession::ValidateToken(absl::string_view token) const {
QUICHE_DCHECK_EQ(perspective_, Perspective::IS_SERVER);
+ if (GetQuicFlag(FLAGS_quic_reject_retry_token_in_initial_packet)) {
+ return false;
+ }
if (token.empty() || token[0] != 0) {
// Validate the prefix for token received in NEW_TOKEN frame.
return false;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h
index cf366cf5654..b6c1367019f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_session.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.h
@@ -264,10 +264,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Sends a WINDOW_UPDATE frame.
virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset);
- // Create and transmit a STOP_SENDING frame
- virtual void SendStopSending(QuicRstStreamErrorCode code,
- QuicStreamId stream_id);
-
// Called by stream |stream_id| when it gets closed.
virtual void OnStreamClosed(QuicStreamId stream_id);
@@ -306,6 +302,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool is_resumption,
std::string* error_details) override;
void OnHandshakeCallbackDone() override;
+ bool PacketFlusherAttached() const override;
// Implement StreamDelegateInterface.
void OnStreamError(QuicErrorCode error_code,
@@ -458,7 +455,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool HasPendingPathValidation() const;
// Switch to the path described in |context| without validating the path.
- void MigratePath(const QuicSocketAddress& self_address,
+ bool MigratePath(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
QuicPacketWriter* writer,
bool owns_writer);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h
index cb6e3aa943c..4b23d3d82cd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h
@@ -6,13 +6,13 @@
#define QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
#include "quic/core/frames/quic_stream_frame.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_interval_deque.h"
#include "quic/core/quic_interval_set.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_iovec.h"
#include "quic/platform/api/quic_mem_slice.h"
#include "quic/platform/api/quic_mem_slice_span.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
index cf7340bdb65..88a51bd5e08 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
@@ -56,13 +56,10 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
(!CloseStreamAtOffset(frame.offset + data_len) || data_len == 0)) {
return;
}
- if (GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_accept_empty_stream_frame_with_no_fin);
- if (stream_->version().HasIetfQuicFrames() && data_len == 0) {
- QUICHE_DCHECK(!frame.fin);
- // Ignore empty frame with no fin.
- return;
- }
+ if (stream_->version().HasIetfQuicFrames() && data_len == 0) {
+ QUICHE_DCHECK(!frame.fin);
+ // Ignore empty frame with no fin.
+ return;
}
OnFrameData(byte_offset, data_len, frame.data_buffer);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc
index e8fe6f367e2..b097bc5bc93 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc
@@ -252,8 +252,7 @@ TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) {
}
TEST_F(QuicStreamSequencerTest, EmptyFrame) {
- if (!GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin) ||
- !stream_.version().HasIetfQuicFrames()) {
+ if (!stream_.version().HasIetfQuicFrames()) {
EXPECT_CALL(stream_,
OnUnrecoverableError(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _));
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
index 739113a9147..2d3298b6fc9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
@@ -1634,8 +1634,7 @@ TEST_P(QuicStreamTest, RstStreamFrameChangesCloseOffset) {
TEST_P(QuicStreamTest, EmptyStreamFrameWithNoFin) {
Initialize();
QuicStreamFrame empty_stream_frame(stream_->id(), false, 0, "");
- if (GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin) &&
- stream_->version().HasIetfQuicFrames()) {
+ if (stream_->version().HasIetfQuicFrames()) {
EXPECT_CALL(*connection_,
CloseConnection(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _, _))
.Times(0);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc
index a6305b086f3..32b7bf9cd76 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc
@@ -12,7 +12,7 @@
#include "absl/strings/str_split.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc
index d6fa2da7a10..dbaa38bdefe 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc
@@ -18,12 +18,13 @@
#include "quic/core/quic_framer.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_utils.h"
+#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_map_util.h"
#include "quic/platform/api/quic_socket_address.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
@@ -324,6 +325,13 @@ void QuicTimeWaitListManager::SendPublicReset(
if (ietf_quic) {
std::unique_ptr<QuicEncryptedPacket> ietf_reset_packet =
BuildIetfStatelessResetPacket(connection_id, received_packet_length);
+ if (GetQuicRestartFlag(quic_fix_stateless_reset2) &&
+ ietf_reset_packet == nullptr) {
+ // This could happen when trying to reject a short header packet of
+ // a connection which is in the time wait list (and with no termination
+ // packet).
+ return;
+ }
QUIC_DVLOG(2) << "Dispatcher sending IETF reset packet for "
<< connection_id << std::endl
<< quiche::QuicheTextUtils::HexDump(
@@ -381,6 +389,10 @@ QuicTimeWaitListManager::BuildIetfStatelessResetPacket(
bool QuicTimeWaitListManager::SendOrQueuePacket(
std::unique_ptr<QueuedPacket> packet,
const QuicPerPacketContext* /*packet_context*/) {
+ if (packet == nullptr) {
+ QUIC_LOG(ERROR) << "Tried to send or queue a null packet";
+ return true;
+ }
if (WriteToWire(packet.get())) {
// Allow the packet to be deleted upon leaving this function.
return true;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h
index 2018f723306..ac371f2c180 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h
@@ -224,7 +224,7 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager
virtual bool SendOrQueuePacket(std::unique_ptr<QueuedPacket> packet,
const QuicPerPacketContext* packet_context);
- const QuicCircularDeque<std::unique_ptr<QueuedPacket>>&
+ const quiche::QuicheCircularDeque<std::unique_ptr<QueuedPacket>>&
pending_packets_queue() const {
return pending_packets_queue_;
}
@@ -318,7 +318,8 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager
// Pending termination packets that need to be sent out to the peer when we
// are given a chance to write by the dispatcher.
- QuicCircularDeque<std::unique_ptr<QueuedPacket>> pending_packets_queue_;
+ quiche::QuicheCircularDeque<std::unique_ptr<QueuedPacket>>
+ pending_packets_queue_;
// Time period for which connection_ids should remain in time wait state.
const QuicTime::Delta time_wait_period_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc
index d33e992e372..4e9f957182b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc
@@ -19,6 +19,7 @@
#include "quic/core/quic_packet_writer.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_utils.h"
+#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/mock_quic_session_visitor.h"
@@ -749,6 +750,24 @@ TEST_F(QuicTimeWaitListManagerTest,
}
}
+// Regression test for b/184053898.
+TEST_F(QuicTimeWaitListManagerTest, DonotCrashOnNullStatelessReset) {
+ // Received a packet with length <
+ // QuicFramer::GetMinStatelessResetPacketLength(), and this will result in a
+ // null stateless reset.
+ time_wait_list_manager_.SendPublicReset(
+ self_address_, peer_address_, TestConnectionId(1),
+ /*ietf_quic=*/true,
+ /*received_packet_length=*/
+ QuicFramer::GetMinStatelessResetPacketLength() - 1,
+ /*packet_context=*/nullptr);
+}
+
+TEST_F(QuicTimeWaitListManagerTest, SendOrQueueNullPacket) {
+ QuicTimeWaitListManagerPeer::SendOrQueuePacket(&time_wait_list_manager_,
+ nullptr, nullptr);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h
index 75c835d6c49..676f054b1fb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h
@@ -7,15 +7,14 @@
#include <cstddef>
#include <cstdint>
-#include <deque>
#include "absl/strings/str_cat.h"
-#include "quic/core/quic_circular_deque.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_transmission_info.h"
#include "quic/core/session_notifier_interface.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_flags.h"
+#include "common/quiche_circular_deque.h"
namespace quic {
@@ -113,10 +112,10 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap {
QuicPacketNumber GetLeastUnacked() const;
using const_iterator =
- QuicCircularDeque<QuicTransmissionInfo>::const_iterator;
+ quiche::QuicheCircularDeque<QuicTransmissionInfo>::const_iterator;
using const_reverse_iterator =
- QuicCircularDeque<QuicTransmissionInfo>::const_reverse_iterator;
- using iterator = QuicCircularDeque<QuicTransmissionInfo>::iterator;
+ quiche::QuicheCircularDeque<QuicTransmissionInfo>::const_reverse_iterator;
+ using iterator = quiche::QuicheCircularDeque<QuicTransmissionInfo>::iterator;
const_iterator begin() const { return unacked_packets_.begin(); }
const_iterator end() const { return unacked_packets_.end(); }
@@ -300,7 +299,7 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap {
// If the old packet is acked before the new packet, then the old entry will
// be removed from the map and the new entry's retransmittable frames will be
// set to nullptr.
- QuicCircularDeque<QuicTransmissionInfo> unacked_packets_;
+ quiche::QuicheCircularDeque<QuicTransmissionInfo> unacked_packets_;
// The packet at the 0th index of unacked_packets_.
QuicPacketNumber least_unacked_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
index 27b74bb9430..1f0137a91bc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
@@ -21,8 +21,8 @@
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
-#include "quic/platform/api/quic_prefetch.h"
#include "common/platform/api/quiche_logging.h"
+#include "common/platform/api/quiche_prefetch.h"
#include "common/quiche_endian.h"
namespace quic {
@@ -266,9 +266,9 @@ void QuicUtils::CopyToBuffer(const struct iovec* iov,
char* next_base = static_cast<char*>(iov[iovnum + 1].iov_base);
// Prefetch 2 cachelines worth of data to get the prefetcher started; leave
// it to the hardware prefetcher after that.
- QuicPrefetchT0(next_base);
+ quiche::QuichePrefetchT0(next_base);
if (iov[iovnum + 1].iov_len >= 64) {
- QuicPrefetchT0(next_base + ABSL_CACHELINE_SIZE);
+ quiche::QuichePrefetchT0(next_base + ABSL_CACHELINE_SIZE);
}
}
@@ -308,7 +308,6 @@ bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) {
case MTU_DISCOVERY_FRAME:
case PATH_CHALLENGE_FRAME:
case PATH_RESPONSE_FRAME:
- case NEW_CONNECTION_ID_FRAME:
return false;
default:
return true;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
index ab68ddd57d1..ba2ec7ee29e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
@@ -17,8 +17,8 @@
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "common/quiche_endian.h"
+#include "common/quiche_text_utils.h"
namespace quic {
namespace {
@@ -599,7 +599,6 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
void QuicVersionInitializeSupportForIetfDraft() {
// Enable necessary flags.
- SetQuicReloadableFlag(quic_fix_key_update_on_first_packet, true);
}
void QuicEnableVersion(const ParsedQuicVersion& version) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h
index 3379fcb39df..dbc2ca9173d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h
@@ -9,13 +9,13 @@
#include <cstdint>
#include <utility>
+#include "http2/core/priority_write_scheduler.h"
#include "quic/core/quic_packets.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_containers.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_map_util.h"
-#include "spdy/core/priority_write_scheduler.h"
namespace quic {
@@ -78,7 +78,7 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
bool IsStreamBlocked(QuicStreamId stream_id) const;
private:
- spdy::PriorityWriteScheduler<QuicStreamId> priority_write_scheduler_;
+ http2::PriorityWriteScheduler<QuicStreamId> priority_write_scheduler_;
// If performing batch writes, this will be the stream ID of the stream doing
// batch writes for this priority level. We will allow this stream to write
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc
index ae85b07c251..ac1fb180f54 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc
@@ -17,7 +17,6 @@
#include "quic/core/quic_types.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_bug_tracker.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
index f8e321663ca..1b9de030860 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
@@ -17,7 +17,7 @@
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_hostname_utils.h"
-#include "common/platform/api/quiche_text_utils.h"
+#include "common/quiche_text_utils.h"
namespace quic {
@@ -42,12 +42,10 @@ TlsClientHandshaker::TlsClientHandshaker(
has_application_state_(has_application_state),
crypto_config_(crypto_config),
tls_connection_(crypto_config->ssl_ctx(), this) {
- if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) {
- std::string token =
- crypto_config->LookupOrCreate(server_id)->source_address_token();
- if (!token.empty()) {
- session->SetSourceAddressTokenToSend(token);
- }
+ std::string token =
+ crypto_config->LookupOrCreate(server_id)->source_address_token();
+ if (!token.empty()) {
+ session->SetSourceAddressTokenToSend(token);
}
}
@@ -179,18 +177,16 @@ bool TlsClientHandshaker::SetAlpn() {
}
// Enable ALPS only for versions that use HTTP/3 frames.
- if (enable_alps_) {
- for (const std::string& alpn_string : alpns) {
- ParsedQuicVersion version = ParseQuicVersionString(alpn_string);
- if (!version.IsKnown() || !version.UsesHttp3()) {
- continue;
- }
- if (SSL_add_application_settings(
- ssl(), reinterpret_cast<const uint8_t*>(alpn_string.data()),
- alpn_string.size(), nullptr, /* settings_len = */ 0) != 1) {
- QUIC_BUG(quic_bug_10576_7) << "Failed to enable ALPS.";
- return false;
- }
+ for (const std::string& alpn_string : alpns) {
+ ParsedQuicVersion version = ParseQuicVersionString(alpn_string);
+ if (!version.IsKnown() || !version.UsesHttp3()) {
+ continue;
+ }
+ if (SSL_add_application_settings(
+ ssl(), reinterpret_cast<const uint8_t*>(alpn_string.data()),
+ alpn_string.size(), nullptr, /* settings_len = */ 0) != 1) {
+ QUIC_BUG(quic_bug_10576_7) << "Failed to enable ALPS.";
+ return false;
}
}
@@ -502,20 +498,18 @@ void TlsClientHandshaker::FinishHandshake() {
<< "'";
// Parse ALPS extension.
- if (enable_alps_) {
- const uint8_t* alps_data;
- size_t alps_length;
- SSL_get0_peer_application_settings(ssl(), &alps_data, &alps_length);
- if (alps_length > 0) {
- auto error = session()->OnAlpsData(alps_data, alps_length);
- if (error) {
- // Calling CloseConnection() is safe even in case OnAlpsData() has
- // already closed the connection.
- CloseConnection(
- QUIC_HANDSHAKE_FAILED,
- absl::StrCat("Error processing ALPS data: ", error.value()));
- return;
- }
+ const uint8_t* alps_data;
+ size_t alps_length;
+ SSL_get0_peer_application_settings(ssl(), &alps_data, &alps_length);
+ if (alps_length > 0) {
+ auto error = session()->OnAlpsData(alps_data, alps_length);
+ if (error) {
+ // Calling CloseConnection() is safe even in case OnAlpsData() has
+ // already closed the connection.
+ CloseConnection(
+ QUIC_HANDSHAKE_FAILED,
+ absl::StrCat("Error processing ALPS data: ", error.value()));
+ return;
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h
index 8fb6da69d2c..eb39ccf9fab 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h
@@ -168,9 +168,6 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
std::unique_ptr<TransportParameters> received_transport_params_ = nullptr;
std::unique_ptr<ApplicationState> received_application_state_ = nullptr;
-
- // Latched value of reloadable flag quic_enable_alps_client.
- const bool enable_alps_ = GetQuicReloadableFlag(quic_enable_alps_client);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
index e498acb9a43..8365f633f0f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
@@ -279,11 +279,7 @@ TEST_P(TlsClientHandshakerTest, ConnectedAfterHandshake) {
TEST_P(TlsClientHandshakerTest, ConnectionClosedOnTlsError) {
// Have client send ClientHello.
stream()->CryptoConnect();
- if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) {
- EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _));
- } else {
- EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
- }
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _));
// Send a zero-length ServerHello from server to client.
char bogus_handshake_message[] = {
@@ -621,23 +617,14 @@ TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) {
.WillOnce([kTestAlpn](const std::vector<absl::string_view>& alpns) {
return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
});
- if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) {
- EXPECT_CALL(
- *server_connection_,
- CloseConnection(
- QUIC_HANDSHAKE_FAILED,
- static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + 120),
- "TLS handshake failure (ENCRYPTION_INITIAL) 120: "
- "no application protocol",
- _));
- } else {
- EXPECT_CALL(
- *server_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED,
- "TLS handshake failure (ENCRYPTION_INITIAL) 120: "
- "no application protocol",
- _));
- }
+
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ static_cast<QuicIetfTransportErrorCodes>(
+ CRYPTO_ERROR_FIRST + 120),
+ "TLS handshake failure (ENCRYPTION_INITIAL) 120: "
+ "no application protocol",
+ _));
stream()->CryptoConnect();
crypto_test_utils::AdvanceHandshake(connection_, stream(), 0,
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc
index bc8e0b48d4d..9ba5f3c12f6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc
@@ -96,6 +96,13 @@ void TlsHandshaker::AdvanceHandshake() {
return;
}
+ QUICHE_BUG_IF(quic_tls_server_async_done_no_flusher,
+ SSL_is_server(ssl()) && add_packet_flusher_on_async_op_done_ &&
+ !handshaker_delegate_->PacketFlusherAttached())
+ << "is_server:" << SSL_is_server(ssl())
+ << ", add_packet_flusher_on_async_op_done_:"
+ << add_packet_flusher_on_async_op_done_;
+
QUIC_VLOG(1) << ENDPOINT << "Continuing handshake";
int rv = SSL_do_handshake(ssl());
@@ -105,6 +112,7 @@ void TlsHandshaker::AdvanceHandshake() {
// that case. If there are no unprocessed ServerHello, the retry will return a
// non-positive number.
if (retry_handshake_on_early_data_ && rv == 1 && SSL_in_early_data(ssl())) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_retry_handshake_on_early_data, 1, 2);
OnEnterEarlyData();
rv = SSL_do_handshake(ssl());
QUIC_VLOG(1) << ENDPOINT
@@ -335,15 +343,10 @@ void TlsHandshaker::SendAlert(EncryptionLevel level, uint8_t desc) {
"TLS handshake failure (", EncryptionLevelToString(level), ") ",
static_cast<int>(desc), ": ", SSL_alert_desc_string_long(desc));
QUIC_DLOG(ERROR) << error_details;
- if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_send_tls_crypto_error_code);
- CloseConnection(
- TlsAlertToQuicErrorCode(desc),
- static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + desc),
- error_details);
- } else {
- CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
- }
+ CloseConnection(
+ TlsAlertToQuicErrorCode(desc),
+ static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + desc),
+ error_details);
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h
index 6bf48b548c4..0b5ddc36769 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h
@@ -16,6 +16,7 @@
#include "quic/core/crypto/tls_connection.h"
#include "quic/core/quic_session.h"
#include "quic/platform/api/quic_export.h"
+#include "quic/platform/api/quic_flags.h"
namespace quic {
@@ -167,6 +168,9 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate,
// error code corresponding to the TLS alert description |desc|.
void SendAlert(EncryptionLevel level, uint8_t desc) override;
+ const bool add_packet_flusher_on_async_op_done_ =
+ GetQuicReloadableFlag(quic_add_packet_flusher_on_async_op_done);
+
const bool retry_handshake_on_early_data_ =
GetQuicReloadableFlag(quic_tls_retry_handshake_on_early_data);
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
index b628db1744a..efd4d275013 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
@@ -8,6 +8,7 @@
#include <string>
#include "absl/base/macros.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "third_party/boringssl/src/include/openssl/pool.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
@@ -22,7 +23,6 @@
#include "quic/platform/api/quic_hostname_utils.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_server_stats.h"
-#include "common/platform/api/quiche_text_utils.h"
#define RECORD_LATENCY_IN_US(stat_name, latency, comment) \
do { \
@@ -47,8 +47,6 @@ void TlsServerHandshaker::DefaultProofSourceHandle::CancelPendingOperation() {
QUIC_DVLOG(1) << "CancelPendingOperation. is_signature_pending="
<< (signature_callback_ != nullptr);
if (signature_callback_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 3,
- 3);
signature_callback_->Cancel();
signature_callback_ = nullptr;
}
@@ -58,9 +56,11 @@ QuicAsyncStatus
TlsServerHandshaker::DefaultProofSourceHandle::SelectCertificate(
const QuicSocketAddress& server_address,
const QuicSocketAddress& client_address,
+ absl::string_view /*ssl_capabilities*/,
const std::string& hostname,
absl::string_view /*client_hello*/,
const std::string& /*alpn*/,
+ absl::optional<std::string> /*alps*/,
const std::vector<uint8_t>& /*quic_transport_params*/,
const absl::optional<std::vector<uint8_t>>& /*early_data_context*/) {
if (!handshaker_ || !proof_source_) {
@@ -73,7 +73,8 @@ TlsServerHandshaker::DefaultProofSourceHandle::SelectCertificate(
proof_source_->GetCertChain(server_address, client_address, hostname);
handshaker_->OnSelectCertificateDone(
- /*ok=*/true, /*is_sync=*/true, chain.get());
+ /*ok=*/true, /*is_sync=*/true, chain.get(),
+ /*handshake_hints=*/absl::string_view());
if (!handshaker_->select_cert_status().has_value()) {
QUIC_BUG(quic_bug_12423_1)
<< "select_cert_status() has no value after a synchronous select cert";
@@ -119,35 +120,6 @@ QuicAsyncStatus TlsServerHandshaker::DefaultProofSourceHandle::ComputeSignature(
return success ? QUIC_SUCCESS : QUIC_FAILURE;
}
-TlsServerHandshaker::SignatureCallback::SignatureCallback(
- TlsServerHandshaker* handshaker)
- : handshaker_(handshaker) {
- QUICHE_DCHECK(!handshaker_->use_proof_source_handle_);
-}
-
-void TlsServerHandshaker::SignatureCallback::Run(
- bool ok,
- std::string signature,
- std::unique_ptr<ProofSource::Details> details) {
- if (handshaker_ == nullptr) {
- return;
- }
- if (ok) {
- handshaker_->cert_verify_sig_ = std::move(signature);
- handshaker_->proof_source_details_ = std::move(details);
- }
- int last_expected_ssl_error = handshaker_->expected_ssl_error();
- handshaker_->set_expected_ssl_error(SSL_ERROR_WANT_READ);
- handshaker_->signature_callback_ = nullptr;
- if (last_expected_ssl_error == SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
- handshaker_->AdvanceHandshakeFromCallback();
- }
-}
-
-void TlsServerHandshaker::SignatureCallback::Cancel() {
- handshaker_ = nullptr;
-}
-
TlsServerHandshaker::DecryptCallback::DecryptCallback(
TlsServerHandshaker* handshaker)
: handshaker_(handshaker) {}
@@ -217,13 +189,9 @@ TlsServerHandshaker::~TlsServerHandshaker() {
}
void TlsServerHandshaker::CancelOutstandingCallbacks() {
- if (use_proof_source_handle_ && proof_source_handle_) {
+ if (proof_source_handle_) {
proof_source_handle_->CancelPendingOperation();
}
- if (signature_callback_) {
- signature_callback_->Cancel();
- signature_callback_ = nullptr;
- }
if (ticket_decryption_callback_) {
ticket_decryption_callback_->Cancel();
ticket_decryption_callback_ = nullptr;
@@ -232,7 +200,6 @@ void TlsServerHandshaker::CancelOutstandingCallbacks() {
std::unique_ptr<ProofSourceHandle>
TlsServerHandshaker::MaybeCreateProofSourceHandle() {
- QUICHE_DCHECK(use_proof_source_handle_);
return std::make_unique<DefaultProofSourceHandle>(this, proof_source_);
}
@@ -384,6 +351,19 @@ TlsServerHandshaker::CreateCurrentOneRttEncrypter() {
void TlsServerHandshaker::OverrideQuicConfigDefaults(QuicConfig* /*config*/) {}
void TlsServerHandshaker::AdvanceHandshakeFromCallback() {
+ std::unique_ptr<QuicConnection::ScopedPacketFlusher> flusher;
+ if (add_packet_flusher_on_async_op_done_) {
+ if (session()->PacketFlusherAttached()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_add_packet_flusher_on_async_op_done, 1,
+ 2);
+ } else {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_add_packet_flusher_on_async_op_done, 2,
+ 2);
+ }
+ flusher = std::make_unique<QuicConnection::ScopedPacketFlusher>(
+ session()->connection());
+ }
+
AdvanceHandshake();
if (!is_connection_closed()) {
handshaker_delegate()->OnHandshakeCallbackDone();
@@ -541,6 +521,7 @@ std::string TlsServerHandshaker::GetAcceptChValueForOrigin(
void TlsServerHandshaker::FinishHandshake() {
if (retry_handshake_on_early_data_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_retry_handshake_on_early_data, 2, 2);
QUICHE_DCHECK(!SSL_in_early_data(ssl()));
} else {
if (SSL_in_early_data(ssl())) {
@@ -601,33 +582,19 @@ ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign(
uint16_t sig_alg,
absl::string_view in) {
QUICHE_DCHECK_EQ(expected_ssl_error(), SSL_ERROR_WANT_READ);
- if (use_proof_source_handle_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 2,
- 3);
- QuicAsyncStatus status = proof_source_handle_->ComputeSignature(
- session()->connection()->self_address(),
- session()->connection()->peer_address(), cert_selection_hostname(),
- sig_alg, in, max_out);
- if (status == QUIC_PENDING) {
- set_expected_ssl_error(SSL_ERROR_WANT_PRIVATE_KEY_OPERATION);
- if (async_op_timer_.has_value()) {
- QUIC_CODE_COUNT(
- quic_tls_server_computing_signature_while_another_op_pending);
- }
- async_op_timer_ = QuicTimeAccumulator();
- async_op_timer_->Start(now());
- }
- return PrivateKeyComplete(out, out_len, max_out);
- }
- signature_callback_ = new SignatureCallback(this);
- proof_source_->ComputeTlsSignature(
+ QuicAsyncStatus status = proof_source_handle_->ComputeSignature(
session()->connection()->self_address(),
- session()->connection()->peer_address(), cert_selection_hostname(),
- sig_alg, in, std::unique_ptr<SignatureCallback>(signature_callback_));
- if (signature_callback_) {
+ session()->connection()->peer_address(), crypto_negotiated_params_->sni,
+ sig_alg, in, max_out);
+ if (status == QUIC_PENDING) {
set_expected_ssl_error(SSL_ERROR_WANT_PRIVATE_KEY_OPERATION);
- return ssl_private_key_retry;
+ if (async_op_timer_.has_value()) {
+ QUIC_CODE_COUNT(
+ quic_tls_server_computing_signature_while_another_op_pending);
+ }
+ async_op_timer_ = QuicTimeAccumulator();
+ async_op_timer_->Start(now());
}
return PrivateKeyComplete(out, out_len, max_out);
}
@@ -673,7 +640,6 @@ void TlsServerHandshaker::OnComputeSignatureDone(
QUIC_DVLOG(1) << "OnComputeSignatureDone. ok:" << ok
<< ", is_sync:" << is_sync
<< ", len(signature):" << signature.size();
- QUICHE_DCHECK(use_proof_source_handle_);
if (ok) {
cert_verify_sig_ = std::move(signature);
proof_source_details_ = std::move(details);
@@ -795,24 +761,21 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback(
// EarlySelectCertCallback can be called twice from BoringSSL: If the first
// call returns ssl_select_cert_retry, when cert selection completes,
// SSL_do_handshake will call it again.
- if (use_proof_source_handle_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 1,
- 3);
- if (select_cert_status_.has_value()) {
- // This is the second call, return the result directly.
- QUIC_DVLOG(1) << "EarlySelectCertCallback called to continue handshake, "
- "returning directly. success:"
- << (select_cert_status_.value() == QUIC_SUCCESS);
- return (select_cert_status_.value() == QUIC_SUCCESS)
- ? ssl_select_cert_success
- : ssl_select_cert_error;
- }
- // This is the first call.
- select_cert_status_ = QUIC_PENDING;
- proof_source_handle_ = MaybeCreateProofSourceHandle();
+ if (select_cert_status_.has_value()) {
+ // This is the second call, return the result directly.
+ QUIC_DVLOG(1) << "EarlySelectCertCallback called to continue handshake, "
+ "returning directly. success:"
+ << (select_cert_status_.value() == QUIC_SUCCESS);
+ return (select_cert_status_.value() == QUIC_SUCCESS)
+ ? ssl_select_cert_success
+ : ssl_select_cert_error;
}
+ // This is the first call.
+ select_cert_status_ = QUIC_PENDING;
+ proof_source_handle_ = MaybeCreateProofSourceHandle();
+
if (!pre_shared_key_.empty()) {
// TODO(b/154162689) add PSK support to QUIC+TLS.
QUIC_BUG(quic_bug_10341_6)
@@ -824,18 +787,17 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback(
// function do not work at this point, but SSL_get_servername does.
const char* hostname = SSL_get_servername(ssl(), TLSEXT_NAMETYPE_host_name);
if (hostname) {
- hostname_ = hostname;
crypto_negotiated_params_->sni =
- QuicHostnameUtils::NormalizeHostname(hostname_);
- if (!ValidateHostname(hostname_)) {
+ QuicHostnameUtils::NormalizeHostname(hostname);
+ if (!ValidateHostname(hostname)) {
return ssl_select_cert_error;
}
- if (hostname_ != crypto_negotiated_params_->sni) {
+ if (hostname != crypto_negotiated_params_->sni) {
QUIC_CODE_COUNT(quic_tls_server_hostname_diff);
QUIC_LOG_EVERY_N_SEC(WARNING, 300)
<< "Raw and normalized hostnames differ, but both are valid SNIs. "
"raw hostname:"
- << hostname_ << ", normalized:" << crypto_negotiated_params_->sni;
+ << hostname << ", normalized:" << crypto_negotiated_params_->sni;
} else {
QUIC_CODE_COUNT(quic_tls_server_hostname_same);
}
@@ -843,97 +805,105 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback(
QUIC_LOG(INFO) << "No hostname indicated in SNI";
}
- if (use_proof_source_handle_) {
- std::string error_details;
- if (!ProcessTransportParameters(client_hello, &error_details)) {
- CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
- return ssl_select_cert_error;
- }
- OverrideQuicConfigDefaults(session()->config());
- session()->OnConfigNegotiated();
-
- auto set_transport_params_result = SetTransportParameters();
- if (!set_transport_params_result.success) {
- QUIC_LOG(ERROR) << "Failed to set transport parameters";
- return ssl_select_cert_error;
- }
-
- const QuicAsyncStatus status = proof_source_handle_->SelectCertificate(
- session()->connection()->self_address(),
- session()->connection()->peer_address(), cert_selection_hostname(),
- absl::string_view(
- reinterpret_cast<const char*>(client_hello->client_hello),
- client_hello->client_hello_len),
- AlpnForVersion(session()->version()),
- set_transport_params_result.quic_transport_params,
- set_transport_params_result.early_data_context);
+ std::string error_details;
+ if (!ProcessTransportParameters(client_hello, &error_details)) {
+ CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
+ return ssl_select_cert_error;
+ }
+ OverrideQuicConfigDefaults(session()->config());
+ session()->OnConfigNegotiated();
- QUICHE_DCHECK_EQ(status, select_cert_status().value());
+ auto set_transport_params_result = SetTransportParameters();
+ if (!set_transport_params_result.success) {
+ QUIC_LOG(ERROR) << "Failed to set transport parameters";
+ return ssl_select_cert_error;
+ }
- if (status == QUIC_PENDING) {
- set_expected_ssl_error(SSL_ERROR_PENDING_CERTIFICATE);
- if (async_op_timer_.has_value()) {
- QUIC_CODE_COUNT(
- quic_tls_server_selecting_cert_while_another_op_pending);
- }
- async_op_timer_ = QuicTimeAccumulator();
- async_op_timer_->Start(now());
- return ssl_select_cert_retry;
+ bssl::UniquePtr<uint8_t> ssl_capabilities;
+ size_t ssl_capabilities_len = 0;
+ absl::string_view ssl_capabilities_view;
+
+ absl::optional<std::string> alps;
+ if (use_handshake_hints_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_tls_server_use_handshake_hints);
+ if (CryptoUtils::GetSSLCapabilities(ssl(), &ssl_capabilities,
+ &ssl_capabilities_len)) {
+ ssl_capabilities_view = absl::string_view(
+ reinterpret_cast<const char*>(ssl_capabilities.get()),
+ ssl_capabilities_len);
}
- if (status == QUIC_FAILURE) {
+ // Enable ALPS for the session's ALPN.
+ SetApplicationSettingsResult alps_result =
+ SetApplicationSettings(AlpnForVersion(session()->version()));
+ if (!alps_result.success) {
return ssl_select_cert_error;
}
-
- return ssl_select_cert_success;
- }
-
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- proof_source_->GetCertChain(session()->connection()->self_address(),
- session()->connection()->peer_address(),
- cert_selection_hostname());
- if (!chain || chain->certs.empty()) {
- QUIC_LOG(ERROR) << "No certs provided for host. raw:" << hostname_
- << ", normalized:" << crypto_negotiated_params_->sni;
- return ssl_select_cert_error;
+ alps = alps_result.alps_length > 0
+ ? std::string(alps_result.alps_buffer.get(),
+ alps_result.alps_length)
+ : std::string();
}
- CryptoBuffers cert_buffers = chain->ToCryptoBuffers();
- tls_connection_.SetCertChain(cert_buffers.value);
-
- std::string error_details;
- if (!ProcessTransportParameters(client_hello, &error_details)) {
- CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
- return ssl_select_cert_error;
+ const QuicAsyncStatus status = proof_source_handle_->SelectCertificate(
+ session()->connection()->self_address(),
+ session()->connection()->peer_address(), ssl_capabilities_view,
+ crypto_negotiated_params_->sni,
+ absl::string_view(
+ reinterpret_cast<const char*>(client_hello->client_hello),
+ client_hello->client_hello_len),
+ AlpnForVersion(session()->version()), std::move(alps),
+ set_transport_params_result.quic_transport_params,
+ set_transport_params_result.early_data_context);
+
+ QUICHE_DCHECK_EQ(status, select_cert_status().value());
+
+ if (status == QUIC_PENDING) {
+ set_expected_ssl_error(SSL_ERROR_PENDING_CERTIFICATE);
+ if (async_op_timer_.has_value()) {
+ QUIC_CODE_COUNT(quic_tls_server_selecting_cert_while_another_op_pending);
+ }
+ async_op_timer_ = QuicTimeAccumulator();
+ async_op_timer_->Start(now());
+ return ssl_select_cert_retry;
}
- OverrideQuicConfigDefaults(session()->config());
- session()->OnConfigNegotiated();
- if (!SetTransportParameters().success) {
- QUIC_LOG(ERROR) << "Failed to set transport parameters";
+ if (status == QUIC_FAILURE) {
return ssl_select_cert_error;
}
- QUIC_DLOG(INFO) << "Set " << chain->certs.size() << " certs for server "
- << "with hostname " << hostname_;
return ssl_select_cert_success;
}
void TlsServerHandshaker::OnSelectCertificateDone(
bool ok,
bool is_sync,
- const ProofSource::Chain* chain) {
+ const ProofSource::Chain* chain,
+ absl::string_view handshake_hints) {
QUIC_DVLOG(1) << "OnSelectCertificateDone. ok:" << ok
- << ", is_sync:" << is_sync;
- QUICHE_DCHECK(use_proof_source_handle_);
-
+ << ", is_sync:" << is_sync
+ << ", len(handshake_hints):" << handshake_hints.size();
select_cert_status_ = QUIC_FAILURE;
if (ok) {
if (chain && !chain->certs.empty()) {
tls_connection_.SetCertChain(chain->ToCryptoBuffers().value);
+ if (use_handshake_hints_) {
+ if (!handshake_hints.empty() &&
+ !SSL_set_handshake_hints(
+ ssl(), reinterpret_cast<const uint8_t*>(handshake_hints.data()),
+ handshake_hints.size())) {
+ // If |SSL_set_handshake_hints| fails, the ssl() object will remain
+ // intact, it is as if we didn't call it. The handshaker will
+ // continue to compute signature/decrypt ticket as normal.
+ QUIC_CODE_COUNT(quic_tls_server_set_handshake_hints_failed);
+ QUIC_DVLOG(1) << "SSL_set_handshake_hints failed";
+ }
+ }
select_cert_status_ = QUIC_SUCCESS;
} else {
- QUIC_LOG(ERROR) << "No certs provided for host '" << hostname_ << "'";
+ QUIC_LOG(ERROR) << "No certs provided for host '"
+ << crypto_negotiated_params_->sni << "', server_address:"
+ << session()->connection()->self_address();
}
}
@@ -1008,40 +978,17 @@ int TlsServerHandshaker::SelectAlpn(const uint8_t** out,
alpn_length);
}
+ // TODO(wub): Remove QuicSession::SelectAlpn. QuicSessions should know the
+ // ALPN on construction.
auto selected_alpn = session()->SelectAlpn(alpns);
if (selected_alpn == alpns.end()) {
QUIC_DLOG(ERROR) << "No known ALPN provided by client";
return SSL_TLSEXT_ERR_NOACK;
}
- // Enable ALPS for the selected ALPN protocol.
- if (GetQuicReloadableFlag(quic_enable_alps_server)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_enable_alps_server);
-
- const uint8_t* alps_data = nullptr;
- size_t alps_length = 0;
- std::unique_ptr<char[]> buffer;
-
- const std::string& hostname = crypto_negotiated_params_->sni;
- std::string accept_ch_value = GetAcceptChValueForOrigin(hostname);
-
- std::string origin;
- if (GetQuicReloadableFlag(quic_alps_include_scheme_in_origin)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_alps_include_scheme_in_origin);
- origin = "https://";
- }
- origin.append(crypto_negotiated_params_->sni);
-
- if (!accept_ch_value.empty()) {
- AcceptChFrame frame{{{std::move(origin), std::move(accept_ch_value)}}};
- alps_length = HttpEncoder::SerializeAcceptChFrame(frame, &buffer);
- alps_data = reinterpret_cast<const uint8_t*>(buffer.get());
- }
-
- if (SSL_add_application_settings(
- ssl(), reinterpret_cast<const uint8_t*>(selected_alpn->data()),
- selected_alpn->size(), alps_data, alps_length) != 1) {
- QUIC_DLOG(ERROR) << "Failed to enable ALPS";
+ if (!use_handshake_hints_) {
+ // Enable ALPS for the selected ALPN protocol.
+ if (!SetApplicationSettings(*selected_alpn).success) {
return SSL_TLSEXT_ERR_NOACK;
}
}
@@ -1053,4 +1000,31 @@ int TlsServerHandshaker::SelectAlpn(const uint8_t** out,
return SSL_TLSEXT_ERR_OK;
}
+TlsServerHandshaker::SetApplicationSettingsResult
+TlsServerHandshaker::SetApplicationSettings(absl::string_view alpn) {
+ TlsServerHandshaker::SetApplicationSettingsResult result;
+ const uint8_t* alps_data = nullptr;
+
+ const std::string& hostname = crypto_negotiated_params_->sni;
+ std::string accept_ch_value = GetAcceptChValueForOrigin(hostname);
+ std::string origin = absl::StrCat("https://", hostname);
+
+ if (!accept_ch_value.empty()) {
+ AcceptChFrame frame{{{std::move(origin), std::move(accept_ch_value)}}};
+ result.alps_length =
+ HttpEncoder::SerializeAcceptChFrame(frame, &result.alps_buffer);
+ alps_data = reinterpret_cast<const uint8_t*>(result.alps_buffer.get());
+ }
+
+ if (SSL_add_application_settings(
+ ssl(), reinterpret_cast<const uint8_t*>(alpn.data()), alpn.size(),
+ alps_data, result.alps_length) != 1) {
+ QUIC_DLOG(ERROR) << "Failed to enable ALPS";
+ result.success = false;
+ } else {
+ result.success = true;
+ }
+ return result;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
index 7850d3519a8..260b094bda7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
@@ -19,6 +19,7 @@
#include "quic/core/quic_types.h"
#include "quic/core/tls_handshaker.h"
#include "quic/platform/api/quic_export.h"
+#include "quic/platform/api/quic_flags.h"
namespace quic {
@@ -88,25 +89,14 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
protected:
// Creates a proof source handle for selecting cert and computing signature.
- // Only called when |use_proof_source_handle_| is true.
virtual std::unique_ptr<ProofSourceHandle> MaybeCreateProofSourceHandle();
- bool use_proof_source_handle() const { return use_proof_source_handle_; }
-
// Hook to allow the server to override parts of the QuicConfig based on SNI
// before we generate transport parameters.
virtual void OverrideQuicConfigDefaults(QuicConfig* config);
virtual bool ValidateHostname(const std::string& hostname) const;
- // The hostname to be used to select certificates and compute signatures.
- // The function should only be called after a successful ValidateHostname().
- const std::string& cert_selection_hostname() const {
- return use_normalized_sni_for_cert_selection_
- ? crypto_negotiated_params_->sni
- : hostname_;
- }
-
const TlsConnection* tls_connection() const override {
return &tls_connection_;
}
@@ -177,7 +167,8 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
// ProofSourceHandleCallback implementation:
void OnSelectCertificateDone(bool ok,
bool is_sync,
- const ProofSource::Chain* chain) override;
+ const ProofSource::Chain* chain,
+ absl::string_view handshake_hints) override;
void OnComputeSignatureDone(
bool ok,
@@ -186,21 +177,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
std::unique_ptr<ProofSource::Details> details) override;
private:
- class QUIC_EXPORT_PRIVATE SignatureCallback
- : public ProofSource::SignatureCallback {
- public:
- explicit SignatureCallback(TlsServerHandshaker* handshaker);
- void Run(bool ok,
- std::string signature,
- std::unique_ptr<ProofSource::Details> details) override;
-
- // If called, Cancel causes the pending callback to be a no-op.
- void Cancel();
-
- private:
- TlsServerHandshaker* handshaker_;
- };
-
class QUIC_EXPORT_PRIVATE DecryptCallback
: public ProofSource::DecryptCallback {
public:
@@ -232,9 +208,11 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
QuicAsyncStatus SelectCertificate(
const QuicSocketAddress& server_address,
const QuicSocketAddress& client_address,
+ absl::string_view ssl_capabilities,
const std::string& hostname,
absl::string_view client_hello,
const std::string& alpn,
+ absl::optional<std::string> alps,
const std::vector<uint8_t>& quic_transport_params,
const absl::optional<std::vector<uint8_t>>& early_data_context)
override;
@@ -302,6 +280,13 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
bool ProcessTransportParameters(const SSL_CLIENT_HELLO* client_hello,
std::string* error_details);
+ struct QUIC_NO_EXPORT SetApplicationSettingsResult {
+ bool success = false;
+ std::unique_ptr<char[]> alps_buffer;
+ size_t alps_length = 0;
+ };
+ SetApplicationSettingsResult SetApplicationSettings(absl::string_view alpn);
+
QuicConnectionStats& connection_stats() {
return session()->connection()->mutable_stats();
}
@@ -309,7 +294,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
std::unique_ptr<ProofSourceHandle> proof_source_handle_;
ProofSource* proof_source_;
- SignatureCallback* signature_callback_ = nullptr;
// State to handle potentially asynchronous session ticket decryption.
// |ticket_decryption_callback_| points to the non-owned callback that was
@@ -328,7 +312,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
// nullopt means select cert hasn't started.
absl::optional<QuicAsyncStatus> select_cert_status_;
- std::string hostname_;
std::string cert_verify_sig_;
std::unique_ptr<ProofSource::Details> proof_source_details_;
@@ -346,11 +329,9 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
crypto_negotiated_params_;
TlsServerConnection tls_connection_;
- const bool use_proof_source_handle_ =
- GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source);
- const bool use_normalized_sni_for_cert_selection_ =
- GetQuicReloadableFlag(quic_tls_use_normalized_sni_for_cert_selectioon);
const QuicCryptoServerConfig* crypto_config_; // Unowned.
+ const bool use_handshake_hints_ =
+ GetQuicReloadableFlag(quic_tls_server_use_handshake_hints);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
index fbec2551227..d67c8791d2c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
@@ -400,10 +400,6 @@ TEST_P(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) {
}
TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertSuccess) {
- if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) {
- return;
- }
-
InitializeServerWithFakeProofSourceHandle();
server_handshaker_->SetupProofSourceHandle(
/*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC,
@@ -426,10 +422,6 @@ TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertSuccess) {
}
TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertFailure) {
- if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) {
- return;
- }
-
InitializeServerWithFakeProofSourceHandle();
server_handshaker_->SetupProofSourceHandle(
/*select_cert_action=*/FakeProofSourceHandle::Action::FAIL_ASYNC,
@@ -449,10 +441,6 @@ TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertFailure) {
}
TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertAndSignature) {
- if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) {
- return;
- }
-
InitializeServerWithFakeProofSourceHandle();
server_handshaker_->SetupProofSourceHandle(
/*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC,
@@ -507,10 +495,6 @@ TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSignature) {
}
TEST_P(TlsServerHandshakerTest, CancelPendingSelectCert) {
- if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) {
- return;
- }
-
InitializeServerWithFakeProofSourceHandle();
server_handshaker_->SetupProofSourceHandle(
/*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC,
@@ -557,10 +541,6 @@ TEST_P(TlsServerHandshakerTest, ExtractSNI) {
}
TEST_P(TlsServerHandshakerTest, HostnameForCertSelectionAndComputeSignature) {
- if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) {
- return;
- }
-
// Client uses upper case letters in hostname. It is considered valid by
// QuicHostnameUtils::IsValidSNI, but it should be normalized for cert
// selection.
@@ -577,23 +557,13 @@ TEST_P(TlsServerHandshakerTest, HostnameForCertSelectionAndComputeSignature) {
EXPECT_EQ(server_stream()->crypto_negotiated_params().sni,
"test.example.com");
- if (GetQuicReloadableFlag(quic_tls_use_normalized_sni_for_cert_selectioon)) {
- EXPECT_EQ(last_select_cert_args().hostname, "test.example.com");
- EXPECT_EQ(last_compute_signature_args().hostname, "test.example.com");
- } else {
- EXPECT_EQ(last_select_cert_args().hostname, "tEsT.EXAMPLE.CoM");
- EXPECT_EQ(last_compute_signature_args().hostname, "tEsT.EXAMPLE.CoM");
- }
+ EXPECT_EQ(last_select_cert_args().hostname, "test.example.com");
+ EXPECT_EQ(last_compute_signature_args().hostname, "test.example.com");
}
TEST_P(TlsServerHandshakerTest, ConnectionClosedOnTlsError) {
- if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) {
- EXPECT_CALL(*server_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _));
- } else {
- EXPECT_CALL(*server_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
- }
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _));
// Send a zero-length ClientHello from client to server.
char bogus_handshake_message[] = {
@@ -601,6 +571,15 @@ TEST_P(TlsServerHandshakerTest, ConnectionClosedOnTlsError) {
1, // HandshakeType client_hello
0, 0, 0, // uint24 length
};
+
+ // Install a packet flusher such that the packets generated by
+ // |server_connection_| in response to this handshake message are more likely
+ // to be coalesced and/or batched in the writer.
+ //
+ // This is required by TlsServerHandshaker because without the flusher, it
+ // tends to generate many small, uncoalesced packets, one per
+ // TlsHandshaker::WriteMessage.
+ QuicConnection::ScopedPacketFlusher flusher(server_connection_);
server_stream()->crypto_message_parser()->ProcessInput(
absl::string_view(bogus_handshake_message,
ABSL_ARRAYSIZE(bogus_handshake_message)),
@@ -613,23 +592,14 @@ TEST_P(TlsServerHandshakerTest, ClientSendingBadALPN) {
const std::string kTestBadClientAlpn = "bad-client-alpn";
EXPECT_CALL(*client_session_, GetAlpnsToOffer())
.WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn})));
- if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) {
- EXPECT_CALL(
- *server_connection_,
- CloseConnection(
- QUIC_HANDSHAKE_FAILED,
- static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + 120),
- "TLS handshake failure (ENCRYPTION_INITIAL) 120: "
- "no application protocol",
- _));
- } else {
- EXPECT_CALL(
- *server_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED,
- "TLS handshake failure (ENCRYPTION_INITIAL) 120: "
- "no application protocol",
- _));
- }
+
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ static_cast<QuicIetfTransportErrorCodes>(
+ CRYPTO_ERROR_FIRST + 120),
+ "TLS handshake failure (ENCRYPTION_INITIAL) 120: "
+ "no application protocol",
+ _));
AdvanceHandshakeWithFakeClient();
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc
index 5ed0e08777a..8f20b33c183 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc
@@ -120,14 +120,11 @@ void UberReceivedPacketManager::EnableMultiplePacketNumberSpacesSupport(
}
// In IETF QUIC, the peer is expected to acknowledge packets in Initial and
// Handshake packets with minimal delay.
- if (!GetQuicReloadableFlag(quic_delay_initial_ack) ||
- perspective == Perspective::IS_CLIENT) {
+ if (perspective == Perspective::IS_CLIENT) {
// Delay the first server ACK, because server ACKs are padded to
// full size and count towards the amplification limit.
received_packet_managers_[INITIAL_DATA].set_local_max_ack_delay(
kAlarmGranularity);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT(quic_delay_initial_ack);
}
received_packet_managers_[HANDSHAKE_DATA].set_local_max_ack_delay(
kAlarmGranularity);
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc
index 05e4a33aedf..cf612feab1d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc
@@ -478,17 +478,10 @@ TEST_F(UberReceivedPacketManagerTest, AckSendingDifferentPacketNumberSpaces) {
MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_INITIAL, 3);
EXPECT_TRUE(HasPendingAck());
// Delayed ack is scheduled.
- if (GetQuicReloadableFlag(quic_delay_initial_ack)) {
- CheckAckTimeout(clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(25));
- // Send delayed handshake data ACK.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(25));
- } else {
- CheckAckTimeout(clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(1));
- // Send delayed handshake data ACK.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- }
+ CheckAckTimeout(clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(25));
+ // Send delayed handshake data ACK.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(25));
CheckAckTimeout(clock_.ApproximateNow());
EXPECT_FALSE(HasPendingAck());