summaryrefslogtreecommitdiff
path: root/chromium/net/third_party
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 16:35:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 15:45:54 +0000
commit32f5a1c56531e4210bc4cf8d8c7825d66e081888 (patch)
treeeeeec6822f4d738d8454525233fd0e2e3a659e6d /chromium/net/third_party
parent99677208ff3b216fdfec551fbe548da5520cd6fb (diff)
downloadqtwebengine-chromium-32f5a1c56531e4210bc4cf8d8c7825d66e081888.tar.gz
BASELINE: Update Chromium to 87.0.4280.67
Change-Id: Ib157360be8c2ffb2c73125751a89f60e049c1d54 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/third_party')
-rw-r--r--chromium/net/third_party/quiche/BUILD.gn12
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h60
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc53
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h19
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h5
-rw-r--r--chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h2
-rw-r--r--chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc3
-rw-r--r--chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h8
-rw-r--r--chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc4
-rw-r--r--chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc110
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc60
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_structures_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc44
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc194
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_constants.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc43
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc170
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc186
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc61
-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/qpack/qpack_receive_stream.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.cc588
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.h116
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc2301
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc55
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h44
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc46
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.cc58
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc265
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc65
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc352
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc154
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc152
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc348
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc126
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h43
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc377
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.cc333
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.h55
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc105
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.cc54
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.h59
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc51
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc69
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc57
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc453
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc63
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc324
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc210
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h376
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h9
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc64
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h3
173 files changed, 5434 insertions, 4363 deletions
diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn
index 836245d848b..ffab81e2122 100644
--- a/chromium/net/third_party/quiche/BUILD.gn
+++ b/chromium/net/third_party/quiche/BUILD.gn
@@ -5,6 +5,16 @@
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
+# Since //net and //net/third_party/quiche have a circular dependency on each
+# other, exporting dependencies from the :quiche target directly does not work.
+# Thus, all public dependencies for QUICHE should go into the target below,
+# which is in turn propagated to all of //net source sets.
+source_set("quiche_public_deps") {
+ visibility = [ "//net:net_public_deps" ]
+
+ public_deps = [ "//third_party/abseil-cpp:absl" ]
+}
+
source_set("quiche") {
sources = [
"src/quic/core/quic_error_codes.cc",
@@ -17,7 +27,6 @@ source_set("quiche") {
"src/common/platform/api/quiche_endian.h",
"src/common/platform/api/quiche_export.h",
"src/common/platform/api/quiche_logging.h",
- "src/common/platform/api/quiche_map_util.h",
"src/common/platform/api/quiche_optional.h",
"src/common/platform/api/quiche_ptr_util.h",
"src/common/platform/api/quiche_str_cat.h",
@@ -1367,7 +1376,6 @@ source_set("quiche_tests") {
"src/quic/core/quic_versions_test.cc",
"src/quic/core/quic_write_blocked_list_test.cc",
"src/quic/core/tls_chlo_extractor_test.cc",
- "src/quic/core/tls_handshaker_test.cc",
"src/quic/core/uber_quic_stream_id_manager_test.cc",
"src/quic/core/uber_received_packet_manager_test.cc",
"src/quic/platform/api/quic_containers_test.cc",
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h
index f8a9ee68665..69bdc5bf029 100644
--- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h
+++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h
@@ -5,8 +5,11 @@
#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_ENDIAN_H_
#define QUICHE_COMMON_PLATFORM_API_QUICHE_ENDIAN_H_
+#include <algorithm>
+#include <cstdint>
+#include <type_traits>
+
#include "net/third_party/quiche/src/common/platform/api/quiche_export.h"
-#include "net/quiche/common/platform/impl/quiche_endian_impl.h"
namespace quiche {
@@ -20,33 +23,38 @@ enum Endianness {
// platform).
class QUICHE_EXPORT_PRIVATE QuicheEndian {
public:
- // Convert |x| from host order (can be either little or big endian depending
- // on the platform) to network order (big endian).
- static uint16_t HostToNet16(uint16_t x) {
- return QuicheEndianImpl::HostToNet16(x);
- }
- static uint32_t HostToNet32(uint32_t x) {
- return QuicheEndianImpl::HostToNet32(x);
- }
- static uint64_t HostToNet64(uint64_t x) {
- return QuicheEndianImpl::HostToNet64(x);
- }
-
- // Convert |x| from network order (big endian) to host order (can be either
- // little or big endian depending on the platform).
- static uint16_t NetToHost16(uint16_t x) {
- return QuicheEndianImpl::NetToHost16(x);
- }
- static uint32_t NetToHost32(uint32_t x) {
- return QuicheEndianImpl::NetToHost32(x);
- }
- static uint64_t NetToHost64(uint64_t x) {
- return QuicheEndianImpl::NetToHost64(x);
- }
+ // Convert |x| from host order (little endian) to network order (big endian).
+#if defined(__clang__) || \
+ (defined(__GNUC__) && \
+ ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
+ static uint16_t HostToNet16(uint16_t x) { return __builtin_bswap16(x); }
+ static uint32_t HostToNet32(uint32_t x) { return __builtin_bswap32(x); }
+ static uint64_t HostToNet64(uint64_t x) { return __builtin_bswap64(x); }
+#else
+ static uint16_t HostToNet16(uint16_t x) { return PortableByteSwap(x); }
+ static uint32_t HostToNet32(uint32_t x) { return PortableByteSwap(x); }
+ static uint64_t HostToNet64(uint64_t x) { return PortableByteSwap(x); }
+#endif
+
+ // Convert |x| from network order (big endian) to host order (little endian).
+ static uint16_t NetToHost16(uint16_t x) { return HostToNet16(x); }
+ static uint32_t NetToHost32(uint32_t x) { return HostToNet32(x); }
+ static uint64_t NetToHost64(uint64_t x) { return HostToNet64(x); }
// Returns true if current host order is little endian.
- static bool HostIsLittleEndian() {
- return QuicheEndianImpl::HostIsLittleEndian();
+ static bool HostIsLittleEndian() { return true; }
+
+ // Left public for tests.
+ template <typename T>
+ static T PortableByteSwap(T input) {
+ static_assert(std::is_unsigned<T>::value, "T has to be uintNN_t");
+ union {
+ T number;
+ char bytes[sizeof(T)];
+ } value;
+ value.number = input;
+ std::reverse(std::begin(value.bytes), std::end(value.bytes));
+ return value.number;
}
};
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc
index 98e16febd2f..2f21938b087 100644
--- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc
+++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc
@@ -18,40 +18,33 @@ const uint64_t k64BitSwappedTestData = 0x11223344ddccbbaa;
class QuicheEndianTest : public QuicheTest {};
+// Test portable version. Since we normally compile with either GCC or Clang,
+// it will very rarely used otherwise.
+TEST_F(QuicheEndianTest, Portable) {
+ EXPECT_EQ(k16BitSwappedTestData,
+ QuicheEndian::PortableByteSwap(k16BitTestData));
+ EXPECT_EQ(k32BitSwappedTestData,
+ QuicheEndian::PortableByteSwap(k32BitTestData));
+ EXPECT_EQ(k64BitSwappedTestData,
+ QuicheEndian::PortableByteSwap(k64BitTestData));
+}
+
TEST_F(QuicheEndianTest, HostToNet) {
- if (quiche::QuicheEndian::HostIsLittleEndian()) {
- EXPECT_EQ(k16BitSwappedTestData,
- quiche::QuicheEndian::HostToNet16(k16BitTestData));
- EXPECT_EQ(k32BitSwappedTestData,
- quiche::QuicheEndian::HostToNet32(k32BitTestData));
- EXPECT_EQ(k64BitSwappedTestData,
- quiche::QuicheEndian::HostToNet64(k64BitTestData));
- } else {
- EXPECT_EQ(k16BitTestData,
- quiche::QuicheEndian::HostToNet16(k16BitTestData));
- EXPECT_EQ(k32BitTestData,
- quiche::QuicheEndian::HostToNet32(k32BitTestData));
- EXPECT_EQ(k64BitTestData,
- quiche::QuicheEndian::HostToNet64(k64BitTestData));
- }
+ EXPECT_EQ(k16BitSwappedTestData,
+ quiche::QuicheEndian::HostToNet16(k16BitTestData));
+ EXPECT_EQ(k32BitSwappedTestData,
+ quiche::QuicheEndian::HostToNet32(k32BitTestData));
+ EXPECT_EQ(k64BitSwappedTestData,
+ quiche::QuicheEndian::HostToNet64(k64BitTestData));
}
TEST_F(QuicheEndianTest, NetToHost) {
- if (quiche::QuicheEndian::HostIsLittleEndian()) {
- EXPECT_EQ(k16BitTestData,
- quiche::QuicheEndian::NetToHost16(k16BitSwappedTestData));
- EXPECT_EQ(k32BitTestData,
- quiche::QuicheEndian::NetToHost32(k32BitSwappedTestData));
- EXPECT_EQ(k64BitTestData,
- quiche::QuicheEndian::NetToHost64(k64BitSwappedTestData));
- } else {
- EXPECT_EQ(k16BitSwappedTestData,
- quiche::QuicheEndian::NetToHost16(k16BitSwappedTestData));
- EXPECT_EQ(k32BitSwappedTestData,
- quiche::QuicheEndian::NetToHost32(k32BitSwappedTestData));
- EXPECT_EQ(k64BitSwappedTestData,
- quiche::QuicheEndian::NetToHost64(k64BitSwappedTestData));
- }
+ EXPECT_EQ(k16BitTestData,
+ quiche::QuicheEndian::NetToHost16(k16BitSwappedTestData));
+ EXPECT_EQ(k32BitTestData,
+ quiche::QuicheEndian::NetToHost32(k32BitSwappedTestData));
+ EXPECT_EQ(k64BitTestData,
+ quiche::QuicheEndian::NetToHost64(k64BitSwappedTestData));
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h
deleted file mode 100644
index b539466caad..00000000000
--- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h
+++ /dev/null
@@ -1,19 +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_COMMON_PLATFORM_API_QUICHE_MAP_UTIL_H_
-#define QUICHE_COMMON_PLATFORM_API_QUICHE_MAP_UTIL_H_
-
-#include "net/quiche/common/platform/impl/quiche_map_util_impl.h"
-
-namespace quiche {
-
-template <class Collection, class Key>
-bool QuicheContainsKey(const Collection& collection, const Key& key) {
- return QuicheContainsKeyImpl(collection, key);
-}
-
-} // namespace quiche
-
-#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_MAP_UTIL_H_
diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h
index 7a1aa0ed3cc..a59a595813c 100644
--- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h
+++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h
@@ -7,13 +7,16 @@
#include <memory>
+#include "absl/memory/memory.h"
#include "net/quiche/common/platform/impl/quiche_ptr_util_impl.h"
namespace quiche {
template <typename T>
std::unique_ptr<T> QuicheWrapUnique(T* ptr) {
- return QuicheWrapUniqueImpl<T>(ptr);
+ // TODO(b/166325009): replace this in code with absl::WrapUnique and delete
+ // this function.
+ return absl::WrapUnique<T>(ptr);
}
} // namespace quiche
diff --git a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h
index 6eb6ed9a5dc..36933bc6505 100644
--- a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h
+++ b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h
@@ -212,7 +212,7 @@ class SimpleLinkedHashMap {
typename ListType::iterator last = list_.end();
--last;
- CHECK(map_.insert(std::make_pair(pair.first, last)).second)
+ CHECK(map_.insert(std::make_pair(last->first, last)).second)
<< "Map and list are inconsistent";
return std::make_pair(last, true);
}
diff --git a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc
index 7e559459e7b..9f9eefd9ab8 100644
--- a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc
+++ b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc
@@ -17,7 +17,8 @@ FakeSimpleEpollServer::FakeSimpleEpollServer() : until_in_usec_(-1) {}
FakeSimpleEpollServer::~FakeSimpleEpollServer() = default;
-int FakeSimpleEpollServer::epoll_wait_impl(int epfd, struct epoll_event* events,
+int FakeSimpleEpollServer::epoll_wait_impl(int /*epfd*/,
+ struct epoll_event* events,
int max_events, int timeout_in_ms) {
int num_events = 0;
while (!event_queue_.empty() && num_events < max_events &&
diff --git a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h
index cd5bd3a8808..ae435881eea 100644
--- a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h
+++ b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h
@@ -95,14 +95,14 @@ class EPOLL_EXPORT_PRIVATE FakeSimpleEpollServer
protected: // functions
// These functions do nothing here, as we're not actually
// using the epoll_* syscalls.
- void DelFD(int fd) const override {}
- void AddFD(int fd, int event_mask) const override {}
- void ModFD(int fd, int event_mask) const override {}
+ void DelFD(int /*fd*/) const override {}
+ void AddFD(int /*fd*/, int /*event_mask*/) const override {}
+ void ModFD(int /*fd*/, int /*event_mask*/) const override {}
// Replaces the epoll_server's epoll_wait_impl.
int epoll_wait_impl(int epfd, struct epoll_event* events, int max_events,
int timeout_in_ms) override;
- void SetNonblocking(int fd) override {}
+ void SetNonblocking(int /*fd*/) override {}
private: // members
EventQueue event_queue_;
diff --git a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc
index 01175421107..1da05ae0a5c 100644
--- a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc
+++ b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc
@@ -87,7 +87,7 @@ class ReadPipeCallback : public EpollCallbackInterface {
data_read = read(fd, &data, sizeof(data));
}
}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
void OnRegistration(SimpleEpollServer*, int, int) override {}
void OnModification(int, int) override {} // COV_NF_LINE
void OnUnregistration(int, bool) override {} // COV_NF_LINE
@@ -790,7 +790,7 @@ void EpollAlarm::OnRegistration(const SimpleEpollServer::AlarmRegToken& token,
void EpollAlarm::OnUnregistration() { registered_ = false; }
-void EpollAlarm::OnShutdown(SimpleEpollServer* eps) {
+void EpollAlarm::OnShutdown(SimpleEpollServer* /*eps*/) {
registered_ = false;
eps_ = NULL;
}
diff --git a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc
index dbc3292f96d..9ec23666048 100644
--- a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc
+++ b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc
@@ -151,7 +151,8 @@ class RecordingCB : public EpollCallbackInterface {
delete recorder_;
}
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
+ void OnRegistration(SimpleEpollServer* /*eps*/, int fd,
+ int event_mask) override {
recorder_->Record(this, REGISTRATION, fd, event_mask);
}
@@ -565,7 +566,7 @@ class TestAlarm : public EpollAlarmCallbackInterface {
}
}
- void OnShutdown(SimpleEpollServer* eps) override {
+ void OnShutdown(SimpleEpollServer* /*eps*/) override {
onshutdown_called_ = true;
has_token_ = false;
}
@@ -657,7 +658,7 @@ class TestChildAlarm : public TestAlarm {
parent_->OnShutdown(this, eps);
}
void OnRegistration(const SimpleEpollServer::AlarmRegToken& token,
- SimpleEpollServer* eps) override {
+ SimpleEpollServer* /*eps*/) override {
parent_->OnRegistration(this, token);
}
@@ -766,7 +767,7 @@ class TestAlarmUnregister : public TestAlarm {
delete iterator_token_;
}
- void OnShutdown(SimpleEpollServer* eps) override {
+ void OnShutdown(SimpleEpollServer* /*eps*/) override {
onshutdown_called_ = true;
}
@@ -778,7 +779,7 @@ class TestAlarmUnregister : public TestAlarm {
}
void OnRegistration(const SimpleEpollServer::AlarmRegToken& token,
- SimpleEpollServer* eps) override {
+ SimpleEpollServer* /*eps*/) override {
// Multiple iterator tokens are not maintained by this code,
// so we should have reset the iterator_token in OnAlarm or
// OnUnregistration.
@@ -1562,7 +1563,7 @@ class UnregisterCB : public EpollCallbackInterface {
~UnregisterCB() override {
}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {
+ void OnShutdown(SimpleEpollServer* /*eps*/, int fd) override {
eps_->UnregisterFD(fd_);
eps_->UnregisterFD(fd);
onshutdown_called_ = true;
@@ -1572,11 +1573,11 @@ class UnregisterCB : public EpollCallbackInterface {
void set_epollserver(SimpleEpollServer* eps) { eps_ = eps; }
bool onshutdown_called() { return onshutdown_called_; }
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
std::string Name() const override { return "UnregisterCB"; }
@@ -1680,10 +1681,10 @@ class EpollReader: public EpollCallbackInterface {
~EpollReader() override {}
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
- void OnModification(int fd, int event_mask) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
void OnEvent(int fd, EpollEvent* event) override {
if (event->in_events & EPOLLIN) {
@@ -1697,9 +1698,9 @@ class EpollReader: public EpollCallbackInterface {
}
}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {
// None of the current tests involve having active callbacks when the
// server shuts down.
EPOLL_LOG(FATAL);
@@ -1934,12 +1935,12 @@ class EdgeTriggerCB : public EpollCallbackInterface {
}
}
- void OnUnregistration(int fd, bool replaced) override {
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {
EXPECT_TRUE(eps_ != nullptr);
eps_ = nullptr;
}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {
// None of the current tests involve having active callbacks when the
// server shuts down.
EPOLL_LOG(FATAL);
@@ -2068,17 +2069,17 @@ class UnRegisterWhileProcessingCB: public EpollCallbackInterface {
~UnRegisterWhileProcessingCB() override {
}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; }
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {
// This should cause no problems.
eps_->UnregisterFD(fd_);
}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
std::string Name() const override { return "UnRegisterWhileProcessingCB"; }
protected:
@@ -2094,17 +2095,17 @@ class RegisterWhileProcessingCB: public EpollCallbackInterface {
~RegisterWhileProcessingCB() override {
}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; }
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {
// This should cause no problems.
eps_->RegisterFDForReadWrite(fd_, cb_);
}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
std::string Name() const override { return "RegisterWhileProcessingCB"; }
protected:
@@ -2180,21 +2181,21 @@ TEST(SimpleEpollServerTest,
class ReRegWhileReadyListOnEvent: public EpollCallbackInterface {
public:
- explicit ReRegWhileReadyListOnEvent(int fd) : eps_(nullptr) {}
+ explicit ReRegWhileReadyListOnEvent(int /*fd*/) : eps_(nullptr) {}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; }
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int fd, EpollEvent* /*event_mask*/) override {
// This should cause no problems.
eps_->UnregisterFD(fd);
eps_->RegisterFDForReadWrite(fd, this);
eps_->UnregisterFD(fd);
}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
std::string Name() const override { return "ReRegWhileReadyListOnEvent"; }
protected:
@@ -2226,14 +2227,15 @@ class UnRegEverythingReadyListOnEvent: public EpollCallbackInterface {
void set_fd_range(int fd_range) { fd_range_ = fd_range; }
void set_num_called(int* num_called) { num_called_ = num_called; }
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; }
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
+ void OnRegistration(SimpleEpollServer* eps, int fd,
+ int /*event_mask*/) override {
eps->SetFDReady(fd, EPOLLIN);
}
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {
// This should cause no problems.
CHECK(num_called_ != nullptr);
++(*num_called_);
@@ -2247,7 +2249,7 @@ class UnRegEverythingReadyListOnEvent: public EpollCallbackInterface {
eps_->UnregisterFD(i);
}
}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
std::string Name() const override {
return "UnRegEverythingReadyListOnEvent";
}
@@ -2306,10 +2308,10 @@ class ApproximateNowInUsecTestCB: public EpollCallbackInterface {
public:
ApproximateNowInUsecTestCB() : feps_(nullptr), called_(false) {}
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {
EXPECT_EQ(feps_->ApproximateNowInUsec(), feps_->NowInUsec());
feps_->AdvanceBy(1111);
EXPECT_EQ(1 * 1111 + feps_->ApproximateNowInUsec(), feps_->NowInUsec());
@@ -2317,8 +2319,8 @@ class ApproximateNowInUsecTestCB: public EpollCallbackInterface {
EXPECT_EQ(2 * 1111 + feps_->ApproximateNowInUsec(), feps_->NowInUsec());
called_ = true;
}
- void OnUnregistration(int fd, bool replaced) override {}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
std::string Name() const override { return "ApproximateNowInUsecTestCB"; }
void set_fakeepollserver(FakeSimpleEpollServer* feps) { feps_ = feps; }
@@ -2374,18 +2376,18 @@ class RecordDelayOnEvent: public EpollCallbackInterface {
~RecordDelayOnEvent() override {
}
- void OnShutdown(SimpleEpollServer* eps, int fd) override {}
+ void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {}
std::string Name() const override { return "RecordDelayOnEvent"; }
void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; }
- void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override {
- }
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override {
+ void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/,
+ int /*event_mask*/) override {}
+ void OnModification(int /*fd*/, int /*event_mask*/) override {}
+ void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {
last_delay = eps_->LastDelayInUsec();
}
- void OnUnregistration(int fd, bool replaced) override {}
+ void OnUnregistration(int /*fd*/, bool /*replaced*/) override {}
int64_t last_delay;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc
new file mode 100644
index 00000000000..1f365c6b0da
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 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.
+
+//
+// $ blaze run -c opt --dynamic_mode=off \
+// -- //net/third_party/quiche/src/http2/hpack/huffman:hpack_huffman_encoder_benchmark \
+// --benchmarks=all --benchmark_memory_usage --benchmark_repetitions=1
+//
+// Benchmark Time(ns) CPU(ns) Allocs Iterations
+// -----------------------------------------------------------------------------
+// BM_EncodeSmallStrings 239 239 0 2456085 0.000B peak-mem
+// BM_EncodeLargeString/1k 4560 4561 5 153325 1.125kB peak-mem
+// BM_EncodeLargeString/4k 18787 18788 7 38430 4.500kB peak-mem
+// BM_EncodeLargeString/32k 147680 147657 10 4664 36.000kB peak-mem
+// BM_EncodeLargeString/256k 1161688 1161511 13 601 288.000kB peak-mem
+// BM_EncodeLargeString/2M 10042722 10036764 16 75 2.250MB peak-mem
+// BM_EncodeLargeString/16M 76127338 76138839 19 9 18.000MB peak-mem
+// BM_EncodeLargeString/128M 640008098 640154859 22 1 144.000MB peak-mem
+//
+
+#include <string>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+// This header has multiple DCHECK_* macros with signed-unsigned comparison.
+#include "testing/base/public/benchmark.h"
+#pragma clang diagnostic pop
+
+#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h"
+
+namespace http2 {
+namespace {
+
+void BM_EncodeSmallStrings(benchmark::State& state) {
+ const std::vector<const std::string> inputs{
+ ":method", ":path", "cookie", "set-cookie", "vary", "accept-encoding"};
+ for (auto s : state) {
+ for (const auto& input : inputs) {
+ std::string result;
+ ExactHuffmanSize(input);
+ HuffmanEncode(input, &result);
+ }
+ }
+}
+
+void BM_EncodeLargeString(benchmark::State& state) {
+ const std::string input(state.range(0), 'a');
+ for (auto s : state) {
+ std::string result;
+ ExactHuffmanSize(input);
+ HuffmanEncode(input, &result);
+ }
+}
+
+BENCHMARK(BM_EncodeSmallStrings);
+BENCHMARK(BM_EncodeLargeString)->Range(1024, 128 * 1024 * 1024);
+
+} // namespace
+} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc b/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc
index a8371808773..20dd0ec1cdc 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc
@@ -47,7 +47,9 @@ E IncrementEnum(E e) {
template <class T>
AssertionResult VerifyRandomCalls() {
T t1;
- Http2Random seq1;
+ // Initialize with a stable key, to avoid test flakiness.
+ Http2Random seq1(
+ "6d9a61ddf2bc1fc0b8245505a1f28e324559d8b5c9c3268f38b42b1af3287c47");
Randomize(&t1, &seq1);
T t2;
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 ade94a73feb..29cbccc97e5 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
@@ -8,6 +8,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h"
namespace quic {
@@ -39,9 +40,23 @@ WriteResult QuicBatchWriterBase::InternalWritePacket(
return WriteResult(WRITE_STATUS_MSG_TOO_BIG, EMSGSIZE);
}
- ReleaseTime release_time = SupportsReleaseTime()
- ? GetReleaseTime(options)
- : ReleaseTime{0, QuicTime::Delta::Zero()};
+ ReleaseTime release_time{0, QuicTime::Delta::Zero()};
+ if (SupportsReleaseTime()) {
+ release_time = GetReleaseTime(options);
+ if (release_time.release_time_offset >= QuicTime::Delta::Zero()) {
+ QUIC_SERVER_HISTOGRAM_TIMES(
+ "batch_writer_positive_release_time_offset",
+ release_time.release_time_offset.ToMicroseconds(), 1, 100000, 50,
+ "Duration from ideal release time to actual "
+ "release time, in microseconds.");
+ } else {
+ QUIC_SERVER_HISTOGRAM_TIMES(
+ "batch_writer_negative_release_time_offset",
+ -release_time.release_time_offset.ToMicroseconds(), 1, 100000, 50,
+ "Duration from actual release time to ideal "
+ "release time, in microseconds.");
+ }
+ }
const CanBatchResult can_batch_result =
CanBatch(buffer, buf_len, self_address, peer_address, options,
diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc
index bda5fe26080..d83b83b3389 100644
--- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc
@@ -120,18 +120,6 @@ QuicGsoBatchWriter::ReleaseTime QuicGsoBatchWriter::GetReleaseTime(
const uint64_t actual_release_time = buffered_writes().back().release_time;
const int64_t offset_ns = actual_release_time - ideal_release_time;
- if (offset_ns >= 0) {
- QUIC_SERVER_HISTOGRAM_TIMES("gso_writer_positive_release_time_offset",
- offset_ns / 1000, 1, 100000, 50,
- "Duration from ideal release time to actual "
- "release time, in microseconds.");
- } else {
- QUIC_SERVER_HISTOGRAM_TIMES("gso_writer_negative_release_time_offset",
- -offset_ns / 1000, 1, 100000, 50,
- "Duration from actual release time to ideal "
- "release time, in microseconds.");
- }
-
ReleaseTime result{actual_release_time,
QuicTime::Delta::FromMicroseconds(offset_ns / 1000)};
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 153f63e1938..605318589e3 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
@@ -211,13 +211,7 @@ void Bbr2NetworkModel::OnCongestionEventFinish(
bandwidth_sampler_.RemoveObsoletePackets(least_unacked_packet);
}
-void Bbr2NetworkModel::UpdateNetworkParameters(QuicBandwidth bandwidth,
- QuicTime::Delta rtt) {
- if (!improve_adjust_network_parameters_ && !bandwidth.IsInfinite() &&
- bandwidth > MaxBandwidth()) {
- max_bandwidth_filter_.Update(bandwidth);
- }
-
+void Bbr2NetworkModel::UpdateNetworkParameters(QuicTime::Delta rtt) {
if (!rtt.IsZero()) {
min_rtt_filter_.Update(rtt, MinRttTimestamp());
}
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 de30377d45e..8732118049e 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
@@ -326,10 +326,8 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
const Bbr2CongestionEvent& congestion_event);
// Update the model without a congestion event.
- // Max bandwidth is updated if |bandwidth| is larger than existing max
- // bandwidth. Min rtt is updated if |rtt| is non-zero and smaller than
- // existing min rtt.
- void UpdateNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt);
+ // Min rtt is updated if |rtt| is non-zero and smaller than existing min rtt.
+ void UpdateNetworkParameters(QuicTime::Delta rtt);
// Update inflight/bandwidth short-term lower bounds.
void AdaptLowerBounds(const Bbr2CongestionEvent& congestion_event);
@@ -450,10 +448,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
float pacing_gain() const { return pacing_gain_; }
void set_pacing_gain(float pacing_gain) { pacing_gain_ = pacing_gain; }
- bool improve_adjust_network_parameters() const {
- return improve_adjust_network_parameters_;
- }
-
private:
const Bbr2Params& Params() const { return *params_; }
const Bbr2Params* const params_;
@@ -485,9 +479,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
float cwnd_gain_;
float pacing_gain_;
-
- const bool improve_adjust_network_parameters_ =
- GetQuicReloadableFlag(quic_bbr2_improve_adjust_network_parameters);
};
enum class Bbr2Mode : uint8_t {
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 59e63032fcb..172911817aa 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
@@ -9,6 +9,7 @@
#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -165,18 +166,26 @@ void Bbr2ProbeBwMode::UpdateProbeDown(
QUIC_DVLOG(3)
<< sender_
<< " Checking if have enough inflight headroom. prior_in_flight:"
- << prior_in_flight
+ << prior_in_flight << " congestion_event.bytes_in_flight:"
+ << congestion_event.bytes_in_flight
<< ", inflight_with_headroom:" << inflight_with_headroom;
- if (prior_in_flight > inflight_with_headroom) {
+ QuicByteCount bytes_in_flight = prior_in_flight;
+ if (GetQuicReloadableFlag(quic_bbr2_use_post_inflight_to_detect_queuing)) {
+ // TODO(ianswett): Remove prior_in_flight from UpdateProbeDown.
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_use_post_inflight_to_detect_queuing,
+ 2, 2);
+ bytes_in_flight = congestion_event.bytes_in_flight;
+ }
+ if (bytes_in_flight > inflight_with_headroom) {
// Stay in PROBE_DOWN.
return;
}
// Transition to PROBE_CRUISE iff we've drained to target.
QuicByteCount bdp = model_->BDP(model_->MaxBandwidth());
- QUIC_DVLOG(3) << sender_ << " Checking if drained to target. prior_in_flight:"
- << prior_in_flight << ", bdp:" << bdp;
- if (prior_in_flight < bdp) {
+ QUIC_DVLOG(3) << sender_ << " Checking if drained to target. bytes_in_flight:"
+ << bytes_in_flight << ", bdp:" << bdp;
+ if (bytes_in_flight < bdp) {
EnterProbeCruise(congestion_event.event_time);
}
}
@@ -436,10 +445,18 @@ void Bbr2ProbeBwMode::UpdateProbeUp(
QuicByteCount queuing_threshold =
(Params().probe_bw_probe_inflight_gain * bdp) +
queuing_threshold_extra_bytes;
- is_queuing = prior_in_flight >= queuing_threshold;
+ if (GetQuicReloadableFlag(quic_bbr2_use_post_inflight_to_detect_queuing)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr2_use_post_inflight_to_detect_queuing, 1, 2);
+ is_queuing = congestion_event.bytes_in_flight >= queuing_threshold;
+ } else {
+ is_queuing = prior_in_flight >= queuing_threshold;
+ }
QUIC_DVLOG(3) << sender_
<< " Checking if building up a queue. prior_in_flight:"
- << prior_in_flight << ", threshold:" << queuing_threshold
+ << prior_in_flight
+ << ", post_in_flight:" << congestion_event.bytes_in_flight
+ << ", threshold:" << queuing_threshold
<< ", is_queuing:" << is_queuing
<< ", max_bw:" << model_->MaxBandwidth()
<< ", min_rtt:" << model_->MinRtt();
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 3c7ba2fc8ad..fe32835fb8f 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
@@ -13,6 +13,7 @@
#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
namespace quic {
@@ -73,8 +74,10 @@ Bbr2Sender::Bbr2Sender(QuicTime now,
/*cwnd_gain=*/1.0,
/*pacing_gain=*/kInitialPacingGain,
old_sender ? &old_sender->sampler_ : nullptr),
- initial_cwnd_(
- cwnd_limits().ApplyLimits(initial_cwnd_in_packets * kDefaultTCPMSS)),
+ initial_cwnd_(cwnd_limits().ApplyLimits(
+ (GetQuicReloadableFlag(quic_copy_bbr_cwnd_to_bbr2) && old_sender)
+ ? old_sender->GetCongestionWindow()
+ : (initial_cwnd_in_packets * kDefaultTCPMSS))),
cwnd_(initial_cwnd_),
pacing_rate_(kInitialPacingGain * QuicBandwidth::FromBytesAndTimeDelta(
cwnd_,
@@ -84,6 +87,10 @@ Bbr2Sender::Bbr2Sender(QuicTime now,
probe_bw_(this, &model_),
probe_rtt_(this, &model_),
last_sample_is_app_limited_(false) {
+ if (GetQuicReloadableFlag(quic_copy_bbr_cwnd_to_bbr2) && old_sender) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_copy_bbr_cwnd_to_bbr2);
+ }
+
QUIC_DVLOG(2) << this << " Initializing Bbr2Sender. mode:" << mode_
<< ", PacingRate:" << pacing_rate_ << ", Cwnd:" << cwnd_
<< ", CwndLimits:" << cwnd_limits() << " @ " << now;
@@ -115,9 +122,7 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config,
QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fewer_startup_round_trips, 2, 2);
params_.startup_full_bw_rounds = 2;
}
- if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_lo) &&
- config.HasClientRequestedIndependentOption(kB2LO, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_lo);
+ if (config.HasClientRequestedIndependentOption(kB2LO, perspective)) {
params_.ignore_inflight_lo = true;
}
if (GetQuicReloadableFlag(quic_bbr2_limit_inflight_hi) &&
@@ -125,6 +130,11 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config,
QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_limit_inflight_hi);
params_.limit_inflight_hi_by_cwnd = true;
}
+ if (GetQuicReloadableFlag(quic_bbr2_use_tcp_inflight_hi_headroom) &&
+ config.HasClientRequestedIndependentOption(kB2HR, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_use_tcp_inflight_hi_headroom);
+ params_.inflight_hi_headroom = 0.15;
+ }
ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
}
@@ -162,33 +172,21 @@ const Limits<QuicByteCount>& Bbr2Sender::cwnd_limits() const {
}
void Bbr2Sender::AdjustNetworkParameters(const NetworkParams& params) {
- model_.UpdateNetworkParameters(params.bandwidth, params.rtt);
+ model_.UpdateNetworkParameters(params.rtt);
if (mode_ == Bbr2Mode::STARTUP) {
const QuicByteCount prior_cwnd = cwnd_;
- if (model_.improve_adjust_network_parameters()) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_improve_adjust_network_parameters);
- QuicBandwidth effective_bandwidth =
- std::max(params.bandwidth, model_.BandwidthEstimate());
- cwnd_ = cwnd_limits().ApplyLimits(model_.BDP(effective_bandwidth));
- } else {
- // Normally UpdateCongestionWindow updates |cwnd_| towards the target by a
- // small step per congestion event, by changing |cwnd_| to the bdp at here
- // we are reducing the number of updates needed to arrive at the target.
- cwnd_ = model_.BDP(model_.BandwidthEstimate());
- UpdateCongestionWindow(0);
- }
+ QuicBandwidth effective_bandwidth =
+ std::max(params.bandwidth, model_.BandwidthEstimate());
+ cwnd_ = cwnd_limits().ApplyLimits(model_.BDP(effective_bandwidth));
if (!params.allow_cwnd_to_decrease) {
cwnd_ = std::max(cwnd_, prior_cwnd);
}
- if (model_.improve_adjust_network_parameters()) {
- pacing_rate_ = std::max(
- pacing_rate_,
- QuicBandwidth::FromBytesAndTimeDelta(cwnd_, model_.MinRtt()));
- }
+ pacing_rate_ = std::max(pacing_rate_, QuicBandwidth::FromBytesAndTimeDelta(
+ cwnd_, model_.MinRtt()));
}
}
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 1ff703d0953..1f5db20c892 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
@@ -449,9 +449,6 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) {
TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) {
SetConnectionOption(kBSAO);
- // Enable Ack Decimation on the receiver.
- QuicConnectionPeer::SetAckMode(receiver_endpoint_.connection(),
- AckMode::ACK_DECIMATION);
DefaultTopologyParams params;
CreateNetwork(params);
@@ -664,10 +661,10 @@ TEST_F(Bbr2DefaultTopologyTest, InFlightAwareGainCycling) {
}
// Now that in-flight is almost zero and the pacing gain is still above 1,
- // send approximately 1.25 BDPs worth of data. This should cause the
- // PROBE_BW mode to enter low gain cycle(PROBE_DOWN), and exit it earlier than
- // one min_rtt due to running out of data to send.
- sender_endpoint_.AddBytesToTransfer(1.3 * params.BDP());
+ // send approximately 1.4 BDPs worth of data. This should cause the PROBE_BW
+ // mode to enter low gain cycle(PROBE_DOWN), and exit it earlier than one
+ // min_rtt due to running out of data to send.
+ sender_endpoint_.AddBytesToTransfer(1.4 * params.BDP());
simulator_result = simulator_.RunUntilOrTimeout(
[this]() {
return sender_->ExportDebugState().probe_bw.phase ==
@@ -915,7 +912,7 @@ TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) {
BbrSender old_sender(sender_connection()->clock()->Now(),
sender_connection()->sent_packet_manager().GetRttStats(),
GetUnackedMap(sender_connection()),
- kDefaultInitialCwndPackets,
+ kDefaultInitialCwndPackets + 1,
GetQuicFlag(FLAGS_quic_max_congestion_window), &random_,
QuicConnectionPeer::GetStats(sender_connection()));
@@ -930,7 +927,11 @@ TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) {
}
// Switch from |old_sender| to |sender_|.
+ const QuicByteCount old_sender_cwnd = old_sender.GetCongestionWindow();
sender_ = SetupBbr2Sender(&sender_endpoint_, &old_sender);
+ if (GetQuicReloadableFlag(quic_copy_bbr_cwnd_to_bbr2)) {
+ EXPECT_EQ(old_sender_cwnd, sender_->GetCongestionWindow());
+ }
// Send packets 5-7.
now = now + QuicTime::Delta::FromMilliseconds(10);
@@ -1007,13 +1008,9 @@ TEST_F(Bbr2DefaultTopologyTest, AdjustNetworkParameters) {
EXPECT_EQ(params.BDP(), sender_->ExportDebugState().congestion_window);
- if (GetQuicReloadableFlag(quic_bbr2_improve_adjust_network_parameters)) {
- EXPECT_EQ(params.BottleneckBandwidth(),
- sender_->PacingRate(/*bytes_in_flight=*/0));
- EXPECT_NE(params.BottleneckBandwidth(), sender_->BandwidthEstimate());
- } else {
- EXPECT_EQ(params.BottleneckBandwidth(), sender_->BandwidthEstimate());
- }
+ EXPECT_EQ(params.BottleneckBandwidth(),
+ sender_->PacingRate(/*bytes_in_flight=*/0));
+ EXPECT_NE(params.BottleneckBandwidth(), sender_->BandwidthEstimate());
EXPECT_APPROX_EQ(params.RTT(), sender_->ExportDebugState().min_rtt, 0.01f);
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc
index 7389067fed7..2948272d737 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc
@@ -112,7 +112,6 @@ BbrSender::BbrSender(QuicTime now,
probe_rtt_round_passed_(false),
last_sample_is_app_limited_(false),
has_non_app_limited_sample_(false),
- flexible_app_limited_(false),
recovery_state_(NOT_IN_RECOVERY),
recovery_window_(max_congestion_window_),
slower_startup_(false),
@@ -219,12 +218,7 @@ bool BbrSender::ShouldSendProbingPacket() const {
// TODO(b/77975811): If the pipe is highly under-utilized, consider not
// sending a probing transmission, because the extra bandwidth is not needed.
- // If flexible_app_limited is enabled, check if the pipe is sufficiently full.
- if (flexible_app_limited_) {
- return !IsPipeSufficientlyFull();
- } else {
- return true;
- }
+ return true;
}
bool BbrSender::IsPipeSufficientlyFull() const {
@@ -268,11 +262,6 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
if (config.HasClientRequestedIndependentOption(kBBR5, perspective)) {
sampler_.SetMaxAckHeightTrackerWindowLength(4 * kBandwidthWindowSize);
}
- if (GetQuicReloadableFlag(quic_bbr_flexible_app_limited) &&
- config.HasClientRequestedIndependentOption(kBBR9, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_flexible_app_limited);
- flexible_app_limited_ = true;
- }
if (config.HasClientRequestedIndependentOption(kBBQ1, perspective)) {
set_high_gain(kDerivedHighGain);
set_high_cwnd_gain(kDerivedHighGain);
@@ -291,9 +280,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
max_congestion_window_with_network_parameters_adjusted_ =
100 * kDefaultTCPMSS;
}
- if (GetQuicReloadableFlag(quic_enable_overshooting_detection) &&
- config.HasClientRequestedIndependentOption(kDTOS, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_enable_overshooting_detection);
+ if (config.HasClientRequestedIndependentOption(kDTOS, perspective)) {
detect_overshooting_ = true;
// DTOS would allow pacing rate drop to IW 10 / min_rtt if overshooting is
// detected.
@@ -887,9 +874,6 @@ void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) {
if (bytes_in_flight >= GetCongestionWindow()) {
return;
}
- if (flexible_app_limited_ && IsPipeSufficientlyFull()) {
- return;
- }
sampler_.OnAppLimited();
QUIC_DVLOG(2) << "Becoming application limited. Last sent packet: "
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h
index d89e3fecdfd..ae6cce9a393 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h
@@ -354,9 +354,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
bool last_sample_is_app_limited_;
// Indicates whether any non app-limited samples have been recorded.
bool has_non_app_limited_sample_;
- // Indicates app-limited calls should be ignored as long as there's
- // enough data inflight to see more bandwidth when necessary.
- bool flexible_app_limited_;
// Current state of recovery.
RecoveryState recovery_state_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc
index 0e94b6b73da..b476b557a47 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc
@@ -292,8 +292,6 @@ TEST_F(BbrSenderTest, SetInitialCongestionWindow) {
// Test a simple long data transfer in the default setup.
TEST_F(BbrSenderTest, SimpleTransfer) {
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
// At startup make sure we are at the default.
@@ -341,8 +339,6 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) {
}
TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) {
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
DriveOutOfStartup();
@@ -421,9 +417,6 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
GetQuicFlag(FLAGS_quic_max_congestion_window), &random_,
QuicConnectionPeer::GetStats(bbr_sender_.connection()));
QuicConnectionPeer::SetSendAlgorithm(bbr_sender_.connection(), sender_);
- // Enable Ack Decimation on the receiver.
- QuicConnectionPeer::SetAckMode(receiver_.connection(),
- AckMode::ACK_DECIMATION);
CreateDefaultSetup();
// Transfer 12MB.
@@ -445,8 +438,6 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) {
SetConnectionOption(kBSAO);
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
SetConnectionOption(kBBR4);
// 2 RTTs of aggregation, with a max of 10kb.
@@ -471,8 +462,6 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) {
SetConnectionOption(kBSAO);
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
SetConnectionOption(kBBR5);
// 2 RTTs of aggregation, with a max of 10kb.
@@ -590,8 +579,6 @@ TEST_F(BbrSenderTest, ApplicationLimitedBurstsWithoutPrior) {
// Verify that the DRAIN phase works correctly.
TEST_F(BbrSenderTest, Drain) {
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
// Get the queue at the bottleneck, which is the outgoing queue at the port to
@@ -654,10 +641,6 @@ TEST_F(BbrSenderTest, Drain) {
// TODO(wub): Re-enable this test once default drain_gain changed to 0.75.
// Verify that the DRAIN phase works correctly.
TEST_F(BbrSenderTest, DISABLED_ShallowDrain) {
- // TODO(haoyuewang) Remove this when TCP_ACKING is deprecated.
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
-
CreateDefaultSetup();
const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
// Get the queue at the bottleneck, which is the outgoing queue at the port to
@@ -746,8 +729,6 @@ TEST_F(BbrSenderTest, ProbeRtt) {
// bandwidth will not exit high gain phase, and similarly ensure that the
// connection will exit low gain early if the number of bytes in flight is low.
TEST_F(BbrSenderTest, InFlightAwareGainCycling) {
- // Disable Ack Decimation on the receiver, because it can increase srtt.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
DriveOutOfStartup();
@@ -987,9 +968,6 @@ TEST_F(BbrSenderTest, DerivedCWNDGainStartup) {
}
TEST_F(BbrSenderTest, AckAggregationInStartup) {
- // Disable Ack Decimation on the receiver to avoid loss and make results
- // consistent.
- QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
SetConnectionOption(kBBQ3);
@@ -1299,9 +1277,6 @@ TEST_F(BbrSenderTest, LossOnlyCongestionEvent) {
}
TEST_F(BbrSenderTest, EnableOvershootingDetection) {
- if (!GetQuicReloadableFlag(quic_enable_overshooting_detection)) {
- return;
- }
SetConnectionOption(kDTOS);
CreateSmallBufferSetup();
// Set a overly large initial cwnd.
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
index 9124e49d2ae..42b97bf89f8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -43,7 +43,7 @@ class GeneralLossAlgorithmTest : public QuicTest {
encrypted_length, false, false);
packet.retransmittable_frames.push_back(QuicFrame(frame));
unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(),
- true);
+ true, true);
}
void SendDataPacket(uint64_t packet_number) {
@@ -55,7 +55,7 @@ class GeneralLossAlgorithmTest : public QuicTest {
PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
true, false);
unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(),
- false);
+ false, true);
}
void VerifyLosses(uint64_t largest_newly_acked,
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
index 458152f024a..7a9d37ee107 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -53,7 +53,7 @@ class UberLossAlgorithmTest : public QuicTest {
packet.encryption_level = encryption_level;
packet.retransmittable_frames.push_back(QuicFrame(frame));
unacked_packets_->AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(),
- true);
+ true, true);
}
void AckPackets(const std::vector<uint64_t>& packets_acked) {
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 4ebdd2e05ef..bf3a97ca891 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
@@ -96,8 +96,7 @@ const QuicTag kBBR3 = TAG('B', 'B', 'R', '3'); // Fully drain the queue once
// per cycle
const QuicTag kBBR4 = TAG('B', 'B', 'R', '4'); // 20 RTT ack aggregation
const QuicTag kBBR5 = TAG('B', 'B', 'R', '5'); // 40 RTT ack aggregation
-const QuicTag kBBR9 = TAG('B', 'B', 'R', '9'); // Ignore app-limited calls in
- // BBR if enough inflight.
+const QuicTag kBBR9 = TAG('B', 'B', 'R', '9'); // DEPRECATED
const QuicTag kBBRS = TAG('B', 'B', 'R', 'S'); // DEPRECATED
const QuicTag kBBQ1 = TAG('B', 'B', 'Q', '1'); // BBR with lower 2.77 STARTUP
// pacing and CWND gain.
@@ -127,6 +126,7 @@ const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW
const QuicTag kB2LO = TAG('B', '2', 'L', 'O'); // Ignore inflight_lo in BBR2
const QuicTag kB2HI = TAG('B', '2', 'H', 'I'); // Limit inflight_hi reduction
// based on CWND.
+const QuicTag kB2HR = TAG('B', '2', 'H', 'R'); // 15% inflight_hi headroom.
const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in
// Bandwidth Sampler with ack
// aggregation
@@ -160,6 +160,7 @@ const QuicTag kAKDU = TAG('A', 'K', 'D', 'U'); // Unlimited number of packets
// received before acking
const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after
// 1 RTT of not receiving.
+const QuicTag kAFFE = TAG('A', 'F', 'F', 'E'); // AckFrequencyFrame Enabled.
const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction.
const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR
const QuicTag k2RTO = TAG('2', 'R', 'T', 'O'); // Close connection on 2 RTOs
@@ -299,6 +300,9 @@ const QuicTag kFIDT = TAG('F', 'I', 'D', 'T'); // Extend idle timer by PTO
// instead of the whole idle
// timeout.
+const QuicTag k3AFF = TAG('3', 'A', 'F', 'F'); // 3 anti amplification factor.
+const QuicTag k10AF = TAG('1', '0', 'A', 'F'); // 10 anti amplification factor.
+
// Enable path MTU discovery experiment.
const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery.
const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
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 fe1a5ee86b8..365fb120d19 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
@@ -691,6 +691,30 @@ const char* CryptoUtils::HandshakeFailureReasonToString(
}
// static
+const char* CryptoUtils::EarlyDataReasonToString(
+ ssl_early_data_reason_t reason) {
+ switch (reason) {
+ RETURN_STRING_LITERAL(ssl_early_data_unknown);
+ RETURN_STRING_LITERAL(ssl_early_data_disabled);
+ RETURN_STRING_LITERAL(ssl_early_data_accepted);
+ RETURN_STRING_LITERAL(ssl_early_data_protocol_version);
+ RETURN_STRING_LITERAL(ssl_early_data_peer_declined);
+ RETURN_STRING_LITERAL(ssl_early_data_no_session_offered);
+ RETURN_STRING_LITERAL(ssl_early_data_session_not_resumed);
+ RETURN_STRING_LITERAL(ssl_early_data_unsupported_for_session);
+ RETURN_STRING_LITERAL(ssl_early_data_hello_retry_request);
+ RETURN_STRING_LITERAL(ssl_early_data_alpn_mismatch);
+ RETURN_STRING_LITERAL(ssl_early_data_channel_id);
+ RETURN_STRING_LITERAL(ssl_early_data_token_binding);
+ RETURN_STRING_LITERAL(ssl_early_data_ticket_age_skew);
+ RETURN_STRING_LITERAL(ssl_early_data_quic_parameter_mismatch);
+ }
+ QUIC_BUG_IF(reason < 0 || reason > ssl_early_data_reason_max_value)
+ << "Unknown ssl_early_data_reason_t " << reason;
+ return "unknown ssl_early_data_reason_t";
+}
+
+// static
std::string CryptoUtils::HashHandshakeMessage(
const CryptoHandshakeMessage& message,
Perspective /*perspective*/) {
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 6c167f8f694..964f81fdf69 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
@@ -12,6 +12,7 @@
#include <string>
#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
@@ -211,6 +212,9 @@ class QUIC_EXPORT_PRIVATE CryptoUtils {
static const char* HandshakeFailureReasonToString(
HandshakeFailureReason reason);
+ // Returns the name of an ssl_early_data_reason_t as a char*
+ static const char* EarlyDataReasonToString(ssl_early_data_reason_t reason);
+
// Returns a hash of the serialized |message|.
static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message,
Perspective perspective);
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc
index 73f16721821..3a980296a96 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc
@@ -8,9 +8,26 @@
namespace quic {
+CryptoBuffers::~CryptoBuffers() {
+ for (size_t i = 0; i < value.size(); i++) {
+ CRYPTO_BUFFER_free(value[i]);
+ }
+}
+
ProofSource::Chain::Chain(const std::vector<std::string>& certs)
: certs(certs) {}
ProofSource::Chain::~Chain() {}
+CryptoBuffers ProofSource::Chain::ToCryptoBuffers() const {
+ CryptoBuffers crypto_buffers;
+ crypto_buffers.value.reserve(certs.size());
+ for (size_t i = 0; i < certs.size(); i++) {
+ crypto_buffers.value.push_back(
+ CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(certs[i].data()),
+ certs[i].length(), nullptr));
+ }
+ return crypto_buffers;
+}
+
} // 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 c4224f46607..637dd0c33c5 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
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -18,6 +19,17 @@
namespace quic {
+// CryptoBuffers is a RAII class to own a std::vector<CRYPTO_BUFFER*> and the
+// buffers the elements point to.
+struct QUIC_EXPORT_PRIVATE CryptoBuffers {
+ CryptoBuffers() = default;
+ CryptoBuffers(const CryptoBuffers&) = delete;
+ CryptoBuffers(CryptoBuffers&&) = default;
+ ~CryptoBuffers();
+
+ std::vector<CRYPTO_BUFFER*> value;
+};
+
// ProofSource is an interface by which a QUIC server can obtain certificate
// chains and signatures that prove its identity.
class QUIC_EXPORT_PRIVATE ProofSource {
@@ -29,6 +41,8 @@ class QUIC_EXPORT_PRIVATE ProofSource {
Chain(const Chain&) = delete;
Chain& operator=(const Chain&) = delete;
+ CryptoBuffers ToCryptoBuffers() const;
+
const std::vector<std::string> certs;
protected:
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 5835e944dca..ec535cfa7c6 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
@@ -47,6 +47,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_testvalue.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
@@ -797,6 +798,11 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
return;
}
+ // Allow testing a specific adversarial case in which a client sends a public
+ // value of incorrect size.
+ AdjustTestValue("quic::QuicCryptoServerConfig::public_value_adjust",
+ &public_value);
+
const AsynchronousKeyExchange* key_exchange =
configs.requested->key_exchanges[key_exchange_index].get();
std::string* initial_premaster_secret =
@@ -824,9 +830,11 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
<< QuicVersionToString(context->transport_version());
if (found_error) {
- // If we are already using the fallback config, just bail out of the
- // handshake.
- if (context->signed_config()->config == configs.fallback ||
+ // If we are already using the fallback config, or there is no fallback
+ // config to use, just bail out of the handshake.
+ if ((GetQuicReloadableFlag(quic_check_fallback_null) &&
+ configs.fallback == nullptr) ||
+ context->signed_config()->config == configs.fallback ||
!GetQuicReloadableFlag(
send_quic_fallback_server_config_on_leto_error)) {
context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
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 0e59997d438..c821a388748 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
@@ -24,16 +24,13 @@ bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx(
SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr);
// We don't actually need the TicketCrypter here, but we need to know
// whether it's set.
- if (GetQuicRestartFlag(quic_enable_tls_resumption_v4) &&
- proof_source->GetTicketCrypter()) {
+ if (proof_source->GetTicketCrypter()) {
SSL_CTX_set_ticket_aead_method(ssl_ctx.get(),
&TlsServerConnection::kSessionTicketMethod);
- QUIC_CODE_COUNT_N(quic_tls_resumption_ticket_method, 1, 2);
if (GetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2)) {
SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
}
} else {
- QUIC_CODE_COUNT_N(quic_tls_resumption_ticket_method, 2, 2);
SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET);
}
return ssl_ctx;
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc
index b8c7efafa98..1486327cb18 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc
@@ -8,6 +8,16 @@
namespace quic {
+QuicAckFrequencyFrame::QuicAckFrequencyFrame(
+ QuicControlFrameId control_frame_id,
+ uint64_t sequence_number,
+ uint64_t packet_tolerance,
+ QuicTime::Delta max_ack_delay)
+ : control_frame_id(control_frame_id),
+ sequence_number(sequence_number),
+ packet_tolerance(packet_tolerance),
+ max_ack_delay(max_ack_delay) {}
+
std::ostream& operator<<(std::ostream& os, const QuicAckFrequencyFrame& frame) {
os << "{ control_frame_id: " << frame.control_frame_id
<< ", sequence_number: " << frame.sequence_number
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h
index 52b70daff2e..3f9397c2f8c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h
@@ -21,8 +21,14 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrequencyFrame {
std::ostream& os,
const QuicAckFrequencyFrame& ack_frequency_frame);
- // A unique identifier of this control frame. 0 when this frame is received,
- // and non-zero when sent.
+ QuicAckFrequencyFrame() = default;
+ QuicAckFrequencyFrame(QuicControlFrameId control_frame_id,
+ uint64_t sequence_number,
+ uint64_t packet_tolerance,
+ QuicTime::Delta max_ack_delay);
+
+ // A unique identifier of this control frame. 0 when this frame is
+ // received, and non-zero when sent.
QuicControlFrameId control_frame_id = kInvalidControlFrameId;
// If true, do not ack immediately upon observeation of packet reordering.
@@ -34,10 +40,11 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrequencyFrame {
// The maximum number of ack-eliciting packets after which the receiver sends
// an acknowledgement. Invald if == 0.
- uint64_t packet_tolerance = 0;
+ uint64_t packet_tolerance = 2;
// The maximum time that ack packets can be delayed.
- QuicTime::Delta max_ack_delay = QuicTime::Delta::Zero();
+ QuicTime::Delta max_ack_delay =
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc
index 99b0963a2dc..7fe322dffaf 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc
@@ -87,6 +87,16 @@ void DeleteFrames(QuicFrames* frames) {
}
void DeleteFrame(QuicFrame* frame) {
+#if QUIC_FRAME_DEBUG
+ // If the frame is not inlined, check that it can be safely deleted.
+ if (frame->type != PADDING_FRAME && frame->type != MTU_DISCOVERY_FRAME &&
+ frame->type != PING_FRAME && frame->type != MAX_STREAMS_FRAME &&
+ frame->type != STOP_WAITING_FRAME &&
+ frame->type != STREAMS_BLOCKED_FRAME && frame->type != STREAM_FRAME &&
+ frame->type != HANDSHAKE_DONE_FRAME) {
+ CHECK(!frame->delete_forbidden) << *frame;
+ }
+#endif // QUIC_FRAME_DEBUG
switch (frame->type) {
// Frames smaller than a pointer are inlined, so don't need to be deleted.
case PADDING_FRAME:
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h
index b5785b8bc7f..6e096e3d91c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h
@@ -36,6 +36,14 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#ifndef QUIC_FRAME_DEBUG
+#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
+#define QUIC_FRAME_DEBUG 1
+#else // !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
+#define QUIC_FRAME_DEBUG 0
+#endif // !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
+#endif // QUIC_FRAME_DEBUG
+
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicFrame {
@@ -87,6 +95,10 @@ struct QUIC_EXPORT_PRIVATE QuicFrame {
struct {
QuicFrameType type;
+#if QUIC_FRAME_DEBUG
+ bool delete_forbidden = false;
+#endif // QUIC_FRAME_DEBUG
+
// TODO(wub): These frames can also be inlined without increasing the size
// of QuicFrame: QuicRstStreamFrame, QuicWindowUpdateFrame,
// QuicBlockedFrame, QuicPathResponseFrame, QuicPathChallengeFrame and
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc
index 3f04c8c0704..3177b0cc191 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc
@@ -95,11 +95,14 @@ TEST_F(QuicFramesTest, StopSendingFrameToString) {
SetControlFrameId(1, &frame);
EXPECT_EQ(1u, GetControlFrameId(frame));
stop_sending.stream_id = 321;
- stop_sending.application_error_code = QUIC_STREAM_CANCELLED;
+ stop_sending.error_code = QUIC_STREAM_CANCELLED;
+ stop_sending.ietf_error_code =
+ static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED);
std::ostringstream stream;
stream << stop_sending;
EXPECT_EQ(
- "{ control_frame_id: 1, stream_id: 321, application_error_code: 6 }\n",
+ "{ control_frame_id: 1, stream_id: 321, error_code: 6, ietf_error_code: "
+ "268 }\n",
stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc
index c4d732ed44d..20281e522b1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc
@@ -6,18 +6,26 @@
namespace quic {
-QuicStopSendingFrame::QuicStopSendingFrame(
- QuicControlFrameId control_frame_id,
- QuicStreamId stream_id,
- QuicApplicationErrorCode application_error_code)
+QuicStopSendingFrame::QuicStopSendingFrame(QuicControlFrameId control_frame_id,
+ QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code)
: control_frame_id(control_frame_id),
stream_id(stream_id),
- application_error_code(application_error_code) {}
+ error_code(error_code),
+ ietf_error_code(
+ GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)
+ ? RstStreamErrorCodeToIetfResetStreamErrorCode(error_code)
+ : static_cast<uint64_t>(error_code)) {
+ if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_stop_sending_uses_ietf_error_code, 1, 2);
+ }
+}
std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) {
os << "{ control_frame_id: " << frame.control_frame_id
<< ", stream_id: " << frame.stream_id
- << ", application_error_code: " << frame.application_error_code << " }\n";
+ << ", error_code: " << frame.error_code
+ << ", ietf_error_code: " << frame.ietf_error_code << " }\n";
return os;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h
index 8222067d276..57114d77c56 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h
@@ -17,7 +17,7 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
QuicStopSendingFrame() = default;
QuicStopSendingFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
- QuicApplicationErrorCode application_error_code);
+ QuicRstStreamErrorCode error_code);
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os,
@@ -27,7 +27,14 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
// and non-zero when sent.
QuicControlFrameId control_frame_id = kInvalidControlFrameId;
QuicStreamId stream_id = 0;
- QuicApplicationErrorCode application_error_code = 0;
+
+ // For an outgoing frame, the error code generated by the application that
+ // determines |ietf_error_code| to be sent on the wire; for an incoming frame,
+ // the error code inferred from |ietf_error_code| received on the wire.
+ QuicRstStreamErrorCode error_code = QUIC_STREAM_NO_ERROR;
+
+ // On-the-wire application error code of the frame.
+ uint64_t ietf_error_code = 0;
};
} // 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 d72471fb687..5103509d06e 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
@@ -58,7 +58,7 @@ class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface {
// Called when 0-RTT data is rejected by the server. This is only called in
// TLS handshakes and only called on clients.
- virtual void OnZeroRttRejected() = 0;
+ virtual void OnZeroRttRejected(int reason) = 0;
// Fills in |params| with values from the delegate's QuicConfig.
// Returns whether the operation succeeded.
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 cfb76718004..7a0bd9a7823 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
@@ -199,9 +199,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
AddToCache("/foo", 200, kFooResponseBody);
AddToCache("/bar", 200, kBarResponseBody);
// Enable fixes for bugs found in tests and prod.
- SetQuicReloadableFlag(quic_fix_packet_number_length, true);
- SetQuicRestartFlag(quic_enable_tls_resumption_v4, true);
SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true);
+ SetQuicReloadableFlag(quic_fix_out_of_order_sending2, true);
}
~EndToEndTest() override { QuicRecyclePort(server_address_.port()); }
@@ -531,8 +530,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
if (server_connection != nullptr) {
QuicConnectionStats server_stats = server_connection->GetStats();
if (!had_packet_loss) {
- EXPECT_EQ(0u, server_stats.packets_lost -
- server_stats.packet_spuriously_detected_lost);
+ EXPECT_EQ(0u, server_stats.packets_lost);
}
EXPECT_EQ(0u, server_stats.packets_discarded);
EXPECT_EQ(server_session->user_agent_id().value_or("MissingUserAgent"),
@@ -1497,7 +1495,6 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
EXPECT_FALSE(client_session->ReceivedInchoateReject());
EXPECT_FALSE(client_->client()->EarlyDataAccepted());
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
-
VerifyCleanConnection(false);
}
@@ -1608,7 +1605,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
}
// This is a regression test for b/162595387
-TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) {
+TEST_P(EndToEndTest, PostZeroRTTRequestDuringHandshake) {
if (!version_.UsesTls()) {
// This test is TLS specific.
ASSERT_TRUE(Initialize());
@@ -1620,15 +1617,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) {
connection_debug_visitor_ = &visitor;
ASSERT_TRUE(Initialize());
- std::string body(20480, 'a');
- SpdyHeaderBlock headers;
- headers[":method"] = "POST";
- headers[":path"] = "/foo";
- headers[":scheme"] = "https";
- headers[":authority"] = server_hostname_;
-
- EXPECT_EQ(kFooResponseBody,
- client_->SendCustomSynchronousRequest(headers, body));
+ SendSynchronousFooRequestAndCheckResponse();
QuicSpdyClientSession* client_session = GetClientSession();
ASSERT_TRUE(client_session);
EXPECT_FALSE(client_session->EarlyDataAccepted());
@@ -1640,8 +1629,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) {
// The 0-RTT handshake should succeed.
ON_CALL(visitor, OnCryptoFrame(_))
- .WillByDefault(Invoke([this, &headers,
- &body](const QuicCryptoFrame& frame) {
+ .WillByDefault(Invoke([this](const QuicCryptoFrame& frame) {
if (frame.level != ENCRYPTION_HANDSHAKE) {
return;
}
@@ -1654,9 +1642,14 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) {
EXPECT_TRUE(
GetClientConnection()->framer().HasEncrypterOfEncryptionLevel(
ENCRYPTION_HANDSHAKE));
- EXPECT_GT(client_->SendMessage(headers, body, /*fin*/ true,
- /*flush*/ false),
- 0);
+ SpdyHeaderBlock headers;
+ headers[":method"] = "POST";
+ headers[":path"] = "/foo";
+ headers[":scheme"] = "https";
+ headers[":authority"] = server_hostname_;
+ EXPECT_GT(
+ client_->SendMessage(headers, "", /*fin*/ true, /*flush*/ false),
+ 0);
}));
client_->Connect();
ASSERT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
@@ -1671,6 +1664,65 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) {
EXPECT_TRUE(client_->client()->EarlyDataAccepted());
}
+// Regression test for b/166836136.
+TEST_P(EndToEndTest, RetransmissionAfterZeroRTTRejectBeforeOneRtt) {
+ if (!version_.UsesTls()) {
+ // This test is TLS specific.
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ // Send a request and then disconnect. This prepares the client to attempt
+ // a 0-RTT handshake for the next request.
+ NiceMock<MockQuicConnectionDebugVisitor> visitor;
+ connection_debug_visitor_ = &visitor;
+ ASSERT_TRUE(Initialize());
+
+ SendSynchronousFooRequestAndCheckResponse();
+ QuicSpdyClientSession* client_session = GetClientSession();
+ ASSERT_TRUE(client_session);
+ EXPECT_FALSE(client_session->EarlyDataAccepted());
+ EXPECT_FALSE(client_session->ReceivedInchoateReject());
+ EXPECT_FALSE(client_->client()->EarlyDataAccepted());
+ EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
+
+ client_->Disconnect();
+
+ client_->Connect();
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ ASSERT_TRUE(client_->client()->connected());
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+
+ client_session = GetClientSession();
+ ASSERT_TRUE(client_session);
+ EXPECT_TRUE(client_session->EarlyDataAccepted());
+ EXPECT_TRUE(client_->client()->EarlyDataAccepted());
+
+ client_->Disconnect();
+
+ // Restart the server so that the 0-RTT handshake will take 1 RTT.
+ StopServer();
+ server_writer_ = new PacketDroppingTestWriter();
+ StartServer();
+
+ ON_CALL(visitor, OnZeroRttRejected(_)).WillByDefault(Invoke([this]() {
+ EXPECT_FALSE(GetClientSession()->IsEncryptionEstablished());
+ // Trigger an OnCanWrite() to make sure no unencrypted data will be written.
+ GetClientSession()->OnCanWrite();
+ }));
+
+ // The 0-RTT handshake should fail.
+ client_->Connect();
+ ASSERT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ client_->WaitForWriteToFlush();
+ client_->WaitForResponse();
+ ASSERT_TRUE(client_->client()->connected());
+
+ client_session = GetClientSession();
+ ASSERT_TRUE(client_session);
+ EXPECT_FALSE(client_session->EarlyDataAccepted());
+ EXPECT_FALSE(client_->client()->EarlyDataAccepted());
+}
+
TEST_P(EndToEndTest, RejectWithPacketLoss) {
// In this test, we intentionally drop the first packet from the
// server, which corresponds with the initial REJ response from
@@ -2108,10 +2160,17 @@ TEST_P(EndToEndTest, MaxInitialRTT) {
client_sent_packet_manager->GetRttStats()->smoothed_rtt().IsInfinite());
const RttStats* server_rtt_stats =
server_sent_packet_manager->GetRttStats();
- EXPECT_EQ(static_cast<int64_t>(kMaxInitialRoundTripTimeUs),
- server_rtt_stats->initial_rtt().ToMicroseconds());
- EXPECT_GE(static_cast<int64_t>(kMaxInitialRoundTripTimeUs),
- server_rtt_stats->smoothed_rtt().ToMicroseconds());
+ if (GetQuicReloadableFlag(quic_cap_large_client_initial_rtt)) {
+ EXPECT_EQ(static_cast<int64_t>(1 * kNumMicrosPerSecond),
+ server_rtt_stats->initial_rtt().ToMicroseconds());
+ EXPECT_GE(static_cast<int64_t>(1 * kNumMicrosPerSecond),
+ server_rtt_stats->smoothed_rtt().ToMicroseconds());
+ } else {
+ EXPECT_EQ(static_cast<int64_t>(kMaxInitialRoundTripTimeUs),
+ server_rtt_stats->initial_rtt().ToMicroseconds());
+ EXPECT_GE(static_cast<int64_t>(kMaxInitialRoundTripTimeUs),
+ server_rtt_stats->smoothed_rtt().ToMicroseconds());
+ }
} else {
ADD_FAILURE() << "Missing sent packet manager";
}
@@ -2606,7 +2665,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) {
if (!version_.UsesHttp3()) {
SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION);
SpdySettingsIR settings_frame;
- settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE,
+ settings_frame.AddSetting(spdy::SETTINGS_MAX_HEADER_LIST_SIZE,
kDefaultMaxUncompressedHeaderSize);
SpdySerializedFrame frame(spdy_framer.SerializeFrame(settings_frame));
@@ -3103,7 +3162,6 @@ TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) {
QuicSession* session = GetClientSession();
ASSERT_TRUE(session);
// Verify canceled stream does not become zombie.
- EXPECT_TRUE(QuicSessionPeer::zombie_streams(session).empty());
EXPECT_EQ(1u, QuicSessionPeer::closed_streams(session).size());
}
@@ -4353,86 +4411,6 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
EXPECT_TRUE(client_->client()->EarlyDataAccepted());
}
-// This observer is used to check whether stream write side is closed when
-// receiving STOP_SENDING (which ends up as noop).
-class StopSendingObserver : public QuicConnectionDebugVisitor {
- public:
- explicit StopSendingObserver(QuicTestClient* client)
- : num_stop_sending_frames_(0),
- client_(client),
- stream_write_side_closed_before_receiving_stop_sending_(false) {}
-
- void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override {
- ++num_stop_sending_frames_;
- stream_write_side_closed_before_receiving_stop_sending_ =
- static_cast<QuicSimpleClientStream*>(client_->latest_created_stream())
- ->write_side_closed();
- }
-
- size_t num_stop_sending_frames() const { return num_stop_sending_frames_; }
-
- bool stream_write_side_closed_before_receiving_stop_sending() const {
- return stream_write_side_closed_before_receiving_stop_sending_;
- }
-
- private:
- size_t num_stop_sending_frames_;
- QuicTestClient* client_;
- bool stream_write_side_closed_before_receiving_stop_sending_;
-};
-
-// Test that STOP_SENDING makes it to the peer. Create a stream and send a
-// STOP_SENDING. The receiver should get a call to QuicStream::OnStopSending.
-TEST_P(EndToEndTest, SimpleStopSendingTest) {
- const uint16_t kStopSendingTestCode = 123;
- ASSERT_TRUE(Initialize());
- if (!version_.HasIetfQuicFrames()) {
- return;
- }
- QuicSession* client_session = GetClientSession();
- ASSERT_TRUE(client_session);
- StopSendingObserver observer(client_.get());
- QuicConnection* client_connection = client_session->connection();
- ASSERT_TRUE(client_connection);
- client_connection->set_debug_visitor(&observer);
-
- std::string response_body(1305, 'a');
- SpdyHeaderBlock response_headers;
- response_headers[":status"] = quiche::QuicheTextUtils::Uint64ToString(200);
- response_headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(response_body.length());
- memory_cache_backend_.AddStopSendingResponse(
- server_hostname_, "/test_url", std::move(response_headers), response_body,
- kStopSendingTestCode);
-
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
- client_->WaitForDelayedAcks();
-
- QuicStreamId stream_id =
- client_session->next_outgoing_bidirectional_stream_id();
- client_->SendRequest("/test_url");
- // Wait for the connection to become idle.
- client_->WaitForDelayedAcks();
-
- EXPECT_THAT(client_->connection_error(), IsQuicNoError());
- QuicSimpleClientStream* client_stream =
- static_cast<QuicSimpleClientStream*>(client_->latest_created_stream());
- if (client_stream != nullptr) {
- // Ensure the stream has been write closed upon receiving STOP_SENDING.
- EXPECT_EQ(stream_id, client_stream->id());
- EXPECT_TRUE(client_stream->write_side_closed());
- client_->WaitUntil(
- -1, [&observer]() { return observer.num_stop_sending_frames() > 0; });
- if (!observer.stream_write_side_closed_before_receiving_stop_sending()) {
- EXPECT_EQ(kStopSendingTestCode,
- static_cast<uint16_t>(client_stream->stream_error()));
- }
- } else {
- ADD_FAILURE() << "Missing client stream";
- }
- client_connection->set_debug_visitor(nullptr);
-}
-
TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) {
ASSERT_TRUE(Initialize());
@@ -4726,7 +4704,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulation) {
ASSERT_TRUE(Initialize());
return;
}
- SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
ASSERT_TRUE(Initialize());
SendSynchronousFooRequestAndCheckResponse();
@@ -4750,7 +4727,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithMultiPacketChlo) {
ASSERT_TRUE(Initialize());
return;
}
- SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
constexpr auto kCustomParameter =
static_cast<TransportParameters::TransportParameterId>(0xff34);
@@ -4774,7 +4750,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithVersionNegotiation) {
}
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
- SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
ASSERT_TRUE(Initialize());
SendSynchronousFooRequestAndCheckResponse();
@@ -4793,7 +4768,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithLoss) {
return;
}
SetPacketLossPercentage(30);
- SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE});
// Disable blackhole detection as this test is testing loss recovery.
client_extra_copts_.push_back(kNBHD);
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
index 8a3436cc9bc..5164a4b67c8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
@@ -30,7 +30,7 @@ enum Http3AndQpackSettingsIdentifiers : uint64_t {
// Same value as spdy::SETTINGS_HEADER_TABLE_SIZE.
SETTINGS_QPACK_MAX_TABLE_CAPACITY = 0x01,
// Same value as spdy::SETTINGS_MAX_HEADER_LIST_SIZE.
- SETTINGS_MAX_HEADER_LIST_SIZE = 0x06,
+ SETTINGS_MAX_FIELD_SECTION_SIZE = 0x06,
SETTINGS_QPACK_BLOCKED_STREAMS = 0x07,
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
index e1b00c8783b..1a1ec691251 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
@@ -52,8 +52,6 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession {
void set_authorized(bool authorized) { authorized_ = authorized; }
- MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override));
-
private:
QuicCryptoClientConfig crypto_config_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc
index 0fc903a7283..3e825a05ce8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc
@@ -40,8 +40,6 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession {
delete;
~MockQuicSpdyClientSession() override {}
- MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override));
-
private:
QuicCryptoClientConfig crypto_config_;
};
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 c7b4c39dafd..9e1b08a486b 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
@@ -663,7 +663,7 @@ TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) {
// Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE,
// SETTINGS_MAX_HEADER_LIST_SIZE.
data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, kTestHeaderTableSize);
- data.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 2000);
+ data.AddSetting(spdy::SETTINGS_MAX_HEADER_LIST_SIZE, 2000);
SpdySerializedFrame frame(framer_->SerializeFrame(data));
stream_frame_.data_buffer = frame.data();
stream_frame_.data_length = frame.size();
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 82d1fe1ca16..1367a953272 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
@@ -20,7 +20,10 @@ namespace quic {
QuicReceiveControlStream::QuicReceiveControlStream(
PendingStream* pending,
QuicSpdySession* spdy_session)
- : QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true),
+ : QuicStream(pending,
+ spdy_session,
+ READ_UNIDIRECTIONAL,
+ /*is_static=*/true),
settings_frame_received_(false),
decoder_(this),
spdy_session_(spdy_session) {
@@ -107,13 +110,6 @@ bool QuicReceiveControlStream::OnGoAwayFrame(const GoAwayFrame& frame) {
return false;
}
- if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_http3_goaway_new_behavior);
- } else if (spdy_session()->perspective() == Perspective::IS_SERVER) {
- OnWrongFrame("Go Away");
- return false;
- }
-
spdy_session()->OnHttp3GoAway(frame.id);
return true;
}
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 32cd298d4e9..5ee5f50e785 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
@@ -156,8 +156,8 @@ TEST_P(QuicReceiveControlStreamTest, ResetControlStream) {
TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) {
SettingsFrame settings;
- settings.values[3] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[10] = 2;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = 12;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 37;
std::string data = EncodeSettings(settings);
@@ -223,8 +223,8 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsTwice) {
TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) {
SettingsFrame settings;
- settings.values[3] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[10] = 2;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
std::string data = EncodeSettings(settings);
std::string data1 = data.substr(0, 1);
std::string data2 = data.substr(1, data.length() - 1);
@@ -292,22 +292,12 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveGoAwayFrame) {
std::string data = std::string(buffer.get(), header_length);
QuicStreamFrame frame(receive_control_stream_->id(), false, offset, data);
- EXPECT_FALSE(session_.http3_goaway_received());
+ EXPECT_FALSE(session_.goaway_received());
EXPECT_CALL(debug_visitor, OnGoAwayFrameReceived(goaway));
- if (!GetQuicReloadableFlag(quic_http3_goaway_new_behavior) &&
- perspective() == Perspective::IS_SERVER) {
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _));
- }
-
receive_control_stream_->OnStreamFrame(frame);
- if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior) ||
- perspective() == Perspective::IS_CLIENT) {
- EXPECT_TRUE(session_.http3_goaway_received());
- }
+ EXPECT_TRUE(session_.goaway_received());
}
TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
index 7be8ee4d46f..c7f1b381799 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
@@ -30,7 +30,7 @@ void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
QUIC_BUG << "OnStreamReset() called for write unidirectional stream.";
}
-bool QuicSendControlStream::OnStopSending(uint16_t /* code */) {
+bool QuicSendControlStream::OnStopSending(QuicRstStreamErrorCode /* code */) {
stream_delegate()->OnStreamError(
QUIC_HTTP_CLOSED_CRITICAL_STREAM,
"STOP_SENDING received for send control stream");
@@ -128,7 +128,8 @@ void QuicSendControlStream::SendGoAway(QuicStreamId id) {
GoAwayFrame frame;
// If the peer has not created any stream yet, use stream ID 0 to indicate no
// request is accepted.
- if (id == QuicUtils::GetInvalidStreamId(session()->transport_version())) {
+ if (!GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id) &&
+ id == QuicUtils::GetInvalidStreamId(session()->transport_version())) {
id = 0;
}
frame.id = id;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
index 6240310c80a..25ea5b7a192 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
@@ -31,7 +31,7 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
// Overriding QuicStream::OnStopSending() to make sure control stream is never
// closed before connection.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
- bool OnStopSending(uint16_t code) override;
+ bool OnStopSending(QuicRstStreamErrorCode code) override;
// Send SETTINGS frame if it hasn't been sent yet. Settings frame must be the
// first frame sent on this stream.
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 c37bacc2b59..61303de9fce 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
@@ -9,6 +9,7 @@
#include <string>
#include <utility>
+#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
@@ -182,20 +183,19 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> {
// would cause a close in the opposite direction. This allows tests to do the
// extra work to get a two-way (full) close where desired. Also sets up
// expects needed to ensure that the STOP_SENDING worked as expected.
- void InjectStopSendingFrame(QuicStreamId stream_id,
- QuicRstStreamErrorCode rst_stream_code) {
+ void InjectStopSendingFrame(QuicStreamId stream_id) {
if (!VersionHasIetfQuicFrames(transport_version())) {
// Only needed for version 99/IETF QUIC. Noop otherwise.
return;
}
- QuicStopSendingFrame stop_sending(
- kInvalidControlFrameId, stream_id,
- static_cast<QuicApplicationErrorCode>(rst_stream_code));
+ QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_id,
+ QUIC_ERROR_PROCESSING_STREAM);
EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
// Expect the RESET_STREAM that is generated in response to receiving a
// STOP_SENDING.
EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
+ EXPECT_CALL(*connection_,
+ OnStreamReset(stream_id, QUIC_ERROR_PROCESSING_STREAM));
session_->OnStopSendingFrame(stop_sending);
}
@@ -258,8 +258,7 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
// For version-99 will create and receive a stop-sending, completing
// the full-close expected by this test.
- InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
- QUIC_ERROR_PROCESSING_STREAM);
+ InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0));
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Send the same two bytes of payload in a new packet.
@@ -288,8 +287,7 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) {
// For version-99 will create and receive a stop-sending, completing
// the full-close expected by this test.
- InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
- QUIC_ERROR_PROCESSING_STREAM);
+ InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0));
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Send two bytes of payload.
@@ -329,8 +327,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
// For version-99 will create and receive a stop-sending, completing
// the full-close expected by this test.
- InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
- QUIC_ERROR_PROCESSING_STREAM);
+ InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0));
// If we were tracking, we'd probably want to reject this because it's data
// past the reset point of stream 3. As it's a closed stream we just drop the
@@ -351,7 +348,9 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
// streams. For versions other than version 99, the server accepts slightly
// more than the negotiated stream limit to deal with rare cases where a
// client FIN/RST is lost.
-
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(session_->perspective()));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
if (!VersionHasIetfQuicFrames(transport_version())) {
@@ -404,7 +403,9 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) {
// Test that the server closes the connection if a client makes too many data
// streams available. The server accepts slightly more than the negotiated
// stream limit to deal with rare cases where a client FIN/RST is lost.
-
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(session_->perspective()));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
const size_t kAvailableStreamLimit =
@@ -511,6 +512,9 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
QuicTagVector copt;
copt.push_back(kBWRE);
QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(session_->perspective()));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_TRUE(
@@ -605,7 +609,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
QuicPacketNumber(1) + kMinPacketsBetweenServerConfigUpdates,
PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false, false);
sent_packet_manager->OnPacketSent(&packet, now, NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
// Verify that the proto has exactly the values we expect.
CachedNetworkParameters expected_network_params;
@@ -702,6 +706,9 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) {
QuicTagVector copt;
copt.push_back(kBWMX);
QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(session_->perspective()));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_TRUE(
@@ -711,6 +718,9 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) {
TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) {
EXPECT_FALSE(
QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(session_->perspective()));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_FALSE(
@@ -726,6 +736,9 @@ TEST_P(QuicServerSessionBaseTest, TurnOffServerPush) {
QuicTagVector copt;
copt.push_back(kQNSP);
QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(session_->perspective()));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
EXPECT_FALSE(session_->server_push_enabled());
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc
index c5ef0c4c596..d7a7b034bfe 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc
@@ -57,10 +57,7 @@ bool QuicSpdyClientSession::ShouldCreateOutgoingBidirectionalStream() {
QUIC_DLOG(INFO) << "Encryption not active so no outgoing stream created.";
return false;
}
- bool goaway_received = VersionUsesHttp3(transport_version())
- ? http3_goaway_received()
- : QuicSession::goaway_received();
- if (goaway_received && respect_goaway_) {
+ if (goaway_received() && respect_goaway_) {
QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
<< "Already received goaway.";
return false;
@@ -131,10 +128,7 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) {
QUIC_BUG << "ShouldCreateIncomingStream called when disconnected";
return false;
}
- bool goaway_received = quic::VersionUsesHttp3(transport_version())
- ? http3_goaway_received()
- : QuicSession::goaway_received();
- if (goaway_received && respect_goaway_) {
+ if (goaway_received() && respect_goaway_) {
QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
<< "Already received goaway.";
return false;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
index 46305a6386c..1bfe2a74e68 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
@@ -213,13 +213,6 @@ void QuicSpdyClientSessionBase::ResetPromised(
}
}
-void QuicSpdyClientSessionBase::CloseStream(QuicStreamId stream_id) {
- QuicSpdySession::CloseStream(stream_id);
- if (!VersionUsesHttp3(transport_version())) {
- headers_stream()->MaybeReleaseSequencerBuffer();
- }
-}
-
void QuicSpdyClientSessionBase::OnStreamClosed(QuicStreamId stream_id) {
QuicSpdySession::OnStreamClosed(stream_id);
if (!VersionUsesHttp3(transport_version())) {
@@ -239,12 +232,12 @@ bool QuicSpdyClientSessionBase::ShouldKeepConnectionAlive() const {
bool QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) {
if (!was_zero_rtt_rejected()) {
if (max_outbound_header_list_size() != std::numeric_limits<size_t>::max() &&
- frame.values.find(SETTINGS_MAX_HEADER_LIST_SIZE) ==
+ frame.values.find(SETTINGS_MAX_FIELD_SECTION_SIZE) ==
frame.values.end()) {
CloseConnectionWithDetails(
QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
"Server accepted 0-RTT but omitted non-default "
- "SETTINGS_MAX_HEADER_LIST_SIZE");
+ "SETTINGS_MAX_FIELD_SECTION_SIZE");
return false;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
index 31924793f6b..e09f7cfdac6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
@@ -102,9 +102,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
void ResetPromised(QuicStreamId id, QuicRstStreamErrorCode error_code);
// Release headers stream's sequencer buffer if it's empty.
- void CloseStream(QuicStreamId stream_id) override;
-
- // Release headers stream's sequencer buffer if it's empty.
void OnStreamClosed(QuicStreamId stream_id) override;
// Returns true if there are no active requests and no promised streams.
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 70b7b360f0b..c3fc0e0ff76 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
@@ -97,7 +97,6 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicUtils::GetInvalidStreamId(GetParam().transport_version)) {
auto client_cache = std::make_unique<test::SimpleSessionCache>();
client_session_cache_ = client_cache.get();
- SetQuicRestartFlag(quic_enable_tls_resumption_v4, true);
SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true);
client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache));
@@ -204,7 +203,7 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
if (session_->version().UsesHttp3()) {
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[256] = 4; // unknown setting
session_->OnSettingsFrame(settings);
}
@@ -969,7 +968,7 @@ TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) {
CompleteCryptoHandshake();
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[256] = 4; // unknown setting
char application_state[] = {// type (SETTINGS)
0x04,
@@ -979,7 +978,7 @@ TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) {
0x01,
// content
0x02,
- // identifier (SETTINGS_MAX_HEADER_LIST_SIZE)
+ // identifier (SETTINGS_MAX_FIELD_SECTION_SIZE)
0x06,
// content
0x05,
@@ -1078,7 +1077,7 @@ TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) {
if (session_->version().UsesHttp3()) {
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[256] = 4; // unknown setting
session_->OnSettingsFrame(settings);
}
@@ -1400,7 +1399,7 @@ TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttResumption) {
// Let the session receive a different SETTINGS frame.
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[256] = 4; // unknown setting
session_->OnSettingsFrame(settings);
}
@@ -1430,8 +1429,8 @@ TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttRejection) {
// Let the session receive a different SETTINGS frame.
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
- // setting on SETTINGS_MAX_HEADER_LIST_SIZE is reduced.
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 4;
+ // setting on SETTINGS_MAX_FIELD_SECTION_SIZE is reduced.
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 4;
settings.values[256] = 4; // unknown setting
session_->OnSettingsFrame(settings);
}
@@ -1455,8 +1454,8 @@ TEST_P(QuicSpdyClientSessionTest, ServerAcceptsZeroRttButOmitSetting) {
// Let the session receive a different SETTINGS frame.
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1;
- // Intentionally omit SETTINGS_MAX_HEADER_LIST_SIZE which was previously sent
- // with a non-zero value.
+ // Intentionally omit SETTINGS_MAX_FIELD_SECTION_SIZE which was previously
+ // sent with a non-zero value.
settings.values[256] = 4; // unknown setting
session_->OnSettingsFrame(settings);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
index ffd4590285a..c8653ed3129 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
@@ -46,8 +46,6 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession {
delete;
~MockQuicSpdyClientSession() override = default;
- MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override));
-
using QuicSession::ActivateStream;
private:
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc
index a32de6168ee..1d08da3d568 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -75,9 +75,8 @@ TEST_F(QuicSpdyServerStreamBaseTest,
if (VersionHasIetfQuicFrames(session_.transport_version())) {
// Create and inject a STOP SENDING frame to complete the close
// of the stream. This is only needed for version 99/IETF QUIC.
- QuicStopSendingFrame stop_sending(
- kInvalidControlFrameId, stream_->id(),
- static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_->id(),
+ QUIC_STREAM_CANCELLED);
session_.OnStopSendingFrame(stop_sending);
}
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 3345feadc96..0f806f70bae 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
@@ -404,8 +404,8 @@ QuicSpdySession::QuicSpdySession(
server_push_enabled_(true),
ietf_server_push_enabled_(
GetQuicFlag(FLAGS_quic_enable_http3_server_push)),
- http3_goaway_sent_(false),
- http3_max_push_id_sent_(false) {
+ http3_max_push_id_sent_(false),
+ reject_spdy_settings_(GetQuicReloadableFlag(quic_reject_spdy_settings)) {
h2_deframer_.set_visitor(spdy_framer_visitor_.get());
h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
@@ -415,21 +415,22 @@ QuicSpdySession::~QuicSpdySession() {
QUIC_BUG_IF(destruction_indicator_ != 123456789)
<< "QuicSpdyStream use after free. " << destruction_indicator_
<< QuicStackTrace();
+ destruction_indicator_ = 987654321;
+
+ if (GetQuicReloadableFlag(quic_clean_up_spdy_session_destructor)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_clean_up_spdy_session_destructor);
+ return;
+ }
// Set the streams' session pointers in closed and dynamic stream lists
// to null to avoid subsequent use of this session.
for (auto& stream : *closed_streams()) {
static_cast<QuicSpdyStream*>(stream.get())->ClearSession();
}
- DCHECK(!remove_zombie_streams() || zombie_streams().empty());
- for (auto const& kv : zombie_streams()) {
- static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
- }
for (auto const& kv : stream_map()) {
if (!kv.second->is_static()) {
static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
}
}
- destruction_indicator_ = 987654321;
}
void QuicSpdySession::Initialize() {
@@ -471,7 +472,7 @@ void QuicSpdySession::FillSettingsFrame() {
qpack_maximum_dynamic_table_capacity_;
settings_.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
qpack_maximum_blocked_streams_;
- settings_.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
+ settings_.values[SETTINGS_MAX_FIELD_SECTION_SIZE] =
max_inbound_header_list_size_;
}
@@ -660,42 +661,21 @@ void QuicSpdySession::OnHttp3GoAway(uint64_t id) {
QUIC_BUG_IF(!version().UsesHttp3())
<< "HTTP/3 GOAWAY received on version " << version();
- if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) {
- if (last_received_http3_goaway_id_.has_value() &&
- id > last_received_http3_goaway_id_.value()) {
- CloseConnectionWithDetails(
- QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS,
- quiche::QuicheStrCat("GOAWAY received with ID ", id,
- " greater than previously received ID ",
- last_received_http3_goaway_id_.value()));
- return;
- }
- last_received_http3_goaway_id_ = id;
-
- if (perspective() == Perspective::IS_SERVER) {
- // TODO(b/151749109): Cancel server pushes with push ID larger than |id|.
- return;
- }
-
- // QuicStreamId is uint32_t. Casting to this narrower type is well-defined
- // and preserves the lower 32 bits. Both IsBidirectionalStreamId() and
- // IsIncomingStream() give correct results, because their return value is
- // determined by the least significant two bits.
- QuicStreamId stream_id = static_cast<QuicStreamId>(id);
- if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
- IsIncomingStream(stream_id)) {
- CloseConnectionWithDetails(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID,
- "GOAWAY with invalid stream ID");
- return;
- }
-
- // TODO(b/161252736): Cancel client requests with ID larger than |id|.
- // If |id| is larger than numeric_limits<QuicStreamId>::max(), then use
- // max() instead of downcast value.
+ if (last_received_http3_goaway_id_.has_value() &&
+ id > last_received_http3_goaway_id_.value()) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS,
+ quiche::QuicheStrCat("GOAWAY received with ID ", id,
+ " greater than previously received ID ",
+ last_received_http3_goaway_id_.value()));
return;
}
+ last_received_http3_goaway_id_ = id;
- DCHECK_EQ(perspective(), Perspective::IS_CLIENT);
+ if (perspective() == Perspective::IS_SERVER) {
+ // TODO(b/151749109): Cancel server pushes with push ID larger than |id|.
+ return;
+ }
// QuicStreamId is uint32_t. Casting to this narrower type is well-defined
// and preserves the lower 32 bits. Both IsBidirectionalStreamId() and
@@ -704,12 +684,14 @@ void QuicSpdySession::OnHttp3GoAway(uint64_t id) {
QuicStreamId stream_id = static_cast<QuicStreamId>(id);
if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
IsIncomingStream(stream_id)) {
- CloseConnectionWithDetails(
- QUIC_INVALID_STREAM_ID,
- "GOAWAY's last stream id has to point to a request stream");
+ CloseConnectionWithDetails(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID,
+ "GOAWAY with invalid stream ID");
return;
}
- last_received_http3_goaway_id_ = id;
+
+ // TODO(b/161252736): Cancel client requests with ID larger than |id|.
+ // If |id| is larger than numeric_limits<QuicStreamId>::max(), then use
+ // max() instead of downcast value.
}
bool QuicSpdySession::OnStreamsBlockedFrame(
@@ -731,9 +713,51 @@ bool QuicSpdySession::OnStreamsBlockedFrame(
void QuicSpdySession::SendHttp3GoAway() {
DCHECK_EQ(perspective(), Perspective::IS_SERVER);
DCHECK(VersionUsesHttp3(transport_version()));
- http3_goaway_sent_ = true;
- send_control_stream_->SendGoAway(
- GetLargestPeerCreatedStreamId(/*unidirectional = */ false));
+
+ QuicStreamId stream_id =
+ GetLargestPeerCreatedStreamId(/*unidirectional = */ false);
+
+ if (GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_http3_goaway_stream_id);
+ if (stream_id == QuicUtils::GetInvalidStreamId(transport_version())) {
+ // No client-initiated bidirectional streams received yet.
+ // Send 0 to let client know that all requests can be retried.
+ stream_id = 0;
+ } else {
+ // Tell client that streams starting with the next after the largest
+ // received one can be retried.
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
+ }
+ if (last_sent_http3_goaway_id_.has_value() &&
+ last_sent_http3_goaway_id_.value() <= stream_id) {
+ // MUST not send GOAWAY with identifier larger than previously sent.
+ // Do not bother sending one with same identifier as before, since GOAWAY
+ // frames on the control stream are guaranteed to be processed in order.
+ return;
+ }
+ }
+
+ send_control_stream_->SendGoAway(stream_id);
+ last_sent_http3_goaway_id_ = stream_id;
+}
+
+void QuicSpdySession::SendHttp3Shutdown() {
+ DCHECK_EQ(perspective(), Perspective::IS_SERVER);
+ DCHECK(VersionUsesHttp3(transport_version()));
+ QuicStreamCount advertised_max_incoming_bidirectional_streams =
+ GetAdvertisedMaxIncomingBidirectionalStreams();
+ const QuicStreamId stream_id =
+ QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
+ Perspective::IS_CLIENT) +
+ QuicUtils::StreamIdDelta(transport_version()) *
+ advertised_max_incoming_bidirectional_streams;
+ if (last_sent_http3_goaway_id_.has_value() &&
+ last_sent_http3_goaway_id_.value() < stream_id) {
+ send_control_stream_->SendGoAway(last_sent_http3_goaway_id_.value());
+ return;
+ }
+ send_control_stream_->SendGoAway(stream_id);
+ last_sent_http3_goaway_id_ = stream_id;
}
void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
@@ -944,6 +968,9 @@ bool QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) {
bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
if (VersionUsesHttp3(transport_version())) {
+ if (reject_spdy_settings_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_reject_spdy_settings);
+ }
// SETTINGS frame received on the control stream.
switch (id) {
case SETTINGS_QPACK_MAX_TABLE_CAPACITY: {
@@ -974,9 +1001,9 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
std::min(value, qpack_maximum_dynamic_table_capacity_));
break;
}
- case SETTINGS_MAX_HEADER_LIST_SIZE:
+ case SETTINGS_MAX_FIELD_SECTION_SIZE:
QUIC_DVLOG(1) << ENDPOINT
- << "SETTINGS_MAX_HEADER_LIST_SIZE received with value "
+ << "SETTINGS_MAX_FIELD_SECTION_SIZE received with value "
<< value;
if (GetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2) &&
max_outbound_header_list_size_ !=
@@ -990,7 +1017,7 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
was_zero_rtt_rejected()
? "Server rejected 0-RTT, aborting because "
: "",
- "Server sent an SETTINGS_MAX_HEADER_LIST_SIZE: ", value,
+ "Server sent an SETTINGS_MAX_FIELD_SECTION_SIZE: ", value,
"which reduces current value: ",
max_outbound_header_list_size_));
return false;
@@ -1018,6 +1045,21 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
}
break;
}
+ case spdy::SETTINGS_ENABLE_PUSH:
+ QUIC_FALLTHROUGH_INTENDED;
+ case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
+ QUIC_FALLTHROUGH_INTENDED;
+ case spdy::SETTINGS_INITIAL_WINDOW_SIZE:
+ QUIC_FALLTHROUGH_INTENDED;
+ case spdy::SETTINGS_MAX_FRAME_SIZE:
+ if (reject_spdy_settings_) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_RECEIVE_SPDY_SETTING,
+ quiche::QuicheStrCat(
+ "received HTTP/2 specific setting in HTTP/3 session: ", id));
+ return false;
+ }
+ break;
default:
QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id
<< " received with value " << value;
@@ -1239,7 +1281,7 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
return false;
}
auto encoder_receive = std::make_unique<QpackReceiveStream>(
- pending, qpack_decoder_->encoder_stream_receiver());
+ pending, this, qpack_decoder_->encoder_stream_receiver());
qpack_encoder_receive_stream_ = encoder_receive.get();
ActivateStream(std::move(encoder_receive));
qpack_encoder_receive_stream_->SetUnblocked();
@@ -1256,7 +1298,7 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
return false;
}
auto decoder_receive = std::make_unique<QpackReceiveStream>(
- pending, qpack_encoder_->decoder_stream_receiver());
+ pending, this, qpack_encoder_->decoder_stream_receiver());
qpack_decoder_receive_stream_ = decoder_receive.get();
ActivateStream(std::move(decoder_receive));
qpack_decoder_receive_stream_->SetUnblocked();
@@ -1268,9 +1310,13 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
return true;
}
default:
- SendStopSending(static_cast<QuicApplicationErrorCode>(
- QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
- pending->id());
+ if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+ SendStopSending(QUIC_STREAM_STREAM_CREATION_ERROR, pending->id());
+ } else {
+ SendStopSending(static_cast<QuicRstStreamErrorCode>(
+ QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+ pending->id());
+ }
pending->StopReading();
}
return false;
@@ -1403,6 +1449,18 @@ void QuicSpdySession::EnableServerPush() {
ietf_server_push_enabled_ = true;
}
+bool QuicSpdySession::goaway_received() const {
+ return VersionUsesHttp3(transport_version())
+ ? last_received_http3_goaway_id_.has_value()
+ : transport_goaway_received();
+}
+
+bool QuicSpdySession::goaway_sent() const {
+ return VersionUsesHttp3(transport_version())
+ ? last_sent_http3_goaway_id_.has_value()
+ : transport_goaway_sent();
+}
+
bool QuicSpdySession::CanCreatePushStreamWithId(PushId push_id) {
DCHECK(VersionUsesHttp3(transport_version()));
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 4c50e7fd001..db8fc6b2df2 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
@@ -225,9 +225,17 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Send GOAWAY if the peer is blocked on the implementation max.
bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override;
- // Write the GOAWAY |frame| on control stream.
+ // Write GOAWAY frame on the control stream to notify the client that every
+ // stream that has not reached the server yet can be retried. Do not send a
+ // GOAWAY frame if it could not convey new information to the client with
+ // respect to the previous GOAWAY frame.
void SendHttp3GoAway();
+ // Write advisory GOAWAY frame on the control stream with the max stream ID
+ // that the client could send. If GOAWAY has already been sent, the lesser of
+ // its max stream ID and the one advertised via MAX_STREAMS is used.
+ void SendHttp3Shutdown();
+
// Write |headers| for |promised_stream_id| on |original_stream_id| in a
// PUSH_PROMISE frame to peer.
virtual void WritePushPromise(QuicStreamId original_stream_id,
@@ -353,11 +361,12 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
Http3DebugVisitor* debug_visitor() { return debug_visitor_; }
- bool http3_goaway_received() const {
- return last_received_http3_goaway_id_.has_value();
- }
-
- bool http3_goaway_sent() const { return http3_goaway_sent_; }
+ // When using Google QUIC, return whether a transport layer GOAWAY frame has
+ // been received or sent.
+ // When using IETF QUIC, return whether an HTTP/3 GOAWAY frame has been
+ // received or sent.
+ bool goaway_received() const;
+ bool goaway_sent() const;
// Log header compression ratio histogram.
// |using_qpack| is true for QPACK, false for HPACK.
@@ -581,13 +590,17 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// The identifier in the most recently received GOAWAY frame. Unset if no
// GOAWAY frame has been received yet.
quiche::QuicheOptional<uint64_t> last_received_http3_goaway_id_;
- // If the endpoint has sent HTTP/3 GOAWAY frame.
- bool http3_goaway_sent_;
+ // The identifier in the most recently sent GOAWAY frame. Unset if no GOAWAY
+ // frame has been sent yet.
+ quiche::QuicheOptional<uint64_t> last_sent_http3_goaway_id_;
// Only used by a client, only with IETF QUIC. True if a MAX_PUSH_ID frame
// has been sent, in which case |max_push_id_| has the value sent in the most
// recent MAX_PUSH_ID frame. Once true, never goes back to false.
bool http3_max_push_id_sent_;
+
+ // Latched value of reloadable flag quic_reject_spdy_settings.
+ const bool reject_spdy_settings_;
};
} // namespace quic
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 fd0c645ab19..6f7d85f68d2 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
@@ -131,6 +131,9 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
}
// QuicCryptoStream implementation
+ ssl_early_data_reason_t EarlyDataReason() const override {
+ return ssl_early_data_unknown;
+ }
bool encryption_established() const override {
return encryption_established_;
}
@@ -1080,9 +1083,88 @@ TEST_P(QuicSpdySessionTestServer, SendHttp3GoAway) {
EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ // No client-initiated stream has been received, therefore a GOAWAY frame with
+ // stream ID = 0 is sent to notify the client that all requests can be retried
+ // on a different connection.
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 0));
+ session_.SendHttp3GoAway();
+ EXPECT_TRUE(session_.goaway_sent());
+
+ const QuicStreamId kTestStreamId =
+ GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0);
+ EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, _)).Times(0);
+ EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId));
+}
+
+TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayAfterStreamIsCreated) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ if (!GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id)) {
+ return;
+ }
+
+ CompleteHandshake();
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_.set_debug_visitor(&debug_visitor);
+
+ const QuicStreamId kTestStreamId =
+ GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0);
+ EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId));
+
+ EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ // The first stream, of kTestStreamId = 0, could already have been processed.
+ // A GOAWAY frame is sent to notify the client that requests starting with
+ // stream ID = 4 can be retried on a different connection.
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 4));
+ session_.SendHttp3GoAway();
+ EXPECT_TRUE(session_.goaway_sent());
+
+ // No more GOAWAY frames are sent because they could not convey new
+ // information to the client.
+ session_.SendHttp3GoAway();
+}
+
+TEST_P(QuicSpdySessionTestServer, SendHttp3Shutdown) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ CompleteHandshake();
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_.set_debug_visitor(&debug_visitor);
+
+ EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(_));
+ session_.SendHttp3Shutdown();
+ EXPECT_TRUE(session_.goaway_sent());
+
+ const QuicStreamId kTestStreamId =
+ GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0);
+ EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, _)).Times(0);
+ EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId));
+}
+
+TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayAfterShutdownNotice) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ CompleteHandshake();
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_.set_debug_visitor(&debug_visitor);
+
+ EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(_)).Times(2);
+
+ session_.SendHttp3Shutdown();
+ EXPECT_TRUE(session_.goaway_sent());
session_.SendHttp3GoAway();
- EXPECT_TRUE(session_.http3_goaway_sent());
const QuicStreamId kTestStreamId =
GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0);
@@ -1116,14 +1198,11 @@ TEST_P(QuicSpdySessionTestServer, Http3GoAwayLargerIdThanBefore) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- if (!GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) {
- return;
- }
- EXPECT_FALSE(session_.http3_goaway_received());
+ EXPECT_FALSE(session_.goaway_received());
PushId push_id1 = 0;
session_.OnHttp3GoAway(push_id1);
- EXPECT_TRUE(session_.http3_goaway_received());
+ EXPECT_TRUE(session_.goaway_received());
EXPECT_CALL(
*connection_,
@@ -1138,6 +1217,7 @@ TEST_P(QuicSpdySessionTestServer, Http3GoAwayLargerIdThanBefore) {
// Test that server session will send a connectivity probe in response to a
// connectivity probe on the same path.
TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) {
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
QuicSocketAddress old_peer_address =
QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
EXPECT_EQ(old_peer_address, session_.peer_address());
@@ -1145,8 +1225,14 @@ TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) {
QuicSocketAddress new_peer_address =
QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort + 1);
- EXPECT_CALL(*connection_,
- SendConnectivityProbingResponsePacket(new_peer_address));
+ if (connection_->send_path_response()) {
+ EXPECT_CALL(*connection_,
+ SendConnectivityProbingPacket(nullptr, new_peer_address));
+ } else {
+ EXPECT_CALL(*connection_,
+ SendConnectivityProbingResponsePacket(new_peer_address));
+ }
+
if (VersionHasIetfQuicFrames(transport_version())) {
// Need to explicitly do this to emulate the reception of a PathChallenge,
// which stores its payload for use in generating the response.
@@ -1198,9 +1284,9 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) {
// one-way close.
if (VersionHasIetfQuicFrames(transport_version())) {
// Only needed for version 99/IETF QUIC.
- QuicStopSendingFrame stop_sending(
- kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0),
- static_cast<QuicApplicationErrorCode>(QUIC_ERROR_PROCESSING_STREAM));
+ QuicStopSendingFrame stop_sending(kInvalidControlFrameId,
+ GetNthClientInitiatedBidirectionalId(0),
+ QUIC_ERROR_PROCESSING_STREAM);
// Expect the RESET_STREAM that is generated in response to receiving a
// STOP_SENDING.
EXPECT_CALL(*connection_,
@@ -1480,9 +1566,8 @@ TEST_P(QuicSpdySessionTestServer,
// one-way close.
if (VersionHasIetfQuicFrames(transport_version())) {
// Only needed for version 99/IETF QUIC.
- QuicStopSendingFrame stop_sending(
- kInvalidControlFrameId, stream->id(),
- static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream->id(),
+ QUIC_STREAM_CANCELLED);
// Expect the RESET_STREAM that is generated in response to receiving a
// STOP_SENDING.
EXPECT_CALL(*connection_,
@@ -2143,7 +2228,7 @@ TEST_P(QuicSpdySessionTestServer, OnPriorityUpdateFrame) {
// PRIORITY_UPDATE frame arrives after stream creation.
TestStream* stream1 = session_.CreateIncomingStream(stream_id1);
- EXPECT_EQ(QuicStream::kDefaultUrgency,
+ EXPECT_EQ(QuicStream::DefaultUrgency(),
stream1->precedence().spdy3_priority());
EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameReceived(priority_update1));
session_.OnStreamFrame(data3);
@@ -2193,9 +2278,15 @@ TEST_P(QuicSpdySessionTestServer, SimplePendingStreamType) {
QuicStopSendingFrame* stop_sending = frame.stop_sending_frame;
EXPECT_EQ(stream_id, stop_sending->stream_id);
- EXPECT_EQ(QuicHttp3ErrorCode::STREAM_CREATION_ERROR,
- static_cast<QuicHttp3ErrorCode>(
- stop_sending->application_error_code));
+ EXPECT_EQ(
+ GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)
+ ? QUIC_STREAM_STREAM_CREATION_ERROR
+ : static_cast<QuicRstStreamErrorCode>(
+ QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+ stop_sending->error_code);
+ EXPECT_EQ(
+ static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+ stop_sending->ietf_error_code);
return ClearControlFrame(frame);
}));
@@ -2324,7 +2415,7 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) {
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 512;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = 42;
std::string data = EncodeSettings(settings);
QuicStreamFrame frame(stream_id, false, 1, quiche::QuicheStringPiece(data));
@@ -2356,8 +2447,8 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStreamOutOfOrderDelivery) {
GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
char type[] = {kControlStream};
SettingsFrame settings;
- settings.values[3] = 2;
- settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[10] = 2;
+ settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
std::string data = EncodeSettings(settings);
QuicStreamFrame data1(stream_id, false, 1, quiche::QuicheStringPiece(data));
@@ -2679,17 +2770,9 @@ TEST_P(QuicSpdySessionTestClient, InvalidHttp3GoAway) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID,
- "GOAWAY with invalid stream ID", _));
- } else {
- EXPECT_CALL(
- *connection_,
- CloseConnection(
- QUIC_INVALID_STREAM_ID,
- "GOAWAY's last stream id has to point to a request stream", _));
- }
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID,
+ "GOAWAY with invalid stream ID", _));
QuicStreamId stream_id =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
session_.OnHttp3GoAway(stream_id);
@@ -2699,15 +2782,12 @@ TEST_P(QuicSpdySessionTestClient, Http3GoAwayLargerIdThanBefore) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- if (!GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) {
- return;
- }
- EXPECT_FALSE(session_.http3_goaway_received());
+ EXPECT_FALSE(session_.goaway_received());
QuicStreamId stream_id1 =
GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0);
session_.OnHttp3GoAway(stream_id1);
- EXPECT_TRUE(session_.http3_goaway_received());
+ EXPECT_TRUE(session_.goaway_received());
EXPECT_CALL(
*connection_,
@@ -2777,7 +2857,7 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) {
if (VersionUsesHttp3(transport_version())) {
EXPECT_EQ(std::numeric_limits<size_t>::max(),
session_.max_outbound_header_list_size());
- session_.OnSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 5);
+ session_.OnSetting(SETTINGS_MAX_FIELD_SECTION_SIZE, 5);
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
@@ -2798,7 +2878,7 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) {
EXPECT_EQ(std::numeric_limits<size_t>::max(),
session_.max_outbound_header_list_size());
- session_.OnSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 5);
+ session_.OnSetting(SETTINGS_MAX_FIELD_SECTION_SIZE, 5);
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
EXPECT_TRUE(session_.server_push_enabled());
@@ -2900,8 +2980,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
ASSERT_TRUE(control_stream);
QuicStopSendingFrame stop_sending_control_stream(
- kInvalidControlFrameId, control_stream->id(),
- static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ kInvalidControlFrameId, control_stream->id(), QUIC_STREAM_CANCELLED);
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
@@ -2913,8 +2992,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
ASSERT_TRUE(decoder_stream);
QuicStopSendingFrame stop_sending_decoder_stream(
- kInvalidControlFrameId, decoder_stream->id(),
- static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ kInvalidControlFrameId, decoder_stream->id(), QUIC_STREAM_CANCELLED);
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
@@ -2926,8 +3004,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
ASSERT_TRUE(encoder_stream);
QuicStopSendingFrame stop_sending_encoder_stream(
- kInvalidControlFrameId, encoder_stream->id(),
- static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ kInvalidControlFrameId, encoder_stream->id(), QUIC_STREAM_CANCELLED);
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
@@ -3027,6 +3104,25 @@ TEST_P(QuicSpdySessionTestClient, DoNotSendInitialMaxPushIdIfSetToDefaut) {
CompleteHandshake();
}
+TEST_P(QuicSpdySessionTestClient, ReceiveSpdySettingInHttp3) {
+ if (!VersionUsesHttp3(transport_version()) ||
+ !GetQuicReloadableFlag(quic_reject_spdy_settings)) {
+ return;
+ }
+
+ SettingsFrame frame;
+ frame.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
+ // https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-30#section-7.2.4.1
+ // specifies the presence of HTTP/2 setting as error.
+ frame.values[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 100;
+
+ CompleteHandshake();
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_HTTP_RECEIVE_SPDY_SETTING, _, _));
+ session_.OnSettingsFrame(frame);
+}
+
} // namespace
} // namespace test
} // namespace quic
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 259493f3862..1c5f9645822 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
@@ -199,7 +199,7 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id,
sequencer_offset_(0),
is_decoder_processing_input_(false),
ack_listener_(nullptr),
- last_sent_urgency_(kDefaultUrgency) {
+ last_sent_urgency_(DefaultUrgency()) {
DCHECK_EQ(session()->connection(), spdy_session->connection());
DCHECK_EQ(transport_version(), spdy_session->transport_version());
DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
@@ -220,7 +220,7 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id,
QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
QuicSpdySession* spdy_session,
StreamType type)
- : QuicStream(pending, type, /*is_static=*/false),
+ : QuicStream(pending, spdy_session, type, /*is_static=*/false),
spdy_session_(spdy_session),
on_body_available_called_because_sequencer_is_closed_(false),
visitor_(nullptr),
@@ -235,7 +235,7 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
sequencer_offset_(sequencer()->NumBytesConsumed()),
is_decoder_processing_input_(false),
ack_listener_(nullptr),
- last_sent_urgency_(kDefaultUrgency) {
+ last_sent_urgency_(DefaultUrgency()) {
DCHECK_EQ(session()->connection(), spdy_session->connection());
DCHECK_EQ(transport_version(), spdy_session->transport_version());
DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id()));
@@ -801,6 +801,11 @@ void QuicSpdyStream::OnDataAvailable() {
void QuicSpdyStream::OnClose() {
QuicStream::OnClose();
+ if (GetQuicReloadableFlag(quic_abort_qpack_on_stream_close)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_abort_qpack_on_stream_close);
+ qpack_decoded_headers_accumulator_.reset();
+ }
+
if (visitor_) {
Visitor* visitor = visitor_;
// Calling Visitor::OnClose() may result the destruction of the visitor,
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h
index 61bc1fb35c9..5a58842e1f8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h
@@ -209,11 +209,13 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Called when owning session is getting deleted to avoid subsequent
// use of the spdy_session_ member.
+ // TODO(b/136274541): Remove this method once
+ // flag_quic_clean_up_spdy_session_destructor is deprecated.
void ClearSession();
// Returns true if the sequencer has delivered the FIN, and no more body bytes
// will be available.
- bool IsClosed() { return sequencer()->IsClosed(); }
+ bool IsSequencerClosed() { return sequencer()->IsClosed(); }
// QpackDecodedHeadersAccumulator::Visitor implementation.
void OnHeadersDecoded(QuicHeaderList headers,
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 cc0e3ec2e80..1c55c96af0b 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
@@ -119,6 +119,9 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
}
// QuicCryptoStream implementation
+ ssl_early_data_reason_t EarlyDataReason() const override {
+ return ssl_early_data_unknown;
+ }
bool encryption_established() const override {
return encryption_established_;
}
@@ -2416,6 +2419,64 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) {
session_->qpack_decoder()->OnInsertWithoutNameReference("trailing", "foobar");
}
+// Regression test for b/132603592: QPACK decoding unblocked after stream is
+// closed.
+TEST_P(QuicSpdyStreamTest, HeaderDecodingUnblockedAfterStreamClosed) {
+ if (!UsesHttp3()) {
+ return;
+ }
+
+ Initialize(kShouldProcessData);
+ testing::InSequence s;
+ session_->qpack_decoder()->OnSetDynamicTableCapacity(1024);
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_->set_debug_visitor(&debug_visitor);
+
+ // HEADERS frame referencing first dynamic table entry.
+ std::string encoded_headers = quiche::QuicheTextUtils::HexDecode("020080");
+ std::string headers = HeadersFrame(encoded_headers);
+ EXPECT_CALL(debug_visitor,
+ OnHeadersFrameReceived(stream_->id(), encoded_headers.length()));
+ stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), false, 0, headers));
+
+ // Decoding is blocked because dynamic table entry has not been received yet.
+ EXPECT_FALSE(stream_->headers_decompressed());
+
+ // Decoder stream type and stream cancellation instruction.
+ auto decoder_send_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 0, _, _, _));
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 1, _, _, _));
+
+ // Reset stream.
+ EXPECT_CALL(*session_,
+ SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, _, _));
+ stream_->Reset(QUIC_STREAM_CANCELLED);
+
+ if (!GetQuicReloadableFlag(quic_abort_qpack_on_stream_close)) {
+ // Header acknowledgement.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 2, _, _, _));
+ EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _));
+ }
+
+ // Deliver dynamic table entry to decoder.
+ session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
+
+ if (GetQuicReloadableFlag(quic_abort_qpack_on_stream_close)) {
+ EXPECT_FALSE(stream_->headers_decompressed());
+ } else {
+ // Verify headers.
+ EXPECT_TRUE(stream_->headers_decompressed());
+ EXPECT_THAT(stream_->header_list(), ElementsAre(Pair("foo", "bar")));
+ }
+}
+
class QuicSpdyStreamIncrementalConsumptionTest : public QuicSpdyStreamTest {
protected:
QuicSpdyStreamIncrementalConsumptionTest() : offset_(0), consumed_bytes_(0) {}
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 69dd3d0a221..847408d89cc 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
@@ -160,7 +160,7 @@ std::string SpdyUtils::H3SettingsToString(
Http3AndQpackSettingsIdentifiers identifier) {
switch (identifier) {
RETURN_STRING_LITERAL(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
- RETURN_STRING_LITERAL(SETTINGS_MAX_HEADER_LIST_SIZE);
+ RETURN_STRING_LITERAL(SETTINGS_MAX_FIELD_SECTION_SIZE);
RETURN_STRING_LITERAL(SETTINGS_QPACK_BLOCKED_STREAMS);
}
return quiche::QuicheStrCat("UNSUPPORTED_SETTINGS_TYPE(", identifier, ")");
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc
index d2fc88b9ecd..b2f15c4ecb3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc
@@ -9,8 +9,9 @@
namespace quic {
QpackReceiveStream::QpackReceiveStream(PendingStream* pending,
+ QuicSession* session,
QpackStreamReceiver* receiver)
- : QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true),
+ : QuicStream(pending, session, READ_UNIDIRECTIONAL, /*is_static=*/true),
receiver_(receiver) {}
void QpackReceiveStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h
index 0613871625e..0814985760c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h
@@ -19,7 +19,9 @@ class QUIC_EXPORT_PRIVATE QpackReceiveStream : public QuicStream {
public:
// Construct receive stream from pending stream, the |pending| object needs
// to be deleted after the construction.
- QpackReceiveStream(PendingStream* pending, QpackStreamReceiver* receiver);
+ QpackReceiveStream(PendingStream* pending,
+ QuicSession* session,
+ QpackStreamReceiver* receiver);
QpackReceiveStream(const QpackReceiveStream&) = delete;
QpackReceiveStream& operator=(const QpackReceiveStream&) = delete;
~QpackReceiveStream() override = default;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc
index 15525b593d5..176c431afb9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc
@@ -20,7 +20,7 @@ void QpackSendStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
QUIC_BUG << "OnStreamReset() called for write unidirectional stream.";
}
-bool QpackSendStream::OnStopSending(uint16_t /* code */) {
+bool QpackSendStream::OnStopSending(QuicRstStreamErrorCode /* code */) {
stream_delegate()->OnStreamError(
QUIC_HTTP_CLOSED_CRITICAL_STREAM,
"STOP_SENDING received for QPACK send stream");
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h
index 50d2808a46e..e8a4ea797d2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h
@@ -33,7 +33,7 @@ class QUIC_EXPORT_PRIVATE QpackSendStream : public QuicStream,
// Overriding QuicStream::OnStopSending() to make sure QPACK stream is never
// closed before connection.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
- bool OnStopSending(uint16_t code) override;
+ bool OnStopSending(QuicRstStreamErrorCode code) override;
// The send QPACK stream is write unidirectional, so this method
// should never be called.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
index 23597e289e9..bac4e181c20 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
@@ -1326,6 +1326,7 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
*error_details = "MinAckDelay is greater than MaxAckDelay.";
return IETF_QUIC_PROTOCOL_VIOLATION;
}
+ QUIC_RELOADABLE_FLAG_COUNT(quic_record_received_min_ack_delay);
min_ack_delay_ms_.SetReceivedValue(params.min_ack_delay_us.value() /
kNumMicrosPerMilli);
}
@@ -1353,14 +1354,11 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
}
}
- bool google_params_already_parsed = false;
if (params.initial_round_trip_time_us.value() > 0) {
- google_params_already_parsed = true;
initial_round_trip_time_us_.SetReceivedValue(
params.initial_round_trip_time_us.value());
}
if (params.google_connection_options.has_value()) {
- google_params_already_parsed = true;
connection_options_.SetReceivedValues(
params.google_connection_options.value());
}
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 5d32a5f171c..e1799817168 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
@@ -26,6 +26,7 @@
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
@@ -37,6 +38,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -65,6 +67,7 @@ class AckAlarmDelegate : public QuicAlarm::Delegate {
void OnAlarm() override {
DCHECK(connection_->ack_frame_updated());
+ DCHECK(connection_->connected());
QuicConnection::ScopedPacketFlusher flusher(connection_);
if (connection_->SupportsMultiplePacketNumberSpaces()) {
connection_->SendAllPendingAcks();
@@ -88,7 +91,10 @@ class RetransmissionAlarmDelegate : public QuicAlarm::Delegate {
RetransmissionAlarmDelegate& operator=(const RetransmissionAlarmDelegate&) =
delete;
- void OnAlarm() override { connection_->OnRetransmissionTimeout(); }
+ void OnAlarm() override {
+ DCHECK(connection_->connected());
+ connection_->OnRetransmissionTimeout();
+ }
private:
QuicConnection* connection_;
@@ -103,7 +109,10 @@ class SendAlarmDelegate : public QuicAlarm::Delegate {
SendAlarmDelegate(const SendAlarmDelegate&) = delete;
SendAlarmDelegate& operator=(const SendAlarmDelegate&) = delete;
- void OnAlarm() override { connection_->WriteAndBundleAcksIfNotBlocked(); }
+ void OnAlarm() override {
+ DCHECK(connection_->connected());
+ connection_->WriteAndBundleAcksIfNotBlocked();
+ }
private:
QuicConnection* connection_;
@@ -116,7 +125,10 @@ class PingAlarmDelegate : public QuicAlarm::Delegate {
PingAlarmDelegate(const PingAlarmDelegate&) = delete;
PingAlarmDelegate& operator=(const PingAlarmDelegate&) = delete;
- void OnAlarm() override { connection_->OnPingTimeout(); }
+ void OnAlarm() override {
+ DCHECK(connection_->connected());
+ connection_->OnPingTimeout();
+ }
private:
QuicConnection* connection_;
@@ -130,7 +142,10 @@ class MtuDiscoveryAlarmDelegate : public QuicAlarm::Delegate {
MtuDiscoveryAlarmDelegate& operator=(const MtuDiscoveryAlarmDelegate&) =
delete;
- void OnAlarm() override { connection_->DiscoverMtu(); }
+ void OnAlarm() override {
+ DCHECK(connection_->connected());
+ connection_->DiscoverMtu();
+ }
private:
QuicConnection* connection_;
@@ -146,6 +161,7 @@ class ProcessUndecryptablePacketsAlarmDelegate : public QuicAlarm::Delegate {
const ProcessUndecryptablePacketsAlarmDelegate&) = delete;
void OnAlarm() override {
+ DCHECK(connection_->connected());
QuicConnection::ScopedPacketFlusher flusher(connection_);
connection_->MaybeProcessUndecryptablePackets();
}
@@ -208,6 +224,7 @@ QuicConnection::QuicConnection(
server_connection_id.length()),
current_packet_content_(NO_FRAMES_RECEIVED),
is_current_packet_connectivity_probing_(false),
+ has_path_challenge_in_current_packet_(false),
current_effective_peer_migration_type_(NO_CHANGE),
helper_(helper),
alarm_factory_(alarm_factory),
@@ -230,9 +247,6 @@ QuicConnection::QuicConnection(
should_last_packet_instigate_acks_(false),
max_undecryptable_packets_(0),
max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)),
- pending_version_negotiation_packet_(false),
- send_ietf_version_negotiation_packet_(false),
- send_version_negotiation_packet_with_prefixed_lengths_(false),
idle_timeout_connection_close_behavior_(
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
num_rtos_for_blackhole_detection_(0),
@@ -304,6 +318,10 @@ QuicConnection::QuicConnection(
&arena_,
alarm_factory_),
support_handshake_done_(version().HasHandshakeDone()) {
+ QUIC_BUG_IF(!start_peer_migration_earlier_ && send_path_response_);
+ if (fix_missing_connected_checks_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_add_missing_connected_checks);
+ }
QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID "
<< server_connection_id
<< " and version: " << ParsedQuicVersionToString(version());
@@ -347,6 +365,7 @@ QuicConnection::QuicConnection(
blackhole_detection_disabled_ = true;
}
}
+ packet_creator_.SetDefaultPeerAddress(initial_peer_address);
}
void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) {
@@ -519,9 +538,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
idle_timeout_connection_close_behavior_ = ConnectionCloseBehavior::
SILENT_CLOSE_WITH_CONNECTION_CLOSE_PACKET_SERIALIZED;
}
- if (GetQuicReloadableFlag(quic_no_silent_close_for_idle_timeout) &&
- config.HasClientRequestedIndependentOption(kNSLC, perspective_)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_no_silent_close_for_idle_timeout);
+ if (config.HasClientRequestedIndependentOption(kNSLC, perspective_)) {
idle_timeout_connection_close_behavior_ =
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET;
}
@@ -581,6 +598,12 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
if (config.HasClientRequestedIndependentOption(kFIDT, perspective_)) {
idle_network_detector_.enable_shorter_idle_timeout_on_sent_packet();
}
+ if (config.HasClientRequestedIndependentOption(k3AFF, perspective_)) {
+ anti_amplification_factor_ = 3;
+ }
+ if (config.HasClientRequestedIndependentOption(k10AF, perspective_)) {
+ anti_amplification_factor_ = 10;
+ }
if (debug_visitor_ != nullptr) {
debug_visitor_->OnSetFromConfig(config);
@@ -1103,6 +1126,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
// Initialize the current packet content state.
current_packet_content_ = NO_FRAMES_RECEIVED;
is_current_packet_connectivity_probing_ = false;
+ has_path_challenge_in_current_packet_ = false;
current_effective_peer_migration_type_ = NO_CHANGE;
if (perspective_ == Perspective::IS_CLIENT) {
@@ -1112,7 +1136,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
// client connections.
// TODO(fayang): only change peer addresses in application data packet
// number space.
- direct_peer_address_ = last_packet_source_address_;
+ UpdatePeerAddress(last_packet_source_address_);
effective_peer_address_ = GetEffectivePeerAddressFromCurrentPacket();
}
} else {
@@ -1293,6 +1317,8 @@ bool QuicConnection::OnAckFrameEnd(QuicPacketNumber start) {
}
const bool one_rtt_packet_was_acked =
sent_packet_manager_.one_rtt_packet_acked();
+ const bool zero_rtt_packet_was_acked =
+ sent_packet_manager_.zero_rtt_packet_acked();
const AckResult ack_result = sent_packet_manager_.OnAckFrameEnd(
idle_network_detector_.time_of_last_received_packet(),
last_header_.packet_number, last_decrypted_packet_level_);
@@ -1309,6 +1335,11 @@ bool QuicConnection::OnAckFrameEnd(QuicPacketNumber start) {
sent_packet_manager_.one_rtt_packet_acked()) {
visitor_->OnOneRttPacketAcknowledged();
}
+ if (debug_visitor_ != nullptr && version().UsesTls() &&
+ !zero_rtt_packet_was_acked &&
+ sent_packet_manager_.zero_rtt_packet_acked()) {
+ debug_visitor_->OnZeroRttPacketAcked();
+ }
// Cancel the send alarm because new packets likely have been acked, which
// may change the congestion window and/or pacing rate. Canceling the alarm
// causes CanWrite to recalculate the next send time.
@@ -1451,23 +1482,49 @@ bool QuicConnection::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
QUIC_DLOG(INFO) << ENDPOINT << "STOP_SENDING frame received for stream: "
<< frame.stream_id
- << " with error: " << frame.application_error_code;
+ << " with error: " << frame.ietf_error_code;
visitor_->OnStopSendingFrame(frame);
return connected_;
}
bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
+ if (has_path_challenge_in_current_packet_) {
+ DCHECK(send_path_response_);
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 2, 5);
+ // Only respond to the 1st PATH_CHALLENGE.
+ return true;
+ }
UpdatePacketContent(PATH_CHALLENGE_FRAME);
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPathChallengeFrame(frame);
}
- // Save the path challenge's payload, for later use in generating the
- // response.
- received_path_challenge_payloads_.push_back(frame.data_buffer);
+ if (!send_path_response_) {
+ // Save the path challenge's payload, for later use in generating the
+ // response.
+ received_path_challenge_payloads_.push_back(frame.data_buffer);
+
+ MaybeUpdateAckTimeout();
+ return true;
+ }
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 3, 5);
+ has_path_challenge_in_current_packet_ = true;
MaybeUpdateAckTimeout();
- return true;
+ // Queue or send PATH_RESPONSE. No matter where the pending data are supposed
+ // to sent, PATH_RESPONSE should always be sent to the source address of the
+ // current incoming packet.
+ 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_});
+ }
+ // TODO(b/150095588): change the stats to
+ // num_valid_path_challenge_received.
+ ++stats_.num_connectivity_probing_received;
+
+ // SendPathResponse() might cause connection to be closed.
+ return connected_;
}
bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) {
@@ -1656,13 +1713,25 @@ bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) {
return connected_;
}
-bool QuicConnection::OnAckFrequencyFrame(
- const QuicAckFrequencyFrame& /*frame*/) {
+bool QuicConnection::OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) {
UpdatePacketContent(ACK_FREQUENCY_FRAME);
- // TODO(b/148614353): implement this fully.
- QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame.";
- return false;
+ if (!can_receive_ack_frequency_frame_) {
+ QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame.";
+ return false;
+ }
+ if (auto packet_number_space =
+ QuicUtils::GetPacketNumberSpace(last_decrypted_packet_level_) ==
+ APPLICATION_DATA) {
+ uber_received_packet_manager_.OnAckFrequencyFrame(frame);
+ } else {
+ QUIC_LOG_EVERY_N_SEC(ERROR, 120)
+ << "Get AckFrequencyFrame in packet number space "
+ << packet_number_space;
+ }
+ MaybeUpdateAckTimeout();
+ return true;
}
+
bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
DCHECK(connected_);
@@ -1716,7 +1785,6 @@ void QuicConnection::OnPacketComplete() {
uber_received_packet_manager_.MaybeUpdateAckTimeout(
should_last_packet_instigate_acks_, last_decrypted_packet_level_,
last_header_.packet_number,
- idle_network_detector_.time_of_last_received_packet(),
clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
}
@@ -1726,6 +1794,9 @@ void QuicConnection::OnPacketComplete() {
void QuicConnection::MaybeRespondToConnectivityProbingOrMigration() {
if (version().HasIetfQuicFrames()) {
+ if (send_path_response_) {
+ return;
+ }
if (perspective_ == Perspective::IS_CLIENT) {
// This node is a client, notify that a speculative connectivity probing
// packet has been received anyway.
@@ -1772,7 +1843,8 @@ void QuicConnection::MaybeRespondToConnectivityProbingOrMigration() {
}
// Server starts to migrate connection upon receiving of non-probing packet
// from a new peer address.
- if (last_header_.packet_number == GetLargestReceivedPacket()) {
+ 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
@@ -1875,47 +1947,6 @@ void QuicConnection::MaybeSendInResponseToPacket() {
}
}
-void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic,
- bool has_length_prefix) {
- pending_version_negotiation_packet_ = true;
- send_ietf_version_negotiation_packet_ = ietf_quic;
- send_version_negotiation_packet_with_prefixed_lengths_ = has_length_prefix;
-
- if (HandleWriteBlocked()) {
- return;
- }
-
- QUIC_DLOG(INFO) << ENDPOINT << "Sending version negotiation packet: {"
- << ParsedQuicVersionVectorToString(
- framer_.supported_versions())
- << "}, " << (ietf_quic ? "" : "!") << "ietf_quic";
- std::unique_ptr<QuicEncryptedPacket> version_packet(
- packet_creator_.SerializeVersionNegotiationPacket(
- ietf_quic, has_length_prefix, framer_.supported_versions()));
- QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {"
- << ParsedQuicVersionVectorToString(framer_.supported_versions())
- << "}, " << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl
- << quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece(
- version_packet->data(), version_packet->length()));
- WriteResult result = writer_->WritePacket(
- version_packet->data(), version_packet->length(), self_address().host(),
- peer_address(), per_packet_options_);
-
- if (IsWriteError(result.status)) {
- OnWriteError(result.error_code);
- return;
- }
- if (IsWriteBlockedStatus(result.status)) {
- visitor_->OnWriteBlocked();
- if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
- pending_version_negotiation_packet_ = false;
- }
- return;
- }
-
- pending_version_negotiation_packet_ = false;
-}
-
void QuicConnection::MaybeActivateLegacyVersionEncapsulation() {
if (!legacy_version_encapsulation_enabled_) {
return;
@@ -2143,10 +2174,6 @@ void QuicConnection::MaybeUpdatePacketCreatorMaxPacketLengthAndPadding() {
max_packet_length -= minimum_overhead;
}
packet_creator_.SetMaxPacketLength(max_packet_length);
- if (legacy_version_encapsulation_enabled_) {
- packet_creator_.set_disable_padding_override(
- legacy_version_encapsulation_in_progress_);
- }
}
void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
@@ -2174,7 +2201,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
}
if (!direct_peer_address_.IsInitialized()) {
- direct_peer_address_ = last_packet_source_address_;
+ UpdatePeerAddress(last_packet_source_address_);
}
if (!effective_peer_address_.IsInitialized()) {
@@ -2255,7 +2282,21 @@ void QuicConnection::OnCanWrite() {
if (!connected_) {
return;
}
- DCHECK(!writer_->IsWriteBlocked());
+ if (GetQuicReloadableFlag(
+ quic_close_connection_in_on_can_write_with_blocked_writer)) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_close_connection_in_on_can_write_with_blocked_writer);
+ if (writer_->IsWriteBlocked()) {
+ const std::string error_details =
+ "Writer is blocked while calling OnCanWrite.";
+ QUIC_BUG << ENDPOINT << error_details;
+ CloseConnection(QUIC_INTERNAL_ERROR, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ } else {
+ DCHECK(!writer_->IsWriteBlocked());
+ }
// Add a flusher to ensure the connection is marked app-limited.
ScopedPacketFlusher flusher(this);
@@ -2274,6 +2315,17 @@ void QuicConnection::OnCanWrite() {
}
}
+ // TODO(danzh) PATH_RESPONSE is of more interest to the peer than ACK,
+ // evaluate if it's worth to send them before sending ACKs.
+ while (!pending_path_challenge_payloads_.empty()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 4, 5);
+ std::pair<QuicPathFrameBuffer, QuicSocketAddress> pair =
+ pending_path_challenge_payloads_.front();
+ if (!SendPathResponse(pair.first, pair.second)) {
+ break;
+ }
+ pending_path_challenge_payloads_.pop_front();
+ }
WriteNewData();
}
@@ -2399,12 +2451,6 @@ bool QuicConnection::ValidateReceivedPacketNumber(
void QuicConnection::WriteQueuedPackets() {
DCHECK(!writer_->IsWriteBlocked());
- if (pending_version_negotiation_packet_) {
- SendVersionNegotiationPacket(
- send_ietf_version_negotiation_packet_,
- send_version_negotiation_packet_with_prefixed_lengths_);
- }
-
QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite",
buffered_packets_.size(), 1, 1000, 50, "");
@@ -2453,16 +2499,17 @@ void QuicConnection::SendProbingRetransmissions() {
}
}
-void QuicConnection::MarkZeroRttPacketsForRetransmission() {
+void QuicConnection::MarkZeroRttPacketsForRetransmission(int reject_reason) {
+ sent_packet_manager_.MarkZeroRttPacketsForRetransmission();
if (debug_visitor_ != nullptr && version().UsesTls()) {
- debug_visitor_->OnZeroRttRejected();
+ debug_visitor_->OnZeroRttRejected(reject_reason);
}
- sent_packet_manager_.MarkZeroRttPacketsForRetransmission();
}
void QuicConnection::NeuterUnencryptedPackets() {
sent_packet_manager_.NeuterUnencryptedPackets();
- if (GetQuicReloadableFlag(
+ if (!fix_missing_initial_keys_ &&
+ GetQuicReloadableFlag(
quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded) &&
version().CanSendCoalescedPackets()) {
QUIC_RELOADABLE_FLAG_COUNT(
@@ -2603,11 +2650,6 @@ QuicTime QuicConnection::CalculatePacketSentTime() {
}
bool QuicConnection::WritePacket(SerializedPacket* packet) {
- if (!packet_creator_.determine_serialized_packet_fate_early() &&
- ShouldDiscardPacket(packet->encryption_level)) {
- ++stats_.packets_discarded;
- return true;
- }
if (sent_packet_manager_.GetLargestSentPacket().IsInitialized() &&
packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) {
QUIC_BUG << "Attempt to write packet:" << packet->packet_number
@@ -2618,10 +2660,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
}
const bool is_mtu_discovery = QuicUtils::ContainsFrameType(
packet->nonretransmittable_frames, MTU_DISCOVERY_FRAME);
- const SerializedPacketFate fate =
- packet_creator_.determine_serialized_packet_fate_early()
- ? packet->fate
- : GetSerializedPacketFate(is_mtu_discovery, packet->encryption_level);
+ const SerializedPacketFate fate = packet->fate;
// Termination packets are encrypted and saved, so don't exit early.
QuicErrorCode error_code = QUIC_NO_ERROR;
const bool is_termination_packet = IsTerminationPacket(*packet, &error_code);
@@ -2675,15 +2714,17 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// during the WritePacket below.
QuicTime packet_send_time = CalculatePacketSentTime();
WriteResult result(WRITE_STATUS_OK, encrypted_length);
+ QuicSocketAddress send_to_address =
+ (send_path_response_) ? packet->peer_address : peer_address();
switch (fate) {
case DISCARD:
- DCHECK(packet_creator_.determine_serialized_packet_fate_early());
++stats_.packets_discarded;
return true;
case COALESCE:
QUIC_BUG_IF(!version().CanSendCoalescedPackets());
+ QUIC_BUG_IF(fix_out_of_order_sending_ && coalescing_done_);
if (!coalesced_packet_.MaybeCoalescePacket(
- *packet, self_address(), peer_address(),
+ *packet, self_address(), send_to_address,
helper_->GetStreamSendBufferAllocator(),
packet_creator_.max_packet_length())) {
// Failed to coalesce packet, flush current coalesced packet.
@@ -2691,8 +2732,21 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// Failed to flush coalesced packet, write error has been handled.
return false;
}
+ if (!fix_missing_initial_keys_ &&
+ GetQuicReloadableFlag(
+ quic_discard_initial_packet_with_key_dropped)) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_discard_initial_packet_with_key_dropped);
+ if (packet->encryption_level == ENCRYPTION_INITIAL &&
+ !framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) {
+ // Discard initial packet since flush of coalesce packet could
+ // cause initial keys to be dropped.
+ ++stats_.packets_discarded;
+ return true;
+ }
+ }
if (!coalesced_packet_.MaybeCoalescePacket(
- *packet, self_address(), peer_address(),
+ *packet, self_address(), send_to_address,
helper_->GetStreamSendBufferAllocator(),
packet_creator_.max_packet_length())) {
// Failed to coalesce packet even it is the only packet, raise a write
@@ -2713,9 +2767,13 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
case BUFFER:
QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number
<< " to buffered packets";
- buffered_packets_.emplace_back(*packet, self_address(), peer_address());
+ buffered_packets_.emplace_back(*packet, self_address(), send_to_address);
break;
case SEND_TO_WRITER:
+ if (fix_out_of_order_sending_ && !coalescing_done_) {
+ // Stop using coalsecer from now on.
+ coalescing_done_ = true;
+ }
// At this point, packet->release_encrypted_buffer is either nullptr,
// meaning |packet->encrypted_buffer| is a stack buffer, or not-nullptr,
/// meaning it's a writer-allocated buffer. Note that connectivity probing
@@ -2725,7 +2783,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// writer_->WritePacket transfers buffer ownership back to the writer.
packet->release_encrypted_buffer = nullptr;
result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length,
- self_address().host(), peer_address(),
+ self_address().host(), send_to_address,
per_packet_options_);
// This is a work around for an issue with linux UDP GSO batch writers.
// When sending a GSO packet with 2 segments, if the first segment is
@@ -2738,11 +2796,6 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
result = writer_->Flush();
}
break;
- case FAILED_TO_WRITE_COALESCED_PACKET:
- // Failed to send existing coalesced packet when determining packet fate,
- // write error has been handled.
- QUIC_BUG_IF(!version().CanSendCoalescedPackets());
- return false;
case LEGACY_VERSION_ENCAPSULATE: {
DCHECK(!is_mtu_discovery);
DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
@@ -2776,13 +2829,14 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
}
if (!buffered_packets_.empty() || HandleWriteBlocked()) {
// Buffer the packet.
- buffered_packets_.emplace_back(*packet, self_address(), peer_address());
+ buffered_packets_.emplace_back(*packet, self_address(),
+ send_to_address);
} else { // Send the packet to the writer.
// writer_->WritePacket transfers buffer ownership back to the writer.
packet->release_encrypted_buffer = nullptr;
result = writer_->WritePacket(packet->encrypted_buffer,
encrypted_length, self_address().host(),
- peer_address(), per_packet_options_);
+ send_to_address, per_packet_options_);
}
} break;
default:
@@ -2807,7 +2861,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number
<< " to buffered packets";
- buffered_packets_.emplace_back(*packet, self_address(), peer_address());
+ buffered_packets_.emplace_back(*packet, self_address(), send_to_address);
}
}
@@ -2830,7 +2884,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
QUIC_LOG_FIRST_N(ERROR, 10)
<< ENDPOINT << "Failed writing packet " << packet_number << " of "
<< encrypted_length << " bytes from " << self_address().host() << " to "
- << peer_address() << ", with error code " << result.error_code
+ << send_to_address << ", with error code " << result.error_code
<< ". long_term_mtu_:" << long_term_mtu_
<< ", previous_validated_mtu_:" << previous_validated_mtu_
<< ", max_packet_length():" << max_packet_length()
@@ -2849,7 +2903,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
packet_send_time = packet_send_time + result.send_time_offset;
}
- if (debug_visitor_ != nullptr) {
+ if (!sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() &&
+ debug_visitor_ != nullptr) {
// Pass the write result to the visitor.
debug_visitor_->OnPacketSent(*packet, packet->transmission_type,
packet_send_time);
@@ -2882,15 +2937,42 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
bytes_sent_before_address_validation_ += encrypted_length;
}
+ // Do not measure rtt of this packet if it's not sent on current path.
+ const bool measure_rtt = send_to_address == peer_address();
+ QUIC_DLOG_IF(INFO, !measure_rtt)
+ << ENDPOINT << " Sent packet " << packet->packet_number
+ << " on a different path with remote address " << send_to_address
+ << " while current path has peer address " << peer_address();
const bool in_flight = sent_packet_manager_.OnPacketSent(
packet, packet_send_time, packet->transmission_type,
- IsRetransmittable(*packet));
+ IsRetransmittable(*packet), measure_rtt);
QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ &&
blackhole_detector_.IsDetectionInProgress() &&
!sent_packet_manager_.HasInFlightPackets())
<< ENDPOINT
<< "Trying to start blackhole detection without no bytes in flight";
+ if (sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() &&
+ debug_visitor_ != nullptr) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_give_sent_packet_to_debug_visitor_after_sent, 1, 2);
+ if (sent_packet_manager_.unacked_packets().empty()) {
+ QUIC_BUG << "Unacked map is empty right after packet is sent";
+ } else {
+ debug_visitor_->OnPacketSent(
+ packet->packet_number, packet->encrypted_length,
+ packet->has_crypto_handshake, packet->transmission_type,
+ packet->encryption_level,
+ sent_packet_manager_.unacked_packets()
+ .rbegin()
+ ->retransmittable_frames,
+ packet->nonretransmittable_frames, packet_send_time);
+ }
+ }
+ if (packet->encryption_level == ENCRYPTION_HANDSHAKE) {
+ handshake_packet_sent_ = true;
+ }
+
if (in_flight || !retransmission_alarm_->IsSet()) {
SetRetransmissionAlarm();
}
@@ -2971,9 +3053,6 @@ bool QuicConnection::ShouldDiscardPacket(EncryptionLevel encryption_level) {
}
QuicTime QuicConnection::GetPathMtuReductionDeadline() const {
- if (!blackhole_detector_.revert_mtu_after_two_ptos()) {
- return QuicTime::Zero();
- }
if (previous_validated_mtu_ == 0) {
return QuicTime::Zero();
}
@@ -3026,7 +3105,14 @@ void QuicConnection::OnWriteError(int error_code) {
}
QuicPacketBuffer QuicConnection::GetPacketBuffer() {
- if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) {
+ if (fix_out_of_order_sending_) {
+ if (version().CanSendCoalescedPackets() && !coalescing_done_) {
+ // Do not use writer's packet buffer for coalesced packets which may
+ // contain
+ // multiple QUIC packets.
+ return {nullptr, nullptr};
+ }
+ } else if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) {
// Do not use writer's packet buffer for coalesced packets which may contain
// multiple QUIC packets.
return {nullptr, nullptr};
@@ -3131,10 +3217,7 @@ void QuicConnection::SendOrQueuePacket(SerializedPacket packet) {
}
void QuicConnection::OnPingTimeout() {
- if (retransmission_alarm_->IsSet()) {
- return;
- }
- if (GetQuicReloadableFlag(quic_fix_on_ping_timeout) &&
+ if (retransmission_alarm_->IsSet() ||
!visitor_->ShouldKeepConnectionAlive()) {
return;
}
@@ -3175,6 +3258,9 @@ void QuicConnection::OnRetransmissionTimeout() {
DCHECK(!IsHandshakeComplete());
}
#endif
+ if (fix_missing_connected_checks_ && !connected_) {
+ return;
+ }
QuicPacketNumber previous_created_packet_number =
packet_creator_.packet_number();
@@ -3288,11 +3374,9 @@ void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
}
encryption_level_ = level;
packet_creator_.set_encryption_level(level);
-
- if (!sent_packet_manager_.fix_packet_number_length()) {
- return;
- }
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_packet_number_length, 2, 2);
+ QUIC_BUG_IF(!framer_.HasEncrypterOfEncryptionLevel(level))
+ << ENDPOINT << "Trying to set encryption level to "
+ << EncryptionLevelToString(level) << " while the key is missing";
if (!changing_level) {
return;
@@ -3369,6 +3453,11 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
encryption_level_ == ENCRYPTION_INITIAL) {
return;
}
+ const bool fix_undecryptable_packets =
+ GetQuicReloadableFlag(quic_fix_undecryptable_packets2);
+ if (fix_undecryptable_packets) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_undecryptable_packets2);
+ }
auto iter = undecryptable_packets_.begin();
while (connected_ && iter != undecryptable_packets_.end()) {
@@ -3379,9 +3468,11 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
return;
}
UndecryptablePacket* undecryptable_packet = &*iter;
- ++iter;
- if (undecryptable_packet->processed) {
- continue;
+ if (!fix_undecryptable_packets) {
+ ++iter;
+ if (undecryptable_packet->processed) {
+ continue;
+ }
}
QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
if (debug_visitor_ != nullptr) {
@@ -3390,7 +3481,11 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
}
if (framer_.ProcessPacket(*undecryptable_packet->packet)) {
QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
- undecryptable_packet->processed = true;
+ if (fix_undecryptable_packets) {
+ iter = undecryptable_packets_.erase(iter);
+ } else {
+ undecryptable_packet->processed = true;
+ }
++stats_.packets_processed;
continue;
}
@@ -3403,14 +3498,21 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
QUIC_DVLOG(1)
<< ENDPOINT
<< "Need to attempt to process this undecryptable packet later";
+ if (fix_undecryptable_packets) {
+ ++iter;
+ }
continue;
}
- undecryptable_packet->processed = true;
+ if (fix_undecryptable_packets) {
+ iter = undecryptable_packets_.erase(iter);
+ } else {
+ undecryptable_packet->processed = true;
+ }
}
// Remove processed packets. We cannot remove elements in the while loop
// above because currently QuicCircularDeque does not support removing
// mid elements.
- while (!undecryptable_packets_.empty()) {
+ while (!fix_undecryptable_packets && !undecryptable_packets_.empty()) {
if (!undecryptable_packets_.front().processed) {
break;
}
@@ -3489,6 +3591,9 @@ void QuicConnection::CloseConnection(
void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
const std::string& details) {
+ // Always use the current path to send CONNECTION_CLOSE.
+ QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_,
+ peer_address());
if (!SupportsMultiplePacketNumberSpaces()) {
QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet.";
SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel());
@@ -3617,8 +3722,7 @@ void QuicConnection::SetMaxPacketLength(QuicByteCount length) {
}
bool QuicConnection::HasQueuedData() const {
- return pending_version_negotiation_packet_ ||
- packet_creator_.HasPendingFrames() || !buffered_packets_.empty();
+ return packet_creator_.HasPendingFrames() || !buffered_packets_.empty();
}
void QuicConnection::SetNetworkTimeouts(QuicTime::Delta handshake_timeout,
@@ -3692,6 +3796,13 @@ void QuicConnection::SetPingAlarm() {
}
void QuicConnection::SetRetransmissionAlarm() {
+ if (fix_missing_connected_checks_ && !connected_) {
+ if (retransmission_alarm_->IsSet()) {
+ QUIC_BUG << ENDPOINT << "Retransmission alarm is set while disconnected";
+ retransmission_alarm_->Cancel();
+ }
+ return;
+ }
if (packet_creator_.PacketFlusherAttached()) {
pending_retransmission_alarm_ = true;
return;
@@ -3718,7 +3829,9 @@ void QuicConnection::MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number) {
QuicConnection::ScopedPacketFlusher::ScopedPacketFlusher(
QuicConnection* connection)
: connection_(connection),
- flush_and_set_pending_retransmission_alarm_on_delete_(false) {
+ flush_and_set_pending_retransmission_alarm_on_delete_(false),
+ handshake_packet_sent_(connection != nullptr &&
+ connection->handshake_packet_sent_) {
if (connection_ == nullptr) {
return;
}
@@ -3767,13 +3880,17 @@ QuicConnection::ScopedPacketFlusher::~ScopedPacketFlusher() {
}
connection_->packet_creator_.Flush();
if (connection_->version().CanSendCoalescedPackets()) {
- if (connection_->packet_creator().coalesced_packet_of_higher_space()) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_coalesced_packet_of_higher_space2);
- connection_->MaybeCoalescePacketOfHigherSpace();
- }
+ connection_->MaybeCoalescePacketOfHigherSpace();
connection_->FlushCoalescedPacket();
}
connection_->FlushPackets();
+ if (connection_->fix_missing_initial_keys_ && !handshake_packet_sent_ &&
+ connection_->handshake_packet_sent_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_missing_initial_keys2, 1, 2);
+ // This would cause INITIAL key to be dropped. Drop keys here to avoid
+ // missing the write keys in the middle of writing.
+ connection_->visitor_->OnHandshakePacketSent();
+ }
// Reset transmission type.
connection_->SetTransmissionType(NOT_RETRANSMISSION);
@@ -3944,6 +4061,7 @@ bool QuicConnection::SendGenericPathProbePacket(
// request or a response.
probing_packet = packet_creator_.SerializeConnectivityProbingPacket();
} else if (is_response) {
+ DCHECK(!send_path_response_);
// IETF QUIC path response.
// Respond to path probe request using IETF QUIC PATH_RESPONSE frame.
probing_packet =
@@ -3991,15 +4109,34 @@ bool QuicConnection::SendGenericPathProbePacket(
return false;
}
- if (debug_visitor_ != nullptr) {
+ if (!sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() &&
+ debug_visitor_ != nullptr) {
debug_visitor_->OnPacketSent(
*probing_packet, probing_packet->transmission_type, packet_send_time);
}
- // Call OnPacketSent regardless of the write result.
- sent_packet_manager_.OnPacketSent(probing_packet.get(), packet_send_time,
- probing_packet->transmission_type,
- NO_RETRANSMITTABLE_DATA);
+ // Send in currrent path. Call OnPacketSent regardless of the write result.
+ sent_packet_manager_.OnPacketSent(
+ probing_packet.get(), packet_send_time, probing_packet->transmission_type,
+ NO_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+
+ if (sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() &&
+ debug_visitor_ != nullptr) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_give_sent_packet_to_debug_visitor_after_sent, 2, 2);
+ if (sent_packet_manager_.unacked_packets().empty()) {
+ QUIC_BUG << "Unacked map is empty right after packet is sent";
+ } else {
+ debug_visitor_->OnPacketSent(
+ probing_packet->packet_number, probing_packet->encrypted_length,
+ probing_packet->has_crypto_handshake,
+ probing_packet->transmission_type, probing_packet->encryption_level,
+ sent_packet_manager_.unacked_packets()
+ .rbegin()
+ ->retransmittable_frames,
+ probing_packet->nonretransmittable_frames, packet_send_time);
+ }
+ }
if (IsWriteBlockedStatus(result.status)) {
if (probing_writer == writer_) {
@@ -4066,6 +4203,13 @@ void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) {
}
void QuicConnection::OnConnectionMigration(AddressChangeType addr_change_type) {
+ if (debug_visitor_ != nullptr) {
+ const QuicTime now = clock_->ApproximateNow();
+ if (now >= stats_.handshake_completion_time) {
+ debug_visitor_->OnPeerAddressChange(
+ addr_change_type, now - stats_.handshake_completion_time);
+ }
+ }
visitor_->OnConnectionMigration(addr_change_type);
sent_packet_manager_.OnConnectionMigration(addr_change_type);
}
@@ -4130,7 +4274,8 @@ void QuicConnection::MaybeSendProbingRetransmissions() {
}
void QuicConnection::CheckIfApplicationLimited() {
- if (probing_retransmission_pending_) {
+ if ((fix_missing_connected_checks_ && !connected_) ||
+ probing_retransmission_pending_) {
return;
}
@@ -4152,14 +4297,14 @@ void QuicConnection::CheckIfApplicationLimited() {
}
void QuicConnection::UpdatePacketContent(QuicFrameType type) {
+ if (version().HasIetfQuicFrames()) {
+ MaybeStartIetfPeerMigration(type);
+ return;
+ }
// Packet content is tracked to identify connectivity probe in non-IETF
// version, where a connectivity probe is defined as
// - a padded PING packet with peer address change received by server,
// - a padded PING packet on new path received by client.
- if (version().HasIetfQuicFrames()) {
- // TODO(b/149315151) detect IETF non-probing packet.
- return;
- }
if (current_packet_content_ == NOT_PADDED_PING) {
// We have already learned the current packet is not a connectivity
@@ -4207,10 +4352,28 @@ void QuicConnection::UpdatePacketContent(QuicFrameType type) {
current_packet_content_ = NOT_PADDED_PING;
if (GetLargestReceivedPacket().IsInitialized() &&
last_header_.packet_number == GetLargestReceivedPacket()) {
- direct_peer_address_ = last_packet_source_address_;
+ UpdatePeerAddress(last_packet_source_address_);
if (current_effective_peer_migration_type_ != NO_CHANGE) {
// Start effective peer migration immediately when the current packet is
// confirmed not a connectivity probing packet.
+ StartEffectivePeerMigration(current_effective_peer_migration_type_);
+ }
+ }
+ current_effective_peer_migration_type_ = NO_CHANGE;
+}
+
+void QuicConnection::MaybeStartIetfPeerMigration(QuicFrameType type) {
+ DCHECK(version().HasIetfQuicFrames());
+ if (!start_peer_migration_earlier_ || QuicUtils::IsProbingFrame(type)) {
+ return;
+ }
+ QUIC_CODE_COUNT(quic_start_peer_migration_earlier);
+ if (GetLargestReceivedPacket().IsInitialized() &&
+ last_header_.packet_number == GetLargestReceivedPacket()) {
+ UpdatePeerAddress(last_packet_source_address_);
+ if (current_effective_peer_migration_type_ != NO_CHANGE) {
+ // Start effective peer migration when the current packet contains a
+ // non-probing frame.
// TODO(fayang): When multiple packet number spaces is supported, only
// start peer migration for the application data.
StartEffectivePeerMigration(current_effective_peer_migration_type_);
@@ -4345,23 +4508,15 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const {
void QuicConnection::MaybeBundleCryptoDataWithAcks() {
DCHECK(SupportsMultiplePacketNumberSpaces());
- if (GetQuicReloadableFlag(quic_retransmit_handshake_data_early) &&
- IsHandshakeConfirmed()) {
+ if (IsHandshakeConfirmed()) {
return;
}
PacketNumberSpace space = HANDSHAKE_DATA;
- if (perspective() == Perspective::IS_SERVER) {
- // On the server side, sends INITIAL data with INITIAL ACK. On the client
- // side, sends HANDSHAKE data (containing client Finished) with HANDSHAKE
- // ACK.
+ if (perspective() == Perspective::IS_SERVER &&
+ framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) {
+ // On the server side, sends INITIAL data with INITIAL ACK if initial key is
+ // available.
space = INITIAL_DATA;
- if (GetQuicReloadableFlag(quic_retransmit_handshake_data_early)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_retransmit_handshake_data_early);
- if (!framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) {
- // Retransmit HANDSHAKE data early.
- space = HANDSHAKE_DATA;
- }
- }
}
const QuicTime ack_timeout =
uber_received_packet_manager_.GetAckTimeout(space);
@@ -4377,6 +4532,16 @@ void QuicConnection::MaybeBundleCryptoDataWithAcks() {
return;
}
+ if (check_keys_before_writing_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_keys_before_writing, 1, 2);
+ if (!framer_.HasAnEncrypterForSpace(space)) {
+ QUIC_BUG << ENDPOINT
+ << "Try to bundle crypto with ACK with missing key of space "
+ << PacketNumberSpaceToString(space);
+ return;
+ }
+ }
+
sent_packet_manager_.RetransmitDataOfSpaceIfAny(space);
}
@@ -4400,6 +4565,13 @@ void QuicConnection::SendAllPendingAcks() {
if (!ack_timeout.IsInitialized()) {
continue;
}
+ if (check_keys_before_writing_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_keys_before_writing, 2, 2);
+ if (!framer_.HasAnEncrypterForSpace(static_cast<PacketNumberSpace>(i))) {
+ // The key has been dropped.
+ continue;
+ }
+ }
if (ack_timeout > clock_->ApproximateNow() &&
ack_timeout > earliest_ack_timeout) {
// Always send the earliest ACK to make forward progress in case alarm
@@ -4500,10 +4672,25 @@ void QuicConnection::MaybeCoalescePacketOfHigherSpace() {
bool QuicConnection::FlushCoalescedPacket() {
ScopedCoalescedPacketClearer clearer(&coalesced_packet_);
+ if (fix_missing_connected_checks_ && !connected_) {
+ return false;
+ }
if (!version().CanSendCoalescedPackets()) {
QUIC_BUG_IF(coalesced_packet_.length() > 0);
return true;
}
+ if (fix_missing_initial_keys_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_missing_initial_keys2, 2, 2);
+ if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_INITIAL) &&
+ !framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) {
+ // Initial packet will be re-serialized. Neuter it in case initial key has
+ // been dropped.
+ QUIC_BUG << ENDPOINT
+ << "Coalescer contains initial packet while initial key has "
+ "been dropped.";
+ coalesced_packet_.NeuterInitialPacket();
+ }
+ }
if (coalesced_packet_.length() == 0) {
return true;
}
@@ -4520,13 +4707,14 @@ bool QuicConnection::FlushCoalescedPacket() {
if (!buffered_packets_.empty() || HandleWriteBlocked()) {
QUIC_DVLOG(1) << ENDPOINT
<< "Buffering coalesced packet of len: " << length;
- buffered_packets_.emplace_back(buffer, length,
- coalesced_packet_.self_address(),
- coalesced_packet_.peer_address());
+ buffered_packets_.emplace_back(
+ buffer, static_cast<QuicPacketLength>(length),
+ coalesced_packet_.self_address(), coalesced_packet_.peer_address());
if (debug_visitor_ != nullptr) {
debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
}
- if (coalesced_packet_.ContainsPacketOfEncryptionLevel(
+ if (!fix_missing_initial_keys_ &&
+ coalesced_packet_.ContainsPacketOfEncryptionLevel(
ENCRYPTION_HANDSHAKE)) {
// This is only called in coalescer because all ENCRYPTION_HANDSHAKE
// packets go through the coalescer.
@@ -4547,15 +4735,16 @@ bool QuicConnection::FlushCoalescedPacket() {
if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
QUIC_DVLOG(1) << ENDPOINT
<< "Buffering coalesced packet of len: " << length;
- buffered_packets_.emplace_back(buffer, length,
- coalesced_packet_.self_address(),
- coalesced_packet_.peer_address());
+ buffered_packets_.emplace_back(
+ buffer, static_cast<QuicPacketLength>(length),
+ coalesced_packet_.self_address(), coalesced_packet_.peer_address());
}
}
if (debug_visitor_ != nullptr) {
debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
}
- if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_HANDSHAKE)) {
+ if (!fix_missing_initial_keys_ &&
+ coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_HANDSHAKE)) {
// This is only called in coalescer because all ENCRYPTION_HANDSHAKE
// packets go through the coalescer.
visitor_->OnHandshakePacketSent();
@@ -4651,34 +4840,34 @@ bool QuicConnection::EnforceAntiAmplificationLimit() const {
bool QuicConnection::LimitedByAmplificationFactor() const {
return EnforceAntiAmplificationLimit() &&
bytes_sent_before_address_validation_ >=
- GetQuicFlag(FLAGS_quic_anti_amplification_factor) *
+ anti_amplification_factor_ *
bytes_received_before_address_validation_;
}
SerializedPacketFate QuicConnection::GetSerializedPacketFate(
bool is_mtu_discovery,
EncryptionLevel encryption_level) {
- if (packet_creator_.determine_serialized_packet_fate_early()) {
- if (ShouldDiscardPacket(encryption_level)) {
- return DISCARD;
- }
+ if (ShouldDiscardPacket(encryption_level)) {
+ return DISCARD;
}
if (legacy_version_encapsulation_in_progress_) {
DCHECK(!is_mtu_discovery);
return LEGACY_VERSION_ENCAPSULATE;
}
- if (version().CanSendCoalescedPackets()) {
- // Disable coalescing when Legacy Version Encapsulation is in use to avoid
- // having to reframe encapsulated packets.
- if (!IsHandshakeConfirmed() && !is_mtu_discovery) {
+ if (version().CanSendCoalescedPackets() && !coalescing_done_ &&
+ !is_mtu_discovery) {
+ if (!IsHandshakeConfirmed()) {
// Before receiving ACK for any 1-RTT packets, always try to coalesce
// packet (except MTU discovery packet).
return COALESCE;
}
- // Packet cannot be coalesced, flush existing coalesced packet.
- if (!packet_creator_.determine_serialized_packet_fate_early() &&
- !FlushCoalescedPacket()) {
- return FAILED_TO_WRITE_COALESCED_PACKET;
+ if (fix_out_of_order_sending_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_out_of_order_sending2);
+ if (coalesced_packet_.length() > 0) {
+ // If the coalescer is not empty, let this packet go through coalescer
+ // to avoid potential out of order sending.
+ return COALESCE;
+ }
}
}
if (!buffered_packets_.empty() || HandleWriteBlocked()) {
@@ -4705,11 +4894,6 @@ void QuicConnection::set_min_received_before_ack_decimation(size_t new_value) {
new_value);
}
-void QuicConnection::set_ack_frequency(size_t new_value) {
- DCHECK_GT(new_value, 0u);
- uber_received_packet_manager_.set_ack_frequency(new_value);
-}
-
const QuicAckFrame& QuicConnection::ack_frame() const {
if (SupportsMultiplePacketNumberSpaces()) {
return uber_received_packet_manager_.GetAckFrame(
@@ -4755,12 +4939,7 @@ void QuicConnection::OnBlackholeDetected() {
}
void QuicConnection::OnPathMtuReductionDetected() {
- DCHECK(blackhole_detector_.revert_mtu_after_two_ptos());
- if (MaybeRevertToPreviousMtu()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_revert_mtu_after_two_ptos, 1, 2);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_revert_mtu_after_two_ptos, 2, 2);
- }
+ MaybeRevertToPreviousMtu();
}
void QuicConnection::OnHandshakeTimeout() {
@@ -4783,15 +4962,23 @@ void QuicConnection::OnIdleNetworkDetected() {
const QuicTime::Delta duration =
clock_->ApproximateNow() -
idle_network_detector_.last_network_activity_time();
- const std::string error_details = quiche::QuicheStrCat(
+ std::string error_details = quiche::QuicheStrCat(
"No recent network activity after ", duration.ToDebuggingValue(),
". Timeout:",
idle_network_detector_.idle_network_timeout().ToDebuggingValue());
QUIC_DVLOG(1) << ENDPOINT << error_details;
- if ((sent_packet_manager_.GetConsecutiveTlpCount() > 0 ||
- sent_packet_manager_.GetConsecutiveRtoCount() > 0 ||
- sent_packet_manager_.GetConsecutivePtoCount() > 0 ||
- visitor_->ShouldKeepConnectionAlive())) {
+ const bool has_consecutive_pto =
+ sent_packet_manager_.GetConsecutiveTlpCount() > 0 ||
+ sent_packet_manager_.GetConsecutiveRtoCount() > 0 ||
+ sent_packet_manager_.GetConsecutivePtoCount() > 0;
+ if (has_consecutive_pto || visitor_->ShouldKeepConnectionAlive()) {
+ if (GetQuicReloadableFlag(quic_add_stream_info_to_idle_close_detail) &&
+ !has_consecutive_pto) {
+ // Include stream information in error detail if there are open streams.
+ QUIC_RELOADABLE_FLAG_COUNT(quic_add_stream_info_to_idle_close_detail);
+ error_details = quiche::QuicheStrCat(
+ error_details, ", ", visitor_->GetStreamsInfoForLogging());
+ }
CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, error_details,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
@@ -4814,7 +5001,6 @@ void QuicConnection::MaybeUpdateAckTimeout() {
uber_received_packet_manager_.MaybeUpdateAckTimeout(
/*should_last_packet_instigate_acks=*/true, last_decrypted_packet_level_,
last_header_.packet_number,
- idle_network_detector_.time_of_last_received_packet(),
clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
}
@@ -4864,5 +5050,21 @@ bool QuicConnection::ShouldDetectBlackhole() const {
return num_rtos_for_blackhole_detection_ > 0;
}
+bool QuicConnection::SendPathResponse(const QuicPathFrameBuffer& data_buffer,
+ QuicSocketAddress peer_address_to_send) {
+ // 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.
+ QUIC_DVLOG(1) << ENDPOINT << "Send PATH_RESPONSE to " << peer_address_to_send;
+ QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_,
+ peer_address_to_send);
+ return packet_creator_.AddPathResponseFrame(data_buffer);
+}
+
+void QuicConnection::UpdatePeerAddress(QuicSocketAddress peer_address) {
+ direct_peer_address_ = peer_address;
+ packet_creator_.SetDefaultPeerAddress(peer_address);
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
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 ba04b9f740c..9b4544ff7b4 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
@@ -170,6 +170,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// transactions expecting a response.
virtual bool ShouldKeepConnectionAlive() const = 0;
+ // Called to retrieve streams information for logging purpose.
+ virtual std::string GetStreamsInfoForLogging() const = 0;
+
// Called when a self address change is observed. Returns true if self address
// change is allowed.
virtual bool AllowSelfAddressChange() const = 0;
@@ -199,10 +202,21 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor
~QuicConnectionDebugVisitor() override {}
// Called when a packet has been sent.
+ // TODO(wub): Delete when deprecating
+ // --quic_give_sent_packet_to_debug_visitor_after_sent.
virtual void OnPacketSent(const SerializedPacket& /*serialized_packet*/,
TransmissionType /*transmission_type*/,
QuicTime /*sent_time*/) {}
+ virtual void OnPacketSent(QuicPacketNumber /*packet_number*/,
+ QuicPacketLength /*packet_length*/,
+ bool /*has_crypto_handshake*/,
+ TransmissionType /*transmission_type*/,
+ EncryptionLevel /*encryption_level*/,
+ const QuicFrames& /*retransmittable_frames*/,
+ const QuicFrames& /*nonretransmittable_frames*/,
+ QuicTime /*sent_time*/) {}
+
// Called when a coalesced packet has been sent.
virtual void OnCoalescedPacketSent(
const QuicCoalescedPacket& /*coalesced_packet*/,
@@ -361,7 +375,14 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor
const TransportParameters& /*transport_parameters*/) {}
// Called for QUIC+TLS versions when 0-RTT is rejected.
- virtual void OnZeroRttRejected() {}
+ virtual void OnZeroRttRejected(int /*reject_reason*/) {}
+
+ // Called for QUIC+TLS versions when 0-RTT packet gets acked.
+ virtual void OnZeroRttPacketAcked() {}
+
+ // Called on peer address change.
+ virtual void OnPeerAddressChange(AddressChangeType /*type*/,
+ QuicTime::Delta /*connection_time*/) {}
};
class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface {
@@ -716,8 +737,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Mark all sent 0-RTT encrypted packets for retransmission. Called when new
// 0-RTT or 1-RTT key is available in gQUIC, or when 0-RTT is rejected in IETF
- // QUIC.
- void MarkZeroRttPacketsForRetransmission();
+ // QUIC. |reject_reason| is used in TLS-QUIC to log why 0-RTT was rejected.
+ void MarkZeroRttPacketsForRetransmission(int reject_reason);
// Calls |sent_packet_manager_|'s NeuterUnencryptedPackets. Used when the
// connection becomes forward secure and hasn't received acks for all packets.
@@ -800,6 +821,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// If true, when this flusher goes out of scope, flush connection and set
// retransmission alarm if there is one pending.
bool flush_and_set_pending_retransmission_alarm_on_delete_;
+ // Latched connection's handshake_packet_sent_ on creation of this flusher.
+ const bool handshake_packet_sent_;
};
QuicPacketWriter* writer() { return writer_; }
@@ -823,6 +846,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Sends response to a connectivity probe. Sends either a Padded Ping
// or an IETF PATH_RESPONSE based on the version of the connection.
// Is the counterpart to SendConnectivityProbingPacket().
+ // TODO(danzh): remove this method after deprecating
+ // --gfe2_reloadable_flag_quic_send_path_response.
virtual void SendConnectivityProbingResponsePacket(
const QuicSocketAddress& peer_address);
@@ -909,8 +934,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection
size_t min_received_before_ack_decimation() const;
void set_min_received_before_ack_decimation(size_t new_value);
- void set_ack_frequency(size_t new_value);
-
// If |defer| is true, configures the connection to defer sending packets in
// response to an ACK to the SendAlarm. If |defer| is false, packets may be
// sent immediately after receiving an ACK.
@@ -1007,11 +1030,23 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Can only be set if this is a client connection.
void EnableLegacyVersionEncapsulation(const std::string& server_name);
+ bool send_path_response() const { return send_path_response_; }
+
// If now is close to idle timeout, returns true and sends a connectivity
// probing packet to test the connection for liveness. Otherwise, returns
// false.
bool MaybeTestLiveness();
+ bool can_receive_ack_frequency_frame() const {
+ return can_receive_ack_frequency_frame_;
+ }
+
+ void set_can_receive_ack_frequency_frame() {
+ can_receive_ack_frequency_frame_ = true;
+ }
+
+ bool check_keys_before_writing() const { return check_keys_before_writing_; }
+
protected:
// Calls cancel() on all the alarms owned by this connection.
void CancelAllAlarms();
@@ -1131,6 +1166,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// This gets set to true if 1) connection sucessfully processed the packet
// or 2) connection failed to process the packet and will not try to process
// it later.
+ // TODO(fayang): Remove this when deprecating
+ // quic_fix_undecryptable_packets2.
bool processed;
};
@@ -1247,9 +1284,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
void UpdateReleaseTimeIntoFuture();
// Sends generic path probe packet to the peer. If we are not IETF QUIC, will
- // always send a padded ping, regardless of whether this is a request or
- // response. If version 99/ietf quic, will send a PATH_RESPONSE if
- // |is_response| is true, a PATH_CHALLENGE if not.
+ // always send a padded ping, regardless of whether this is a request or not.
+ // TODO(danzh): remove |is_response| after deprecating
+ // --gfe2_reloadable_flag_quic_send_path_response.
bool SendGenericPathProbePacket(QuicPacketWriter* probing_writer,
const QuicSocketAddress& peer_address,
bool is_response);
@@ -1368,6 +1405,17 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// deprecated.
void MaybeRespondToConnectivityProbingOrMigration();
+ // Called in IETF QUIC. Start peer migration if a non-probing frame is
+ // received and the current packet number is largest received so far.
+ void MaybeStartIetfPeerMigration(QuicFrameType type);
+
+ // Send PATH_RESPONSE to the given peer address.
+ bool SendPathResponse(const QuicPathFrameBuffer& data_buffer,
+ QuicSocketAddress peer_address_to_send);
+
+ // Update both connection's and packet creator's peer address.
+ void UpdatePeerAddress(QuicSocketAddress peer_address);
+
QuicFramer framer_;
// Contents received in the current packet, especially used to identify
@@ -1378,6 +1426,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Always false outside the context of ProcessUdpPacket().
bool is_current_packet_connectivity_probing_;
+ bool has_path_challenge_in_current_packet_;
+
// Caches the current effective peer migration type if a effective peer
// migration might be initiated. As soon as the current packet is confirmed
// not a connectivity probe, effective peer migration will start.
@@ -1403,6 +1453,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicSocketAddress self_address_;
QuicSocketAddress peer_address_;
+ // Other than initialization, do not modify it directly, use
+ // UpdatePeerAddress() instead.
QuicSocketAddress direct_peer_address_;
// Address of the endpoint behind the proxy if the connection is proxied.
// Otherwise it is the same as |peer_address_|.
@@ -1448,7 +1500,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// established, but which could not be decrypted. We buffer these on
// the assumption that they could not be processed because they were
// sent with the INITIAL encryption and the CHLO message was lost.
- QuicCircularDeque<UndecryptablePacket> undecryptable_packets_;
+ std::deque<UndecryptablePacket> undecryptable_packets_;
// Collection of coalesced packets which were received while processing
// the current packet.
@@ -1461,13 +1513,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Maximum number of tracked packets.
QuicPacketCount max_tracked_packets_;
- // When the version negotiation packet could not be sent because the socket
- // was not writable, this is set to true.
- bool pending_version_negotiation_packet_;
- // Used when pending_version_negotiation_packet_ is true.
- bool send_ietf_version_negotiation_packet_;
- bool send_version_negotiation_packet_with_prefixed_lengths_;
-
// Contains the connection close packets if the connection has been closed.
std::unique_ptr<std::vector<std::unique_ptr<QuicEncryptedPacket>>>
termination_packets_;
@@ -1651,8 +1696,16 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Deque because the peer might no be using this implementation, and others
// might send a packet with more than one PATH_CHALLENGE, so all need to be
// saved and responded to.
+ // TODO(danzh) deprecate this field when deprecating
+ // --quic_send_path_response.
QuicCircularDeque<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<std::pair<QuicPathFrameBuffer, QuicSocketAddress>>
+ 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
// vector to improve performance since it is expected to be very small.
@@ -1720,6 +1773,37 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// True if next packet is intended to consume remaining space in the
// coalescer.
bool fill_coalesced_packet_ = false;
+
+ size_t anti_amplification_factor_ =
+ GetQuicFlag(FLAGS_quic_anti_amplification_factor);
+
+ bool start_peer_migration_earlier_ =
+ GetQuicReloadableFlag(quic_start_peer_migration_earlier);
+
+ bool fix_missing_connected_checks_ =
+ GetQuicReloadableFlag(quic_add_missing_connected_checks);
+
+ // 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_response);
+ // True if AckFrequencyFrame is supported.
+ bool can_receive_ack_frequency_frame_ = false;
+
+ // Indicate whether coalescing is done.
+ bool coalescing_done_ = false;
+
+ // Indicate whether any ENCRYPTION_HANDSHAKE packet has been sent.
+ bool handshake_packet_sent_ = false;
+
+ const bool fix_missing_initial_keys_ =
+ GetQuicReloadableFlag(quic_fix_missing_initial_keys2);
+
+ const bool fix_out_of_order_sending_ =
+ GetQuicReloadableFlag(quic_fix_out_of_order_sending2);
+
+ const bool check_keys_before_writing_ =
+ GetQuicReloadableFlag(quic_check_keys_before_writing);
};
} // namespace quic
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 d33cb353a76..3acac1c22dc 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
@@ -24,7 +24,6 @@
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_error_code_wrappers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -40,7 +39,6 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h"
-#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
#include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
@@ -110,162 +108,6 @@ QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) {
}
}
-// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message.
-class TaggingEncrypter : public QuicEncrypter {
- public:
- explicit TaggingEncrypter(uint8_t tag) : tag_(tag) {}
- TaggingEncrypter(const TaggingEncrypter&) = delete;
- TaggingEncrypter& operator=(const TaggingEncrypter&) = delete;
-
- ~TaggingEncrypter() override {}
-
- // QuicEncrypter interface.
- bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; }
-
- bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override {
- return true;
- }
-
- bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; }
-
- bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override {
- return true;
- }
-
- bool EncryptPacket(uint64_t /*packet_number*/,
- quiche::QuicheStringPiece /*associated_data*/,
- quiche::QuicheStringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override {
- const size_t len = plaintext.size() + kTagSize;
- if (max_output_length < len) {
- return false;
- }
- // Memmove is safe for inplace encryption.
- memmove(output, plaintext.data(), plaintext.size());
- output += plaintext.size();
- memset(output, tag_, kTagSize);
- *output_length = len;
- return true;
- }
-
- std::string GenerateHeaderProtectionMask(
- quiche::QuicheStringPiece /*sample*/) override {
- return std::string(5, 0);
- }
-
- size_t GetKeySize() const override { return 0; }
- size_t GetNoncePrefixSize() const override { return 0; }
- size_t GetIVSize() const override { return 0; }
-
- size_t GetMaxPlaintextSize(size_t ciphertext_size) const override {
- return ciphertext_size - kTagSize;
- }
-
- size_t GetCiphertextSize(size_t plaintext_size) const override {
- return plaintext_size + kTagSize;
- }
-
- quiche::QuicheStringPiece GetKey() const override {
- return quiche::QuicheStringPiece();
- }
-
- quiche::QuicheStringPiece GetNoncePrefix() const override {
- return quiche::QuicheStringPiece();
- }
-
- private:
- enum {
- kTagSize = 12,
- };
-
- const uint8_t tag_;
-};
-
-// TaggingDecrypter ensures that the final kTagSize bytes of the message all
-// have the same value and then removes them.
-class TaggingDecrypter : public QuicDecrypter {
- public:
- ~TaggingDecrypter() override {}
-
- // QuicDecrypter interface
- bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; }
-
- bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override {
- return true;
- }
-
- bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; }
-
- bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override {
- return true;
- }
-
- bool SetPreliminaryKey(quiche::QuicheStringPiece /*key*/) override {
- QUIC_BUG << "should not be called";
- return false;
- }
-
- bool SetDiversificationNonce(const DiversificationNonce& /*key*/) override {
- return true;
- }
-
- bool DecryptPacket(uint64_t /*packet_number*/,
- quiche::QuicheStringPiece /*associated_data*/,
- quiche::QuicheStringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t /*max_output_length*/) override {
- if (ciphertext.size() < kTagSize) {
- return false;
- }
- if (!CheckTag(ciphertext, GetTag(ciphertext))) {
- return false;
- }
- *output_length = ciphertext.size() - kTagSize;
- memcpy(output, ciphertext.data(), *output_length);
- return true;
- }
-
- std::string GenerateHeaderProtectionMask(
- QuicDataReader* /*sample_reader*/) override {
- return std::string(5, 0);
- }
-
- size_t GetKeySize() const override { return 0; }
- size_t GetNoncePrefixSize() const override { return 0; }
- size_t GetIVSize() const override { return 0; }
- quiche::QuicheStringPiece GetKey() const override {
- return quiche::QuicheStringPiece();
- }
- quiche::QuicheStringPiece GetNoncePrefix() const override {
- return quiche::QuicheStringPiece();
- }
- // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
- uint32_t cipher_id() const override { return 0xFFFFFFF0; }
-
- protected:
- virtual uint8_t GetTag(quiche::QuicheStringPiece ciphertext) {
- return ciphertext.data()[ciphertext.size() - 1];
- }
-
- private:
- enum {
- kTagSize = 12,
- };
-
- bool CheckTag(quiche::QuicheStringPiece ciphertext, uint8_t tag) {
- for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) {
- if (ciphertext.data()[i] != tag) {
- return false;
- }
- }
-
- return true;
- }
-};
-
// StringTaggingDecrypter ensures that the final kTagSize bytes of the message
// match the expected value.
class StrictTaggingDecrypter : public TaggingDecrypter {
@@ -336,345 +178,6 @@ class TestAlarmFactory : public QuicAlarmFactory {
}
};
-class TestPacketWriter : public QuicPacketWriter {
- struct PacketBuffer {
- QUIC_CACHELINE_ALIGNED char buffer[1500];
- bool in_use = false;
- };
-
- public:
- TestPacketWriter(ParsedQuicVersion version, MockClock* clock)
- : version_(version),
- framer_(SupportedVersions(version_), Perspective::IS_SERVER),
- clock_(clock) {
- QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
- TestConnectionId());
- framer_.framer()->SetInitialObfuscators(TestConnectionId());
-
- for (int i = 0; i < 128; ++i) {
- PacketBuffer* p = new PacketBuffer();
- packet_buffer_pool_.push_back(p);
- packet_buffer_pool_index_[p->buffer] = p;
- packet_buffer_free_list_.push_back(p);
- }
- }
- TestPacketWriter(const TestPacketWriter&) = delete;
- TestPacketWriter& operator=(const TestPacketWriter&) = delete;
-
- ~TestPacketWriter() override {
- EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size())
- << packet_buffer_pool_.size() - packet_buffer_free_list_.size()
- << " out of " << packet_buffer_pool_.size()
- << " packet buffers have been leaked.";
- for (auto p : packet_buffer_pool_) {
- delete p;
- }
- }
-
- // QuicPacketWriter interface
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const QuicIpAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/,
- PerPacketOptions* /*options*/) override {
- // If the buffer is allocated from the pool, return it back to the pool.
- // Note the buffer content doesn't change.
- if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) !=
- packet_buffer_pool_index_.end()) {
- FreePacketBuffer(buffer);
- }
-
- QuicEncryptedPacket packet(buffer, buf_len);
- ++packets_write_attempts_;
-
- if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
- final_bytes_of_previous_packet_ = final_bytes_of_last_packet_;
- memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4,
- sizeof(final_bytes_of_last_packet_));
- }
-
- if (use_tagging_decrypter_) {
- if (framer_.framer()->version().KnowsWhichDecrypterToUse()) {
- framer_.framer()->InstallDecrypter(
- ENCRYPTION_INITIAL, std::make_unique<TaggingDecrypter>());
- framer_.framer()->InstallDecrypter(
- ENCRYPTION_HANDSHAKE, std::make_unique<TaggingDecrypter>());
- framer_.framer()->InstallDecrypter(
- ENCRYPTION_ZERO_RTT, std::make_unique<TaggingDecrypter>());
- framer_.framer()->InstallDecrypter(
- ENCRYPTION_FORWARD_SECURE, std::make_unique<TaggingDecrypter>());
- } else {
- framer_.framer()->SetDecrypter(ENCRYPTION_INITIAL,
- std::make_unique<TaggingDecrypter>());
- }
- } else if (framer_.framer()->version().KnowsWhichDecrypterToUse()) {
- framer_.framer()->InstallDecrypter(
- ENCRYPTION_FORWARD_SECURE,
- std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
- }
- EXPECT_TRUE(framer_.ProcessPacket(packet))
- << framer_.framer()->detailed_error();
- if (block_on_next_write_) {
- write_blocked_ = true;
- block_on_next_write_ = false;
- }
- if (next_packet_too_large_) {
- next_packet_too_large_ = false;
- return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
- }
- if (always_get_packet_too_large_) {
- return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
- }
- if (IsWriteBlocked()) {
- return WriteResult(is_write_blocked_data_buffered_
- ? WRITE_STATUS_BLOCKED_DATA_BUFFERED
- : WRITE_STATUS_BLOCKED,
- 0);
- }
-
- if (ShouldWriteFail()) {
- return WriteResult(WRITE_STATUS_ERROR, 0);
- }
-
- last_packet_size_ = packet.length();
- last_packet_header_ = framer_.header();
- if (!framer_.connection_close_frames().empty()) {
- ++connection_close_packets_;
- }
- if (!write_pause_time_delta_.IsZero()) {
- clock_->AdvanceTime(write_pause_time_delta_);
- }
- if (is_batch_mode_) {
- bytes_buffered_ += last_packet_size_;
- return WriteResult(WRITE_STATUS_OK, 0);
- }
- return WriteResult(WRITE_STATUS_OK, last_packet_size_);
- }
-
- bool ShouldWriteFail() { return write_should_fail_; }
-
- bool IsWriteBlocked() const override { return write_blocked_; }
-
- void SetWriteBlocked() { write_blocked_ = true; }
-
- void SetWritable() override { write_blocked_ = false; }
-
- void SetShouldWriteFail() { write_should_fail_ = true; }
-
- QuicByteCount GetMaxPacketSize(
- const QuicSocketAddress& /*peer_address*/) const override {
- return max_packet_size_;
- }
-
- bool SupportsReleaseTime() const override { return supports_release_time_; }
-
- bool IsBatchMode() const override { return is_batch_mode_; }
-
- QuicPacketBuffer GetNextWriteLocation(
- const QuicIpAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/) override {
- return {AllocPacketBuffer(),
- [this](const char* p) { FreePacketBuffer(p); }};
- }
-
- WriteResult Flush() override {
- flush_attempts_++;
- if (block_on_next_flush_) {
- block_on_next_flush_ = false;
- SetWriteBlocked();
- return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1);
- }
- if (write_should_fail_) {
- return WriteResult(WRITE_STATUS_ERROR, /*errno*/ -1);
- }
- int bytes_flushed = bytes_buffered_;
- bytes_buffered_ = 0;
- return WriteResult(WRITE_STATUS_OK, bytes_flushed);
- }
-
- void BlockOnNextFlush() { block_on_next_flush_ = true; }
-
- void BlockOnNextWrite() { block_on_next_write_ = true; }
-
- void SimulateNextPacketTooLarge() { next_packet_too_large_ = true; }
-
- void AlwaysGetPacketTooLarge() { always_get_packet_too_large_ = true; }
-
- // Sets the amount of time that the writer should before the actual write.
- void SetWritePauseTimeDelta(QuicTime::Delta delta) {
- write_pause_time_delta_ = delta;
- }
-
- void SetBatchMode(bool new_value) { is_batch_mode_ = new_value; }
-
- const QuicPacketHeader& header() { return framer_.header(); }
-
- size_t frame_count() const { return framer_.num_frames(); }
-
- const std::vector<QuicAckFrame>& ack_frames() const {
- return framer_.ack_frames();
- }
-
- const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
- return framer_.stop_waiting_frames();
- }
-
- const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const {
- return framer_.connection_close_frames();
- }
-
- const std::vector<QuicRstStreamFrame>& rst_stream_frames() const {
- return framer_.rst_stream_frames();
- }
-
- const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const {
- return framer_.stream_frames();
- }
-
- const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const {
- return framer_.crypto_frames();
- }
-
- const std::vector<QuicPingFrame>& ping_frames() const {
- return framer_.ping_frames();
- }
-
- const std::vector<QuicMessageFrame>& message_frames() const {
- return framer_.message_frames();
- }
-
- const std::vector<QuicWindowUpdateFrame>& window_update_frames() const {
- return framer_.window_update_frames();
- }
-
- const std::vector<QuicPaddingFrame>& padding_frames() const {
- return framer_.padding_frames();
- }
-
- const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const {
- return framer_.path_challenge_frames();
- }
-
- const std::vector<QuicPathResponseFrame>& path_response_frames() const {
- return framer_.path_response_frames();
- }
-
- const QuicEncryptedPacket* coalesced_packet() const {
- return framer_.coalesced_packet();
- }
-
- size_t last_packet_size() { return last_packet_size_; }
-
- const QuicPacketHeader& last_packet_header() const {
- return last_packet_header_;
- }
-
- const QuicVersionNegotiationPacket* version_negotiation_packet() {
- return framer_.version_negotiation_packet();
- }
-
- void set_is_write_blocked_data_buffered(bool buffered) {
- is_write_blocked_data_buffered_ = buffered;
- }
-
- void set_perspective(Perspective perspective) {
- // We invert perspective here, because the framer needs to parse packets
- // we send.
- QuicFramerPeer::SetPerspective(framer_.framer(),
- QuicUtils::InvertPerspective(perspective));
- }
-
- // final_bytes_of_last_packet_ returns the last four bytes of the previous
- // packet as a little-endian, uint32_t. This is intended to be used with a
- // TaggingEncrypter so that tests can determine which encrypter was used for
- // a given packet.
- uint32_t final_bytes_of_last_packet() { return final_bytes_of_last_packet_; }
-
- // Returns the final bytes of the second to last packet.
- uint32_t final_bytes_of_previous_packet() {
- return final_bytes_of_previous_packet_;
- }
-
- void use_tagging_decrypter() { use_tagging_decrypter_ = true; }
-
- uint32_t packets_write_attempts() const { return packets_write_attempts_; }
-
- uint32_t flush_attempts() const { return flush_attempts_; }
-
- uint32_t connection_close_packets() const {
- return connection_close_packets_;
- }
-
- void Reset() { framer_.Reset(); }
-
- void SetSupportedVersions(const ParsedQuicVersionVector& versions) {
- framer_.SetSupportedVersions(versions);
- }
-
- void set_max_packet_size(QuicByteCount max_packet_size) {
- max_packet_size_ = max_packet_size;
- }
-
- void set_supports_release_time(bool supports_release_time) {
- supports_release_time_ = supports_release_time;
- }
-
- SimpleQuicFramer* framer() { return &framer_; }
-
- private:
- char* AllocPacketBuffer() {
- PacketBuffer* p = packet_buffer_free_list_.front();
- EXPECT_FALSE(p->in_use);
- p->in_use = true;
- packet_buffer_free_list_.pop_front();
- return p->buffer;
- }
-
- void FreePacketBuffer(const char* buffer) {
- auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer));
- ASSERT_TRUE(iter != packet_buffer_pool_index_.end());
- PacketBuffer* p = iter->second;
- ASSERT_TRUE(p->in_use);
- p->in_use = false;
- packet_buffer_free_list_.push_back(p);
- }
-
- ParsedQuicVersion version_;
- SimpleQuicFramer framer_;
- size_t last_packet_size_ = 0;
- QuicPacketHeader last_packet_header_;
- bool write_blocked_ = false;
- bool write_should_fail_ = false;
- bool block_on_next_flush_ = false;
- bool block_on_next_write_ = false;
- bool next_packet_too_large_ = false;
- bool always_get_packet_too_large_ = false;
- bool is_write_blocked_data_buffered_ = false;
- bool is_batch_mode_ = false;
- // Number of times Flush() was called.
- uint32_t flush_attempts_ = 0;
- // (Batch mode only) Number of bytes buffered in writer. It is used as the
- // return value of a successful Flush().
- uint32_t bytes_buffered_ = 0;
- uint32_t final_bytes_of_last_packet_ = 0;
- uint32_t final_bytes_of_previous_packet_ = 0;
- bool use_tagging_decrypter_ = false;
- uint32_t packets_write_attempts_ = 0;
- uint32_t connection_close_packets_ = 0;
- MockClock* clock_ = nullptr;
- // If non-zero, the clock will pause during WritePacket for this amount of
- // time.
- QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero();
- QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize;
- bool supports_release_time_ = false;
- // Used to verify writer-allocated packet buffers are properly released.
- std::vector<PacketBuffer*> packet_buffer_pool_;
- // Buffer address => Address of the owning PacketBuffer.
- QuicHashMap<char*, PacketBuffer*> packet_buffer_pool_index_;
- // Indices in packet_buffer_pool_ that are not allocated.
- std::list<PacketBuffer*> packet_buffer_free_list_;
-};
-
class TestConnection : public QuicConnection {
public:
TestConnection(QuicConnectionId connection_id,
@@ -724,6 +227,7 @@ class TestConnection : public QuicConnection {
SerializedPacket serialized_packet(
QuicPacketNumber(packet_number), PACKET_4BYTE_PACKET_NUMBER, buffer,
encrypted_length, has_ack, has_pending_frames);
+ serialized_packet.peer_address = kPeerAddress;
if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
serialized_packet.retransmittable_frames.push_back(
QuicFrame(QuicPingFrame()));
@@ -854,9 +358,26 @@ class TestConnection : public QuicConnection {
writer()->SetSupportedVersions(versions);
}
+ // This should be called before setting customized encrypters/decrypters for
+ // connection and peer creator.
void set_perspective(Perspective perspective) {
writer()->set_perspective(perspective);
QuicConnectionPeer::SetPerspective(this, perspective);
+ QuicSentPacketManagerPeer::SetPerspective(
+ QuicConnectionPeer::GetSentPacketManager(this), perspective);
+ QuicConnectionPeer::GetFramer(this)->SetInitialObfuscators(
+ TestConnectionId());
+ for (EncryptionLevel level : {ENCRYPTION_ZERO_RTT, ENCRYPTION_HANDSHAKE,
+ ENCRYPTION_FORWARD_SECURE}) {
+ if (QuicConnectionPeer::GetFramer(this)->HasEncrypterOfEncryptionLevel(
+ level)) {
+ SetEncrypter(level, std::make_unique<NullEncrypter>(perspective));
+ }
+ if (QuicConnectionPeer::GetFramer(this)->HasDecrypterOfEncryptionLevel(
+ level)) {
+ InstallDecrypter(level, std::make_unique<NullDecrypter>(perspective));
+ }
+ }
}
// Enable path MTU discovery. Assumes that the test is performed from the
@@ -1069,7 +590,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
peer_creator_(connection_id_,
&peer_framer_,
/*delegate=*/nullptr),
- writer_(new TestPacketWriter(version(), &clock_)),
+ writer_(
+ new TestPacketWriter(version(), &clock_, Perspective::IS_CLIENT)),
connection_(connection_id_,
kPeerAddress,
helper_.get(),
@@ -1170,6 +692,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullDecrypter>(Perspective::IS_CLIENT));
}
+ peer_creator_.SetDefaultPeerAddress(kSelfAddress);
}
QuicConnectionTest(const QuicConnectionTest&) = delete;
@@ -1338,6 +861,70 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
return encrypted_length;
}
+ struct PacketInfo {
+ PacketInfo(uint64_t packet_number, QuicFrames frames, EncryptionLevel level)
+ : packet_number(packet_number), frames(frames), level(level) {}
+
+ uint64_t packet_number;
+ QuicFrames frames;
+ EncryptionLevel level;
+ };
+
+ size_t ProcessCoalescedPacket(std::vector<PacketInfo> packets) {
+ char coalesced_buffer[kMaxOutgoingPacketSize];
+ size_t coalesced_size = 0;
+ bool contains_initial = false;
+ for (const auto& packet : packets) {
+ QuicPacketHeader header =
+ ConstructPacketHeader(packet.packet_number, packet.level);
+ // Set the correct encryption level and encrypter on peer_creator and
+ // peer_framer, respectively.
+ peer_creator_.set_encryption_level(packet.level);
+ if (packet.level == ENCRYPTION_INITIAL) {
+ contains_initial = true;
+ }
+ if (QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_) >
+ ENCRYPTION_INITIAL) {
+ peer_framer_.SetEncrypter(
+ QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_),
+ std::make_unique<TaggingEncrypter>(0x01));
+ // Set the corresponding decrypter.
+ if (connection_.version().KnowsWhichDecrypterToUse()) {
+ connection_.InstallDecrypter(
+ QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_),
+ std::make_unique<StrictTaggingDecrypter>(0x01));
+ } else {
+ connection_.SetDecrypter(
+ QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_),
+ std::make_unique<StrictTaggingDecrypter>(0x01));
+ }
+ }
+ std::unique_ptr<QuicPacket> constructed_packet(
+ ConstructPacket(header, packet.frames));
+
+ char buffer[kMaxOutgoingPacketSize];
+ size_t encrypted_length = peer_framer_.EncryptPayload(
+ packet.level, QuicPacketNumber(packet.packet_number),
+ *constructed_packet, buffer, kMaxOutgoingPacketSize);
+ DCHECK_LE(coalesced_size + encrypted_length, kMaxOutgoingPacketSize);
+ memcpy(coalesced_buffer + coalesced_size, buffer, encrypted_length);
+ coalesced_size += encrypted_length;
+ }
+ if (contains_initial) {
+ // Padded coalesced packet to full if it contains initial packet.
+ memset(coalesced_buffer + coalesced_size, '0',
+ kMaxOutgoingPacketSize - coalesced_size);
+ }
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(coalesced_buffer, coalesced_size, clock_.Now(),
+ false));
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+ return coalesced_size;
+ }
+
size_t ProcessDataPacket(uint64_t number) {
return ProcessDataPacketAtLevel(number, false, ENCRYPTION_FORWARD_SECURE);
}
@@ -1362,7 +949,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
} else {
frames.push_back(QuicFrame(frame1_));
}
- frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
+ if (level == ENCRYPTION_INITIAL) {
+ frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
+ }
std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames);
char buffer[kMaxOutgoingPacketSize];
peer_creator_.set_encryption_level(level);
@@ -1678,6 +1267,14 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
}
QuicFramerPeer::SetPerspective(&peer_framer_,
QuicUtils::InvertPerspective(perspective));
+ peer_framer_.SetInitialObfuscators(TestConnectionId());
+ for (EncryptionLevel level : {ENCRYPTION_ZERO_RTT, ENCRYPTION_HANDSHAKE,
+ ENCRYPTION_FORWARD_SECURE}) {
+ if (peer_framer_.HasEncrypterOfEncryptionLevel(level)) {
+ peer_creator_.SetEncrypter(
+ level, std::make_unique<NullEncrypter>(peer_framer_.perspective()));
+ }
+ }
}
void set_packets_between_probes_base(
@@ -1759,6 +1356,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
}
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Prevent packets from being coalesced.
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
}
void TestClientRetryHandling(bool invalid_retry_tag,
@@ -1958,6 +1558,11 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) {
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Prevent packets from being coalesced.
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
// Clear direct_peer_address.
QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress());
@@ -1967,23 +1572,30 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
- } else {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
- }
- ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
- kPeerAddress);
+ const QuicSocketAddress kNewPeerAddress =
+ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
+ 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());
+ }));
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame1_));
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
// Process another packet with a different peer address on server side will
// start connection migration.
- const QuicSocketAddress kNewPeerAddress =
- QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1);
- ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
- kNewPeerAddress);
+ QuicFrames frames2;
+ frames2.push_back(QuicFrame(frame2_));
+ ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
}
@@ -2099,8 +1711,9 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(0);
- // Process a padded PING or PATH CHALLENGE packet with no peer address change
- // on server side will be ignored.
+ // Process a padded PING packet with no peer address change on server side
+ // will be ignored. But a PATH CHALLENGE packet with no peer address change
+ // will be considered as path probing.
std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
@@ -2112,7 +1725,10 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
- EXPECT_EQ(num_probing_received,
+ EXPECT_EQ(num_probing_received + (GetParam().version.HasIetfQuicFrames() &&
+ connection_.send_path_response()
+ ? 1u
+ : 0u),
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2434,7 +2050,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
}
-TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
+TEST_P(QuicConnectionTest, ReceiveConnectivityProbingPacketAtClient) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
PathProbeTestInit(Perspective::IS_CLIENT);
@@ -2459,7 +2075,9 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
// Client takes all padded PING packet as speculative connectivity
// probing packet, and reports to visitor.
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1);
+ if (!connection_.send_path_response()) {
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1);
+ }
std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
@@ -2470,7 +2088,10 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
- EXPECT_EQ(num_probing_received,
+ EXPECT_EQ(num_probing_received + (GetParam().version.HasIetfQuicFrames() &&
+ connection_.send_path_response()
+ ? 1u
+ : 0u),
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2939,16 +2560,47 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
ProcessAckPacket(&frame2);
}
-TEST_P(QuicConnectionTest, AckSentEveryNthPacket) {
- connection_.set_ack_frequency(3);
+TEST_P(QuicConnectionTest, AckFrequencyUpdatedFromAckFrequencyFrame) {
+ if (!GetParam().version.HasIetfQuicFrames()) {
+ return;
+ }
+ connection_.set_can_receive_ack_frequency_frame();
+ // Expect 13 acks, every 3rd packet including the first packet with
+ // AckFrequencyFrame.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(13);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(39);
- // Expect 13 acks, every 3rd packet.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(13);
- // Receives packets 1 - 39.
- for (size_t i = 1; i <= 39; ++i) {
+ QuicAckFrequencyFrame ack_frequency_frame;
+ ack_frequency_frame.packet_tolerance = 3;
+ ProcessFramePacketAtLevel(1, QuicFrame(&ack_frequency_frame),
+ ENCRYPTION_FORWARD_SECURE);
+
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(38);
+ // Receives packets 2 - 39.
+ for (size_t i = 2; i <= 39; ++i) {
+ ProcessDataPacket(i);
+ }
+}
+
+TEST_P(QuicConnectionTest,
+ AckFrequencyFrameOutsideApplicationDataNumberSpaceIsIgnored) {
+ if (!GetParam().version.HasIetfQuicFrames()) {
+ return;
+ }
+ connection_.set_can_receive_ack_frequency_frame();
+
+ QuicAckFrequencyFrame ack_frequency_frame;
+ ack_frequency_frame.packet_tolerance = 3;
+ ProcessFramePacketAtLevel(1, QuicFrame(&ack_frequency_frame),
+ ENCRYPTION_HANDSHAKE);
+
+ // Expect 30 acks, every 2nd (instead of 3rd) packet including the first
+ // packet with AckFrequencyFrame.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(30);
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(60);
+ // Receives packets 2 - 61.
+ for (size_t i = 2; i <= 61; ++i) {
ProcessDataPacket(i);
}
}
@@ -2960,7 +2612,6 @@ TEST_P(QuicConnectionTest, AckDecimationReducesAcks) {
QuicTime::Delta::Zero(), QuicTime::Zero());
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING);
// Start ack decimation from 10th packet.
connection_.set_min_received_before_ack_decimation(10);
@@ -3043,6 +2694,8 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFramesAfterPto) {
connection_.SetFromConfig(config);
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ connection_.OnHandshakeComplete();
+
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(10);
@@ -4538,7 +4191,7 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr);
EXPECT_FALSE(notifier_.HasLostStreamData());
- connection_.MarkZeroRttPacketsForRetransmission();
+ connection_.MarkZeroRttPacketsForRetransmission(0);
EXPECT_TRUE(notifier_.HasLostStreamData());
}
@@ -4565,9 +4218,9 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
// which should result in the original packet being processed.
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<TaggingEncrypter>(tag));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2);
ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
@@ -4640,9 +4293,9 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePacketsThenKeyChange) {
SetDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<StrictTaggingDecrypter>(tag));
EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<TaggingEncrypter>(tag));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(100);
connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
@@ -5445,11 +5098,6 @@ TEST_P(QuicConnectionTest, MtuDiscoverySecondProbeFailed) {
EXPECT_EQ(third_probe_size, connection_.max_packet_length());
SendStreamDataToPeer(3, "$", stream_offset++, NO_FIN, nullptr);
- if (!GetQuicReloadableFlag(quic_revert_mtu_after_two_ptos)) {
- EXPECT_FALSE(connection_.PathMtuReductionDetectionInProgress());
- return;
- }
-
EXPECT_TRUE(connection_.PathMtuReductionDetectionInProgress());
if (connection_.PathDegradingDetectionInProgress() &&
@@ -5938,6 +5586,9 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) {
// Indicate streams are still open.
EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
.WillRepeatedly(Return(true));
+ if (GetQuicReloadableFlag(quic_add_stream_info_to_idle_close_detail)) {
+ EXPECT_CALL(visitor_, GetStreamsInfoForLogging()).WillOnce(Return(""));
+ }
// This time, we should time out and send a connection close due to the TLP.
EXPECT_CALL(visitor_,
@@ -6254,85 +5905,8 @@ TEST_P(QuicConnectionTest, SendDelayedAck) {
EXPECT_FALSE(connection_.HasPendingAcks());
}
-TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true);
-
- // The beginning of the connection counts as quiescence.
- QuicTime ack_time = clock_.ApproximateNow() + kAlarmGranularity;
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.HasPendingAcks());
- const uint8_t tag = 0x07;
- SetDecrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
- // instead of ENCRYPTION_INITIAL.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(DefaultDelayedAckTime());
- connection_.GetAckAlarm()->Fire();
- // Check that ack is sent and that delayed ack alarm is reset.
- size_t padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // Process another packet immedately after sending the ack and expect the
- // ack alarm to be set delayed ack time in the future.
- ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(DefaultDelayedAckTime());
- connection_.GetAckAlarm()->Fire();
- // Check that ack is sent and that delayed ack alarm is reset.
- padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // Wait 1 second and ensure the ack alarm is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-}
-
TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION);
const size_t kMinRttMs = 40;
RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
@@ -6389,141 +5963,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
EXPECT_FALSE(connection_.HasPendingAcks());
}
-TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION);
- QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
-
- // The beginning of the connection counts as quiescence.
- QuicTime ack_time =
- clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.HasPendingAcks());
- const uint8_t tag = 0x07;
- SetDecrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
- // instead of ENCRYPTION_INITIAL.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(DefaultDelayedAckTime());
- connection_.GetAckAlarm()->Fire();
- // Check that ack is sent and that delayed ack alarm is reset.
- size_t padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // Process another packet immedately after sending the ack and expect the
- // ack alarm to be set delayed ack time in the future.
- ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(DefaultDelayedAckTime());
- connection_.GetAckAlarm()->Fire();
- // Check that ack is sent and that delayed ack alarm is reset.
- padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // Wait 1 second and enesure the ack alarm is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process enough packets to get into ack decimation behavior.
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- ack_time = clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
- uint64_t kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 4; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- }
- EXPECT_FALSE(connection_.HasPendingAcks());
- // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
- // instead of ENCRYPTION_INITIAL.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // Wait 1 second and enesure the ack alarm is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-}
-
TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
@@ -6585,7 +6024,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION);
QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
const size_t kMinRttMs = 40;
@@ -6643,319 +6081,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_FALSE(connection_.HasPendingAcks());
}
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.HasPendingAcks());
- const uint8_t tag = 0x07;
- SetDecrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- }
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // Receive one packet out of order and then the rest in order.
- // The loop leaves a one packet gap between acks sent to simulate some loss.
- for (int j = 0; j < 3; ++j) {
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9 + (j * 11),
- !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- writer_->Reset();
- for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- // The ACK shouldn't be sent until the 10th packet is processed.
- EXPECT_TRUE(writer_->ack_frames().empty());
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + i + (j * 11),
- !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- size_t padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
- }
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.HasPendingAcks());
- const uint8_t tag = 0x07;
- SetDecrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- }
- EXPECT_FALSE(connection_.HasPendingAcks());
- // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
- // instead of ENCRYPTION_INITIAL.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // The next packet received in order will cause an immediate ack,
- // because it fills a hole.
- EXPECT_FALSE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- // Check that ack is sent and that delayed ack alarm is reset.
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING);
- QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.HasPendingAcks());
- const uint8_t tag = 0x07;
- SetDecrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- }
- EXPECT_FALSE(connection_.HasPendingAcks());
- // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
- // instead of ENCRYPTION_INITIAL.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- size_t padding_frame_count = writer_->padding_frames().size();
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-}
-
-TEST_P(QuicConnectionTest,
- SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
- QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING);
- QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() +
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.HasPendingAcks());
- const uint8_t tag = 0x07;
- SetDecrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
- std::make_unique<TaggingEncrypter>(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
- }
- EXPECT_FALSE(connection_.HasPendingAcks());
- // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
- // instead of ENCRYPTION_INITIAL.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-
- // The next packet received in order will cause an immediate ack,
- // because it fills a hole.
- EXPECT_FALSE(connection_.HasPendingAcks());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
- ENCRYPTION_ZERO_RTT);
- // Check that ack is sent and that delayed ack alarm is reset.
- if (GetParam().no_stop_waiting) {
- EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count());
- EXPECT_TRUE(writer_->stop_waiting_frames().empty());
- } else {
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- }
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.HasPendingAcks());
-}
-
TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
@@ -7259,20 +6384,8 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) {
ConnectionCloseBehavior::SILENT_CLOSE);
EXPECT_FALSE(connection_.connected());
EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
- if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early)) {
- EXPECT_EQ(DISCARD, connection_.GetSerializedPacketFate(
- /*is_mtu_discovery=*/false, ENCRYPTION_INITIAL));
- return;
- }
- std::unique_ptr<QuicPacket> packet =
- ConstructDataPacket(1, !kHasStopWaiting, ENCRYPTION_INITIAL);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
- .Times(0);
- connection_.SendPacket(ENCRYPTION_INITIAL, 1, std::move(packet),
- HAS_RETRANSMITTABLE_DATA, false, false);
- EXPECT_EQ(1, connection_close_frame_count_);
- EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
- IsError(QUIC_PEER_GOING_AWAY));
+ EXPECT_EQ(DISCARD, connection_.GetSerializedPacketFate(
+ /*is_mtu_discovery=*/false, ENCRYPTION_INITIAL));
}
TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) {
@@ -7303,7 +6416,7 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) {
TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) {
PathProbeTestInit(Perspective::IS_CLIENT);
- TestPacketWriter probing_writer(version(), &clock_);
+ TestPacketWriter probing_writer(version(), &clock_, Perspective::IS_CLIENT);
// Block next write so that sending connectivity probe will encounter a
// blocked write when send a connectivity probe to the peer.
probing_writer.BlockOnNextWrite();
@@ -7335,7 +6448,7 @@ TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) {
TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) {
PathProbeTestInit(Perspective::IS_CLIENT);
- TestPacketWriter probing_writer(version(), &clock_);
+ TestPacketWriter probing_writer(version(), &clock_, Perspective::IS_CLIENT);
probing_writer.SetShouldWriteFail();
// Connection should not be closed if a connectivity probe is failed to be
@@ -7674,10 +6787,20 @@ TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) {
MockQuicConnectionDebugVisitor debug_visitor;
connection_.set_debug_visitor(&debug_visitor);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ }
connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ }
connection_.SendConnectivityProbingPacket(writer_.get(),
connection_.peer_address());
}
@@ -7804,7 +6927,12 @@ TEST_P(QuicConnectionTest, SendPingImmediately) {
CongestionBlockWrites();
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ }
EXPECT_CALL(debug_visitor, OnPingSent()).Times(1);
connection_.SendControlFrame(QuicFrame(QuicPingFrame(1)));
EXPECT_FALSE(connection_.HasQueuedData());
@@ -7816,7 +6944,12 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) {
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ }
EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
connection_.SendControlFrame(QuicFrame(new QuicBlockedFrame(1, 3)));
EXPECT_EQ(1u, connection_.GetStats().blocked_frames_sent);
@@ -7832,7 +6965,12 @@ TEST_P(QuicConnectionTest, FailedToSendBlockedFrames) {
QuicBlockedFrame blocked(1, 3);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0);
+ }
EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
connection_.SendControlFrame(QuicFrame(&blocked));
EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
@@ -8555,21 +7693,45 @@ TEST_P(QuicConnectionTest, SendProbingRetransmissions) {
}
// Expect them retransmitted in cyclic order (foo, bar, test, foo, bar...).
QuicPacketCount sent_count = 0;
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _))
- .WillRepeatedly(Invoke([this, &sent_count](const SerializedPacket&,
- TransmissionType, QuicTime) {
- ASSERT_EQ(1u, writer_->stream_frames().size());
- if (connection_.version().CanSendCoalescedPackets()) {
- // There is a delay of sending coalesced packet, so (6, 0, 3, 6,
- // 0...).
- EXPECT_EQ(3 * ((sent_count + 2) % 3),
- writer_->stream_frames()[0]->offset);
- } else {
- // Identify the frames by stream offset (0, 3, 6, 0, 3...).
- EXPECT_EQ(3 * (sent_count % 3), writer_->stream_frames()[0]->offset);
- }
- sent_count++;
- }));
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _))
+ .WillRepeatedly(
+ Invoke([this, &sent_count](QuicPacketNumber, QuicPacketLength, bool,
+ TransmissionType, EncryptionLevel,
+ const QuicFrames&, const QuicFrames&,
+ QuicTime) {
+ ASSERT_EQ(1u, writer_->stream_frames().size());
+ if (connection_.version().CanSendCoalescedPackets()) {
+ // There is a delay of sending coalesced packet, so (6, 0, 3, 6,
+ // 0...).
+ EXPECT_EQ(3 * ((sent_count + 2) % 3),
+ writer_->stream_frames()[0]->offset);
+ } else {
+ // Identify the frames by stream offset (0, 3, 6, 0, 3...).
+ EXPECT_EQ(3 * (sent_count % 3),
+ writer_->stream_frames()[0]->offset);
+ }
+ sent_count++;
+ }));
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _))
+ .WillRepeatedly(Invoke([this, &sent_count](const SerializedPacket&,
+ TransmissionType, QuicTime) {
+ ASSERT_EQ(1u, writer_->stream_frames().size());
+ if (connection_.version().CanSendCoalescedPackets()) {
+ // There is a delay of sending coalesced packet, so (6, 0, 3, 6,
+ // 0...).
+ EXPECT_EQ(3 * ((sent_count + 2) % 3),
+ writer_->stream_frames()[0]->offset);
+ } else {
+ // Identify the frames by stream offset (0, 3, 6, 0, 3...).
+ EXPECT_EQ(3 * (sent_count % 3),
+ writer_->stream_frames()[0]->offset);
+ }
+ sent_count++;
+ }));
+ }
EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket())
.WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] {
@@ -8593,7 +7755,12 @@ TEST_P(QuicConnectionTest,
MockQuicConnectionDebugVisitor debug_visitor;
connection_.set_debug_visitor(&debug_visitor);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0);
+ }
EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket())
.WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] {
@@ -9163,12 +8330,13 @@ TEST_P(QuicConnectionTest, LimitedLargestMessagePayload) {
// Test to check that the path challenge/path response logic works
// correctly. This test is only for version-99
-TEST_P(QuicConnectionTest, PathChallengeResponse) {
+TEST_P(QuicConnectionTest, ServerResponseToPathChallenge) {
if (!VersionHasIetfQuicFrames(connection_.version().transport_version)) {
return;
}
- // First check if we can probe from server to client and back
- set_perspective(Perspective::IS_SERVER);
+ PathProbeTestInit(Perspective::IS_SERVER);
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ // First check if the server can send probing packet.
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
// Create and send the probe request (PATH_CHALLENGE frame).
@@ -9188,21 +8356,61 @@ TEST_P(QuicConnectionTest, PathChallengeResponse) {
// Normally, QuicConnection::OnPathChallengeFrame and OnPaddingFrame would be
// called and it will perform actions to ensure that the rest of the protocol
- // is performed (specifically, call UpdatePacketContent to say that this is a
- // path challenge so that when QuicConnection::OnPacketComplete is called
- // (again, out of the framer), the response is generated). Simulate those
- // calls so that the right internal state is set up for generating
- // the response.
+ // is performed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
EXPECT_TRUE(connection_.OnPathChallengeFrame(
writer_->path_challenge_frames().front()));
EXPECT_TRUE(connection_.OnPaddingFrame(writer_->padding_frames().front()));
- // Cause the response to be created and sent. Result is that the response
- // should be stashed in writer's path_response_frames.
+ if (!connection_.send_path_response()) {
+ connection_.SendConnectivityProbingResponsePacket(
+ connection_.peer_address());
+ }
+ creator_->FlushCurrentPacket();
+
+ // The final check is to ensure that the random data in the response matches
+ // the random data from the challenge.
+ EXPECT_EQ(1u, writer_->path_response_frames().size());
+ EXPECT_EQ(0, memcmp(&challenge_data,
+ &(writer_->path_response_frames().front().data_buffer),
+ sizeof(challenge_data)));
+}
+
+TEST_P(QuicConnectionTest, ClientResponseToPathChallenge) {
+ if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
+ !connection_.send_path_response()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_CLIENT);
+ // First check if the client can send probing packet.
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+
+ // Create and send the probe request (PATH_CHALLENGE frame).
+ // SendConnectivityProbingPacket ends up calling
+ // TestPacketWriter::WritePacket() which in turns receives and parses the
+ // packet by calling framer_.ProcessPacket() -- which in turn calls
+ // SimpleQuicFramer::OnPathChallengeFrame(). SimpleQuicFramer saves
+ // the packet in writer_->path_challenge_frames()
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendConnectivityProbingResponsePacket(connection_.peer_address());
+ connection_.SendConnectivityProbingPacket(writer_.get(),
+ connection_.peer_address());
+ // Save the random contents of the challenge for later validation against the
+ // response.
+ ASSERT_GE(writer_->path_challenge_frames().size(), 1u);
+ QuicPathFrameBuffer challenge_data =
+ writer_->path_challenge_frames().front().data_buffer;
+
+ // Normally, QuicConnection::OnPathChallengeFrame would be
+ // called and it will perform actions to ensure that the rest of the protocol
+ // is performed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ EXPECT_TRUE(connection_.OnPathChallengeFrame(
+ writer_->path_challenge_frames().front()));
+ EXPECT_TRUE(connection_.OnPaddingFrame(writer_->padding_frames().front()));
+ creator_->FlushCurrentPacket();
// The final check is to ensure that the random data in the response matches
// the random data from the challenge.
+ EXPECT_EQ(1u, writer_->path_response_frames().size());
EXPECT_EQ(0, memcmp(&challenge_data,
&(writer_->path_response_frames().front().data_buffer),
sizeof(challenge_data)));
@@ -9263,7 +8471,7 @@ TEST_P(QuicConnectionTest,
// Simulate path degrading handling by sending a probe on an alternet path.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- TestPacketWriter probing_writer(version(), &clock_);
+ TestPacketWriter probing_writer(version(), &clock_, Perspective::IS_CLIENT);
connection_.SendConnectivityProbingPacket(&probing_writer,
connection_.peer_address());
// Verify that path degrading detection is not reset.
@@ -9941,8 +9149,9 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) {
connection_.SetFromConfig(config);
if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
EXPECT_CALL(visitor_, GetHandshakeState())
- .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
}
+ connection_.OnHandshakeComplete();
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Send stream data.
@@ -9992,8 +9201,9 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
connection_.SetFromConfig(config);
if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
EXPECT_CALL(visitor_, GetHandshakeState())
- .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
}
+ connection_.OnHandshakeComplete();
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Send stream data.
@@ -10042,8 +9252,9 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) {
connection_.SetFromConfig(config);
if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
EXPECT_CALL(visitor_, GetHandshakeState())
- .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
}
+ connection_.OnHandshakeComplete();
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Send stream data.
@@ -10166,6 +9377,136 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
}
}
+TEST_P(QuicConnectionTest, 3AntiAmplificationLimit) {
+ if (!connection_.version().SupportsAntiAmplificationLimit()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+
+ set_perspective(Perspective::IS_SERVER);
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k3AFF);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(&config,
+ QuicConnectionId());
+ }
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+
+ // Verify no data can be sent at the beginning because bytes received is 0.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo", 0);
+ EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
+ EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA));
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Receives packet 1.
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+
+ const size_t anti_amplification_factor = 3;
+ // Verify now packets can be sent.
+ for (size_t i = 0; i < anti_amplification_factor; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendCryptoDataWithString("foo", i * 3);
+ // Verify retransmission alarm is not set if throttled by anti-amplification
+ // limit.
+ EXPECT_EQ(i != anti_amplification_factor - 1,
+ connection_.GetRetransmissionAlarm()->IsSet());
+ }
+ // Verify server is throttled by anti-amplification limit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3);
+
+ // Receives packet 2.
+ ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
+ // Verify more packets can be sent.
+ for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2;
+ ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendCryptoDataWithString("foo", i * 3);
+ }
+ // Verify server is throttled by anti-amplification limit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo",
+ 2 * anti_amplification_factor * 3);
+
+ ProcessPacket(3);
+ // Verify anti-amplification limit is gone after address validation.
+ for (size_t i = 0; i < 100; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(3, "first", i * 0, NO_FIN);
+ }
+}
+
+TEST_P(QuicConnectionTest, 10AntiAmplificationLimit) {
+ if (!connection_.version().SupportsAntiAmplificationLimit()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+
+ set_perspective(Perspective::IS_SERVER);
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k10AF);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ if (connection_.version().AuthenticatesHandshakeConnectionIds()) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &config, connection_.connection_id());
+ QuicConfigPeer::SetReceivedInitialSourceConnectionId(&config,
+ QuicConnectionId());
+ }
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+
+ // Verify no data can be sent at the beginning because bytes received is 0.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo", 0);
+ EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
+ EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA));
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Receives packet 1.
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+
+ const size_t anti_amplification_factor = 10;
+ // Verify now packets can be sent.
+ for (size_t i = 0; i < anti_amplification_factor; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendCryptoDataWithString("foo", i * 3);
+ // Verify retransmission alarm is not set if throttled by anti-amplification
+ // limit.
+ EXPECT_EQ(i != anti_amplification_factor - 1,
+ connection_.GetRetransmissionAlarm()->IsSet());
+ }
+ // Verify server is throttled by anti-amplification limit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3);
+
+ // Receives packet 2.
+ ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
+ // Verify more packets can be sent.
+ for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2;
+ ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendCryptoDataWithString("foo", i * 3);
+ }
+ // Verify server is throttled by anti-amplification limit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo",
+ 2 * anti_amplification_factor * 3);
+
+ ProcessPacket(3);
+ // Verify anti-amplification limit is gone after address validation.
+ for (size_t i = 0; i < 100; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(3, "first", i * 0, NO_FIN);
+ }
+}
+
TEST_P(QuicConnectionTest, AckPendingWithAmplificationLimited) {
if (!connection_.version().SupportsAntiAmplificationLimit()) {
return;
@@ -10308,7 +9649,12 @@ TEST_P(QuicConnectionTest, SendCoalescedPackets) {
}
MockQuicConnectionDebugVisitor debug_visitor;
connection_.set_debug_visitor(&debug_visitor);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(3);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(3);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(3);
+ }
EXPECT_CALL(debug_visitor, OnCoalescedPacketSent(_, _)).Times(1);
EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
{
@@ -10350,7 +9696,12 @@ TEST_P(QuicConnectionTest, LegacyVersionEncapsulation) {
MockQuicConnectionDebugVisitor debug_visitor;
connection_.set_debug_visitor(&debug_visitor);
- EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ if (connection_.sent_packet_manager()
+ .give_sent_packet_to_debug_visitor_after_sent()) {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1);
+ }
// Our TestPacketWriter normally parses the sent packet using the version
// from the connection, so here we need to tell it to use the encapsulation
@@ -10445,14 +9796,12 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
? QuicPacketNumber(3)
: QuicPacketNumber(4),
_, _));
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
- connection_.GetRetransmissionAlarm()->Fire();
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- // Verify 1-RTT packet gets coalesced with handshake retransmission.
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
- } else {
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+ if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
}
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Verify 1-RTT packet gets coalesced with handshake retransmission.
+ EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
// Send application data.
connection_.SendApplicationDataAtLevel(ENCRYPTION_FORWARD_SECURE, 5, "data",
@@ -10466,21 +9815,17 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
QuicPacketNumber handshake_retransmission =
GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(5)
: QuicPacketNumber(7);
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- handshake_retransmission += 1;
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, handshake_retransmission + 1, _, _));
- }
+ handshake_retransmission += 1;
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, handshake_retransmission + 1, _, _));
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, handshake_retransmission, _, _));
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
- connection_.GetRetransmissionAlarm()->Fire();
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- // Verify 1-RTT packet gets coalesced with handshake retransmission.
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
- } else {
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+ if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
}
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Verify 1-RTT packet gets coalesced with handshake retransmission.
+ EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
// Discard handshake key.
connection_.OnHandshakeComplete();
@@ -10492,9 +9837,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
QuicPacketNumber application_retransmission =
GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(6)
: QuicPacketNumber(9);
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- application_retransmission += 2;
- }
+ application_retransmission += 2;
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, application_retransmission, _, _));
connection_.GetRetransmissionAlarm()->Fire();
@@ -10853,6 +10196,7 @@ TEST_P(QuicConnectionTest, SendPingWhenSkipPacketNumberForPto) {
}
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
+ connection_.OnHandshakeComplete();
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
EXPECT_EQ(MESSAGE_STATUS_SUCCESS, SendMessage("message"));
@@ -11209,13 +10553,17 @@ TEST_P(QuicConnectionTest, ProcessUndecryptablePacketsBasedOnEncryptionLevel) {
SetDecrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<StrictTaggingDecrypter>(0x01));
EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
// Verify all ENCRYPTION_HANDSHAKE packets get processed.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(6);
connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
- EXPECT_EQ(4u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+ if (GetQuicReloadableFlag(quic_fix_undecryptable_packets2)) {
+ EXPECT_EQ(1u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+ } else {
+ EXPECT_EQ(4u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+ }
SetDecrypter(ENCRYPTION_FORWARD_SECURE,
std::make_unique<StrictTaggingDecrypter>(0x02));
@@ -11254,10 +10602,10 @@ TEST_P(QuicConnectionTest, ServerBundlesInitialDataWithInitialAck) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
- } else {
+ if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
}
connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
// Verify PTO time does not change.
@@ -11297,8 +10645,11 @@ TEST_P(QuicConnectionTest, ClientBundlesHandshakeDataWithHandshakeAck) {
// Receives packet 1000 in handshake data.
ProcessCryptoPacketAtLevel(1000, ENCRYPTION_HANDSHAKE);
EXPECT_TRUE(connection_.HasPendingAcks());
-
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
+ if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
+ }
connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
// Receives packet 1001 in handshake data.
@@ -11361,7 +10712,11 @@ TEST_P(QuicConnectionTest, ServerRetransmitsHandshakeDataEarly) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(3);
+ if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(3);
+ }
// Send HANDSHAKE 2 and 3.
connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
connection_.SendCryptoDataWithString("bar", 3, ENCRYPTION_HANDSHAKE);
@@ -11389,12 +10744,8 @@ TEST_P(QuicConnectionTest, ServerRetransmitsHandshakeDataEarly) {
clock_.AdvanceTime(kAlarmGranularity);
connection_.GetAckAlarm()->Fire();
EXPECT_FALSE(writer_->ack_frames().empty());
- if (GetQuicReloadableFlag(quic_retransmit_handshake_data_early)) {
- // Verify handshake data gets retransmitted early.
- EXPECT_FALSE(writer_->crypto_frames().empty());
- } else {
- EXPECT_TRUE(writer_->crypto_frames().empty());
- }
+ // Verify handshake data gets retransmitted early.
+ EXPECT_FALSE(writer_->crypto_frames().empty());
}
// Regression test for b/161228202
@@ -11431,11 +10782,10 @@ TEST_P(QuicConnectionTest, InflatedRttSample) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- // Verify HANDSHAKE packet is coalesced with INITIAL retransmission.
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
- } else {
+ if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
}
std::string handshake_crypto_data(1024, 'a');
connection_.SendCryptoDataWithString(handshake_crypto_data, 0,
@@ -11460,26 +10810,15 @@ TEST_P(QuicConnectionTest, InflatedRttSample) {
EXPECT_EQ(kTestRTT, rtt_stats->latest_rtt());
// Because retransmitted INITIAL gets received so HANDSHAKE 2 gets processed.
frames.clear();
- QuicAckFrame ack_frame2;
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- // HANDSHAKE 5 is also processed.
- ack_frame2 = InitAckFrame(
- {{QuicPacketNumber(2), QuicPacketNumber(3)},
- {initial_retransmission + 1, initial_retransmission + 2}});
- } else {
- ack_frame2 = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
- }
+ // HANDSHAKE 5 is also processed.
+ QuicAckFrame ack_frame2 =
+ InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)},
+ {initial_retransmission + 1, initial_retransmission + 2}});
ack_frame2.ack_delay_time = QuicTime::Delta::Zero();
frames.push_back(QuicFrame(&ack_frame2));
ProcessFramesPacketAtLevel(1, frames, ENCRYPTION_HANDSHAKE);
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- // Verify RTT inflation gets mitigated.
- EXPECT_EQ(rtt_stats->latest_rtt(), kTestRTT);
- } else {
- // Verify this RTT sample gets inflated as it includes the PTO timeout and
- // the actual RTT.
- EXPECT_GE(rtt_stats->latest_rtt(), pto_timeout + kTestRTT);
- }
+ // Verify RTT inflation gets mitigated.
+ EXPECT_EQ(rtt_stats->latest_rtt(), kTestRTT);
}
// Regression test for b/161228202
@@ -11518,11 +10857,11 @@ TEST_P(QuicConnectionTest, CoalscingPacketCausesInfiniteLoop) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
- if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
- // Verify HANDSHAKE packet is coalesced with INITIAL retransmission.
- EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
- } else {
+ // Verify HANDSHAKE packet is coalesced with INITIAL retransmission.
+ if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
}
std::string handshake_crypto_data(1024, 'a');
connection_.SendCryptoDataWithString(handshake_crypto_data, 0,
@@ -11615,6 +10954,7 @@ TEST_P(QuicConnectionTest, SilentIdleTimeout) {
}
TEST_P(QuicConnectionTest, NoSilentClose) {
+ SetQuicReloadableFlag(quic_add_silent_idle_timeout, false);
set_perspective(Perspective::IS_SERVER);
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
if (version().SupportsAntiAmplificationLimit()) {
@@ -11641,13 +10981,7 @@ TEST_P(QuicConnectionTest, NoSilentClose) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
connection_.GetTimeoutAlarm()->Fire();
- if (GetQuicReloadableFlag(quic_no_silent_close_for_idle_timeout)) {
- TestConnectionCloseQuicErrorCode(QUIC_NETWORK_IDLE_TIMEOUT);
- } else {
- // Verify no connection close packet is serialized.
- EXPECT_EQ(nullptr,
- QuicConnectionPeer::GetConnectionClosePacket(&connection_));
- }
+ TestConnectionCloseQuicErrorCode(QUIC_NETWORK_IDLE_TIMEOUT);
}
TEST_P(QuicConnectionTest, DonotSendPing) {
@@ -11692,13 +11026,8 @@ TEST_P(QuicConnectionTest, DonotSendPing) {
// Suppose now ShouldKeepConnectionAlive returns false.
EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
.WillRepeatedly(Return(false));
- if (GetQuicReloadableFlag(quic_fix_on_ping_timeout)) {
- // Verify PING does not get sent.
- EXPECT_CALL(visitor_, SendPing()).Times(0);
- } else {
- // PING get sent even ShouldKeepConnectionAlive returns false.
- EXPECT_CALL(visitor_, SendPing()).Times(1);
- }
+ // Verify PING does not get sent.
+ EXPECT_CALL(visitor_, SendPing()).Times(0);
connection_.GetPingAlarm()->Fire();
}
@@ -11817,7 +11146,10 @@ TEST_P(QuicConnectionTest,
ReserializeInitialPacketInCoalescerAfterDiscardingInitialKey) {
SetQuicReloadableFlag(
quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded, true);
- if (!connection_.version().CanSendCoalescedPackets()) {
+ if (!connection_.version().CanSendCoalescedPackets() ||
+ !GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ // Cannot set quic_fix_missing_initial_keys in the test since connection_ is
+ // created since the setup.
return;
}
use_tagging_decrypter();
@@ -11830,15 +11162,17 @@ TEST_P(QuicConnectionTest,
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() {
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ }));
{
QuicConnection::ScopedPacketFlusher flusher(&connection_);
- connection_.GetAckAlarm()->Fire();
- // Verify this ACK packet is on hold.
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
+ // Verify the packet is on hold.
EXPECT_EQ(0u, writer_->packets_write_attempts());
-
- // Discard INITIAL key while there is an INITIAL packet in the coalescer.
- connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
- connection_.NeuterUnencryptedPackets();
+ // Flush pending ACKs.
+ connection_.GetAckAlarm()->Fire();
}
// If not setting
// quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded, there
@@ -11849,6 +11183,585 @@ TEST_P(QuicConnectionTest,
// crashes).
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(1000, false, ENCRYPTION_FORWARD_SECURE);
+ EXPECT_TRUE(connection_.connected());
+}
+
+// Check that if there are two PATH_CHALLENGE frames in the packet, the latter
+// one is ignored.
+TEST_P(QuicConnectionTest, ReceiveMultiplePathChallenge) {
+ if (!VersionHasIetfQuicFrames(connection_.version().transport_version)) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_SERVER);
+
+ // 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());
+
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ QuicPathFrameBuffer path_frame_buffer1{0, 1, 2, 3, 4, 5, 6, 7};
+ QuicPathFrameBuffer path_frame_buffer2{8, 9, 10, 11, 12, 13, 14, 15};
+ QuicFrames frames;
+ frames.push_back(
+ QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer1)));
+ frames.push_back(
+ QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer2)));
+ const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(),
+ /*port=*/23456);
+
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
+
+ // Expect 2 packets to be sent: the first are padded PATH_RESPONSE(s) to the
+ // alternative peer address. The 2nd is a ACK-only packet to the original
+ // peer address.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(2)
+ .WillOnce(Invoke([=]() {
+ EXPECT_EQ((connection_.send_path_response() ? 1u : 2u),
+ writer_->path_response_frames().size());
+ // The final check is to ensure that the random data in the response
+ // matches the random data from the challenge.
+ EXPECT_EQ(0,
+ memcmp(path_frame_buffer1.data(),
+ &(writer_->path_response_frames().front().data_buffer),
+ sizeof(path_frame_buffer1)));
+ if (!connection_.send_path_response()) {
+ EXPECT_EQ(
+ 0, memcmp(path_frame_buffer2.data(),
+ &(writer_->path_response_frames().back().data_buffer),
+ sizeof(path_frame_buffer2)));
+ } else {
+ EXPECT_EQ(1u, writer_->padding_frames().size());
+ }
+ EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+ }))
+ .WillOnce(Invoke([=]() {
+ // The last write of ACK-only packet should still use the old peer
+ // address.
+ EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address());
+ }));
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress);
+}
+
+TEST_P(QuicConnectionTest, ReceiveStreamFrameBeforePathChallenge) {
+ if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
+ !connection_.send_path_response()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_SERVER);
+
+ // 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());
+
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame1_));
+ QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7};
+ frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer)));
+ const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(),
+ /*port=*/23456);
+
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE));
+ EXPECT_CALL(visitor_, OnStreamFrame(_))
+ .WillOnce(Invoke([=](const QuicStreamFrame& frame) {
+ // Send some data on the stream. The STREAM_FRAME should be built into
+ // one packet together with the latter PATH_RESPONSE.
+ std::string data{"response body"};
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
+ data.length());
+ return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
+ NO_FIN);
+ }));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress);
+
+ // Verify that this packet contains a STREAM_FRAME and a
+ // PATH_RESPONSE_FRAME.
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(1u, writer_->path_response_frames().size());
+ // The final check is to ensure that the random data in the response
+ // matches the random data from the challenge.
+ EXPECT_EQ(0, memcmp(path_frame_buffer.data(),
+ &(writer_->path_response_frames().front().data_buffer),
+ sizeof(path_frame_buffer)));
+ EXPECT_EQ(1u, writer_->padding_frames().size());
+ EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+}
+
+TEST_P(QuicConnectionTest, ReceiveStreamFrameFollowingPathChallenge) {
+ if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
+ !connection_.send_path_response()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_SERVER);
+
+ // 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());
+
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ QuicFrames frames;
+ QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7};
+ frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer)));
+ // PATH_RESPONSE should be flushed out before the rest packet is parsed.
+ frames.push_back(QuicFrame(frame1_));
+ const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(),
+ /*port=*/23456);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(Invoke([=]() {
+ // Verify that this packet contains a PATH_RESPONSE_FRAME.
+ EXPECT_EQ(0u, writer_->stream_frames().size());
+ EXPECT_EQ(1u, writer_->path_response_frames().size());
+ // The final check is to ensure that the random data in the response
+ // matches the random data from the challenge.
+ EXPECT_EQ(0,
+ memcmp(path_frame_buffer.data(),
+ &(writer_->path_response_frames().front().data_buffer),
+ sizeof(path_frame_buffer)));
+ EXPECT_EQ(1u, writer_->padding_frames().size());
+ EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+ }))
+ .WillOnce(Invoke([=]() {
+ // Verify that this packet contains a STREAM_FRAME.
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+ }));
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE));
+ EXPECT_CALL(visitor_, OnStreamFrame(_))
+ .WillOnce(Invoke([=](const QuicStreamFrame& frame) {
+ // Send some data on the stream. The STREAM_FRAME should be built into
+ // one packet together with the latter PATH_RESPONSE.
+ std::string data{"response body"};
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
+ data.length());
+ return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
+ NO_FIN);
+ }));
+
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress);
+}
+
+// Tests that a PATH_CHALLENGE is received in between other frames in an out of
+// order packet.
+TEST_P(QuicConnectionTest, PathChallengeWithDataInOutOfOrderPacket) {
+ if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
+ !connection_.send_path_response()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_SERVER);
+
+ // 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());
+
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame1_));
+ QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7};
+ frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer)));
+ frames.push_back(QuicFrame(frame2_));
+ const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(),
+ /*port=*/23456);
+
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0u);
+ EXPECT_CALL(visitor_, OnStreamFrame(_))
+ .Times(2)
+ .WillRepeatedly(Invoke([=](const QuicStreamFrame& frame) {
+ // Send some data on the stream. The STREAM_FRAME should be built into
+ // one packet together with the latter PATH_RESPONSE.
+ std::string data{"response body"};
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
+ data.length());
+ return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
+ NO_FIN);
+ }));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(Invoke([=]() {
+ // Verify that this packet contains a STREAM_FRAME and is sent to the
+ // original peer address.
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ // No connection migration should happen because the packet is received
+ // out of order.
+ EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address());
+ }))
+ .WillOnce(Invoke([=]() {
+ EXPECT_EQ(1u, writer_->path_response_frames().size());
+ // The final check is to ensure that the random data in the response
+ // matches the random data from the challenge.
+ EXPECT_EQ(0,
+ memcmp(path_frame_buffer.data(),
+ &(writer_->path_response_frames().front().data_buffer),
+ sizeof(path_frame_buffer)));
+ EXPECT_EQ(1u, writer_->padding_frames().size());
+ // PATH_RESPONSE should be sent in another packet to a different peer
+ // address.
+ EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+ }))
+ .WillOnce(Invoke([=]() {
+ // Verify that this packet contains a STREAM_FRAME and is sent to the
+ // original peer address.
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ // No connection migration should happen because the packet is received
+ // out of order.
+ EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address());
+ }));
+ // Lower the packet number so that receiving this packet shouldn't trigger
+ // peer migration.
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress);
+}
+
+// Tests that a PATH_CHALLENGE is cached if its PATH_RESPONSE can't be sent.
+TEST_P(QuicConnectionTest, FailToWritePathResponse) {
+ if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
+ !connection_.send_path_response()) {
+ return;
+ }
+ PathProbeTestInit(Perspective::IS_SERVER);
+
+ // 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());
+
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ QuicFrames frames;
+ QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7};
+ frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer)));
+ const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(),
+ /*port=*/23456);
+
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0u);
+ // Lower the packet number so that receiving this packet shouldn't trigger
+ // peer migration.
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ writer_->SetWriteBlocked();
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress);
+
+ EXPECT_EQ(
+ 1u,
+ QuicConnectionPeer::pending_path_challenge_payloads(&connection_).size());
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->path_response_frames().size());
+ // The final check is to ensure that the random data in the response
+ // matches the random data from the challenge.
+ EXPECT_EQ(0, memcmp(path_frame_buffer.data(),
+ &(writer_->path_response_frames().front().data_buffer),
+ sizeof(path_frame_buffer)));
+ EXPECT_EQ(1u, writer_->padding_frames().size());
+ // PATH_RESPONSE should be sent in another packet to a different peer
+ // address.
+ EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+ EXPECT_TRUE(QuicConnectionPeer::pending_path_challenge_payloads(&connection_)
+ .empty());
+}
+
+// Regression test for b/168101557.
+TEST_P(QuicConnectionTest, HandshakeDataDoesNotGetPtoed) {
+ 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.
+ connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN);
+
+ // Receives HANDSHAKE 1.
+ peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_HANDSHAKE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ // Verify there is pending ACK.
+ ASSERT_TRUE(connection_.HasPendingAcks());
+ // Set the send alarm.
+ connection_.GetSendAlarm()->Set(clock_.ApproximateNow());
+
+ // Fire ACK alarm.
+ if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ }
+ connection_.GetAckAlarm()->Fire();
+ if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) {
+ // Verify 1-RTT packet is coalesced with handshake packet.
+ EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+ } else {
+ // Verify handshake crypto frame is not bundled.
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_TRUE(writer_->crypto_frames().empty());
+ }
+ connection_.GetSendAlarm()->Fire();
+
+ ASSERT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) {
+ if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ }
+ } else {
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(0);
+ EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() {
+ SendPing();
+ }));
+ }
+ connection_.GetRetransmissionAlarm()->Fire();
+ if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) {
+ // Verify a handshake packet gets PTOed and 1-RTT packet gets coalesced.
+ EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+ } else {
+ // Verify an 1-RTT PING gets sent because there is nothing to PTO, bummer,
+ // since this 1-RTT PING cannot be processed by peer and there is a
+ // deadlock.
+ EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+ EXPECT_FALSE(writer_->ping_frames().empty());
+ }
+}
+
+// Regression test for b/168294218.
+TEST_P(QuicConnectionTest, CoalescerHandlesInitialKeyDiscard) {
+ if (!connection_.version().CanSendCoalescedPackets() ||
+ !GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_discard_initial_packet_with_key_dropped, true);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() {
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ }));
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+
+ EXPECT_EQ(0u, connection_.GetStats().packets_discarded);
+ {
+ QuicConnection::ScopedPacketFlusher flusher(&connection_);
+ use_tagging_decrypter();
+ ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ connection_.SendCryptoDataWithString(std::string(1300, 'a'), 0);
+ // Verify this packet is on hold.
+ EXPECT_EQ(0u, writer_->packets_write_attempts());
+ }
+ EXPECT_TRUE(connection_.connected());
+}
+
+// Regresstion test for b/168294218
+TEST_P(QuicConnectionTest, ZeroRttRejectionAndMissingInitialKeys) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces() ||
+ !GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) {
+ return;
+ }
+ // Not defer send in response to packet.
+ connection_.set_defer_send_in_response_to_packets(false);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() {
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ }));
+ EXPECT_CALL(visitor_, OnCryptoFrame(_))
+ .WillRepeatedly(Invoke([=](const QuicCryptoFrame& frame) {
+ if (frame.level == ENCRYPTION_HANDSHAKE) {
+ // 0-RTT gets rejected.
+ connection_.MarkZeroRttPacketsForRetransmission(0);
+ // Send Crypto data.
+ connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(0x03));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ connection_.SendCryptoStreamData();
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(0x04));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Retransmit rejected 0-RTT packets.
+ connection_.OnCanWrite();
+ // Advance INITIAL ack delay to trigger initial ACK to be sent AFTER
+ // the retransmission of rejected 0-RTT packets while the HANDSHAKE
+ // packet is still in the coalescer, such that the INITIAL key gets
+ // dropped between SendAllPendingAcks and actually send the ack frame,
+ // bummer.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ }
+ }));
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SendCryptoStreamData();
+ // Send 0-RTT packet.
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN);
+
+ QuicAckFrame frame1 = InitAckFrame(1);
+ // Received ACK for packet 1.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _));
+ ProcessFramePacketAtLevel(1, QuicFrame(&frame1), ENCRYPTION_INITIAL);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Fire retransmission alarm.
+ EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ QuicFrames frames1;
+ frames1.push_back(QuicFrame(&crypto_frame_));
+ QuicFrames frames2;
+ QuicCryptoFrame crypto_frame(ENCRYPTION_HANDSHAKE, 0,
+ quiche::QuicheStringPiece(data1));
+ frames2.push_back(QuicFrame(&crypto_frame));
+ ProcessCoalescedPacket(
+ {{2, frames1, ENCRYPTION_INITIAL}, {3, frames2, ENCRYPTION_HANDSHAKE}});
+}
+
+TEST_P(QuicConnectionTest, OnZeroRttPacketAcked) {
+ if (!connection_.version().UsesTls()) {
+ return;
+ }
+ MockQuicConnectionDebugVisitor debug_visitor;
+ connection_.set_debug_visitor(&debug_visitor);
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SendCryptoStreamData();
+ // Send 0-RTT packet.
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
+ std::make_unique<TaggingEncrypter>(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN);
+ connection_.SendStreamDataWithString(4, "bar", 0, NO_FIN);
+ // Received ACK for packet 1, HANDSHAKE packet and 1-RTT ACK.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+ .Times(AnyNumber());
+ QuicFrames frames1;
+ QuicAckFrame ack_frame1 = InitAckFrame(1);
+ frames1.push_back(QuicFrame(&ack_frame1));
+
+ QuicFrames frames2;
+ QuicCryptoFrame crypto_frame(ENCRYPTION_HANDSHAKE, 0,
+ quiche::QuicheStringPiece(data1));
+ frames2.push_back(QuicFrame(&crypto_frame));
+ EXPECT_CALL(debug_visitor, OnZeroRttPacketAcked()).Times(0);
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1);
+ ProcessCoalescedPacket(
+ {{1, frames1, ENCRYPTION_INITIAL}, {2, frames2, ENCRYPTION_HANDSHAKE}});
+
+ QuicFrames frames3;
+ QuicAckFrame ack_frame2 =
+ InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
+ frames3.push_back(QuicFrame(&ack_frame2));
+ EXPECT_CALL(debug_visitor, OnZeroRttPacketAcked()).Times(1);
+ ProcessCoalescedPacket({{3, frames3, ENCRYPTION_FORWARD_SECURE}});
+
+ QuicFrames frames4;
+ QuicAckFrame ack_frame3 =
+ InitAckFrame({{QuicPacketNumber(3), QuicPacketNumber(4)}});
+ frames4.push_back(QuicFrame(&ack_frame3));
+ EXPECT_CALL(debug_visitor, OnZeroRttPacketAcked()).Times(0);
+ ProcessCoalescedPacket({{4, frames4, ENCRYPTION_FORWARD_SECURE}});
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc
index ba000156b79..28b3446fb02 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc
@@ -6,6 +6,8 @@
#include <string>
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
@@ -103,8 +105,9 @@ void QuicControlFrameManager::WriteOrBufferMaxStreams(QuicStreamCount count,
QuicMaxStreamsFrame(++last_control_frame_id_, count, unidirectional)));
}
-void QuicControlFrameManager::WriteOrBufferStopSending(uint16_t code,
- QuicStreamId stream_id) {
+void QuicControlFrameManager::WriteOrBufferStopSending(
+ QuicRstStreamErrorCode code,
+ QuicStreamId stream_id) {
QUIC_DVLOG(1) << "Writing STOP_SENDING_FRAME";
WriteOrBufferQuicFrame(QuicFrame(
new QuicStopSendingFrame(++last_control_frame_id_, stream_id, code)));
@@ -116,6 +119,16 @@ void QuicControlFrameManager::WriteOrBufferHandshakeDone() {
QuicFrame(QuicHandshakeDoneFrame(++last_control_frame_id_)));
}
+void QuicControlFrameManager::WriteOrBufferAckFrequency(
+ uint64_t packet_tolerance,
+ QuicTime::Delta max_ack_delay) {
+ QUIC_DVLOG(1) << "Writing ACK_FREQUENCY frame";
+ QuicControlFrameId control_frame_id = ++last_control_frame_id_;
+ WriteOrBufferQuicFrame(QuicFrame(new QuicAckFrequencyFrame(
+ control_frame_id,
+ /*sequence_number=*/control_frame_id, packet_tolerance, max_ack_delay)));
+}
+
void QuicControlFrameManager::WritePing() {
QUIC_DVLOG(1) << "Writing PING_FRAME";
if (HasBufferedFrames()) {
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 76157549562..d79b679c984 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
@@ -77,12 +77,18 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it
// can not be sent immediately.
- void WriteOrBufferStopSending(uint16_t code, QuicStreamId stream_id);
+ void WriteOrBufferStopSending(QuicRstStreamErrorCode code,
+ QuicStreamId stream_id);
// Tries to send an HANDSHAKE_DONE frame. The frame is buffered if it can not
// be sent immediately.
void WriteOrBufferHandshakeDone();
+ // Tries to send an AckFrequencyFrame. The frame is buffered if it cannot be
+ // sent immediately.
+ void WriteOrBufferAckFrequency(uint64_t packet_tolerance,
+ QuicTime::Delta max_ack_delay);
+
// Sends a PING_FRAME. Do not send PING if there is buffered frames.
void WritePing();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
index f8e9932f4e5..68176997944 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -31,7 +32,8 @@ class QuicControlFrameManagerPeer {
namespace {
const QuicStreamId kTestStreamId = 5;
-const QuicStreamId kTestStopSendingCode = 321;
+const QuicRstStreamErrorCode kTestStopSendingCode =
+ QUIC_STREAM_ENCODER_STREAM_ERROR;
class QuicControlFrameManagerTest : public QuicTest {
public:
@@ -230,6 +232,29 @@ TEST_F(QuicControlFrameManagerTest, DonotSendPingWithBufferedFrames) {
EXPECT_FALSE(manager_->WillingToWrite());
}
+TEST_F(QuicControlFrameManagerTest, SendAndAckAckFrequencyFrame) {
+ Initialize();
+ InSequence s;
+ // Send Non-AckFrequency frame 1-5.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(5)
+ .WillRepeatedly(Invoke(&ClearControlFrame));
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ manager_->OnCanWrite();
+
+ // Send AckFrequencyFrame as frame 6.
+ QuicAckFrequencyFrame ack_frequency = {6, 6, 10,
+ QuicTime::Delta::FromMilliseconds(24)};
+ manager_->WriteOrBufferAckFrequency(10,
+ QuicTime::Delta::FromMilliseconds(24));
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&ClearControlFrame));
+ manager_->OnCanWrite();
+
+ // Ack AckFrequencyFrame.
+ EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&ack_frequency)));
+}
+
TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
Initialize();
// Send two more window updates of the same stream.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
index 72769372318..b60b02643b6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
@@ -128,6 +128,10 @@ bool QuicCryptoClientHandshaker::EarlyDataAccepted() const {
return num_client_hellos_ == 1;
}
+ssl_early_data_reason_t QuicCryptoClientHandshaker::EarlyDataReason() const {
+ return early_data_reason_;
+}
+
bool QuicCryptoClientHandshaker::ReceivedInchoateReject() const {
QUIC_BUG_IF(!one_rtt_keys_available_);
return num_client_hellos_ >= 3;
@@ -290,9 +294,16 @@ void QuicCryptoClientHandshaker::DoSendCHLO(
// inchoate or subsequent hello.
session()->config()->ToHandshakeMessage(&out, session()->transport_version());
- if (!cached->IsComplete(session()->connection()->clock()->WallNow()) ||
- session()->config()->HasClientRequestedIndependentOption(
- kQNZR, session()->perspective())) {
+ bool fill_inchoate_client_hello = false;
+ if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
+ early_data_reason_ = ssl_early_data_no_session_offered;
+ fill_inchoate_client_hello = true;
+ } else if (session()->config()->HasClientRequestedIndependentOption(
+ kQNZR, session()->perspective())) {
+ early_data_reason_ = ssl_early_data_disabled;
+ fill_inchoate_client_hello = true;
+ }
+ if (fill_inchoate_client_hello) {
crypto_config_->FillInchoateClientHello(
server_id_, session()->supported_versions().front(), cached,
session()->connection()->random_generator(),
@@ -356,6 +367,9 @@ void QuicCryptoClientHandshaker::DoSendCHLO(
/*latch_once_used=*/true);
encryption_established_ = true;
delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ if (early_data_reason_ == ssl_early_data_unknown && num_client_hellos_ > 1) {
+ early_data_reason_ = ssl_early_data_peer_declined;
+ }
}
void QuicCryptoClientHandshaker::DoReceiveREJ(
@@ -531,6 +545,9 @@ void QuicCryptoClientHandshaker::DoReceiveSHLO(
"unencrypted SHLO message");
return;
}
+ if (num_client_hellos_ == 1) {
+ early_data_reason_ = ssl_early_data_accepted;
+ }
std::string error_details;
QuicErrorCode error = crypto_config_->ProcessServerHello(
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
index 90f011dd053..605318edc06 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
@@ -40,6 +40,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
int num_sent_client_hellos() const override;
bool IsResumption() const override;
bool EarlyDataAccepted() const override;
+ ssl_early_data_reason_t EarlyDataReason() const override;
bool ReceivedInchoateReject() const override;
int num_scup_messages_received() const override;
std::string chlo_hash() const override;
@@ -153,6 +154,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
// connection has sent.
int num_client_hellos_;
+ ssl_early_data_reason_t early_data_reason_ = ssl_early_data_unknown;
+
QuicCryptoClientConfig* const crypto_config_;
// SHA-256 hash of the most recently sent CHLO.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
index 62a261d1fc1..67a9a113510 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
@@ -71,6 +71,10 @@ bool QuicCryptoClientStream::EarlyDataAccepted() const {
return handshaker_->EarlyDataAccepted();
}
+ssl_early_data_reason_t QuicCryptoClientStream::EarlyDataReason() const {
+ return handshaker_->EarlyDataReason();
+}
+
bool QuicCryptoClientStream::ReceivedInchoateReject() const {
return handshaker_->ReceivedInchoateReject();
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h
index be99fb2b949..1d9b04b35fc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h
@@ -116,6 +116,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
// Returns true if early data (0-RTT) was accepted in the connection.
virtual bool EarlyDataAccepted() const = 0;
+ // Returns the ssl_early_data_reason_t describing why 0-RTT was accepted or
+ // rejected.
+ virtual ssl_early_data_reason_t EarlyDataReason() const = 0;
+
// Returns true if the client received an inchoate REJ during the handshake,
// extending the handshake by one round trip. This only applies for QUIC
// crypto handshakes. The equivalent feature in IETF QUIC is a Retry packet,
@@ -203,6 +207,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
int num_sent_client_hellos() const override;
bool IsResumption() const override;
bool EarlyDataAccepted() const override;
+ ssl_early_data_reason_t EarlyDataReason() const override;
bool ReceivedInchoateReject() const override;
int num_scup_messages_received() const override;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc
index 7f6d7770eb6..52791b3d8e1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc
@@ -107,6 +107,7 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
EXPECT_TRUE(stream()->encryption_established());
EXPECT_TRUE(stream()->one_rtt_keys_available());
EXPECT_FALSE(stream()->IsResumption());
+ EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_no_session_offered);
}
TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
@@ -179,6 +180,7 @@ TEST_F(QuicCryptoClientStreamTest, ClientTurnedOffZeroRtt) {
// Check that a client hello was sent.
ASSERT_EQ(1u, connection_->encrypted_packets_.size());
EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+ EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_disabled);
}
TEST_F(QuicCryptoClientStreamTest, ClockSkew) {
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 665cae10efb..5fc683944ab 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
@@ -360,6 +360,16 @@ bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
return true;
}
+ssl_early_data_reason_t QuicCryptoServerStream::EarlyDataReason() const {
+ if (IsZeroRtt()) {
+ return ssl_early_data_accepted;
+ }
+ if (zero_rtt_attempted_) {
+ return ssl_early_data_session_not_resumed;
+ }
+ return ssl_early_data_no_session_offered;
+}
+
bool QuicCryptoServerStream::encryption_established() const {
return encryption_established_;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
index 5a4b9b1428d..29d680ec98d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
@@ -51,6 +51,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
const ProofSource::Details* ProofSourceDetails() const override;
// From QuicCryptoStream
+ ssl_early_data_reason_t EarlyDataReason() const override;
bool encryption_established() const override;
bool one_rtt_keys_available() const override;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
index 54d1b2525c2..d73d97080a8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
@@ -9,6 +9,7 @@
#include <cstddef>
#include <string>
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_config.h"
@@ -72,6 +73,13 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
virtual void WriteCryptoData(EncryptionLevel level,
quiche::QuicheStringPiece data);
+ // Returns the ssl_early_data_reason_t describing why 0-RTT was accepted or
+ // rejected. Note that the value returned by this function may vary during the
+ // handshake. Once |one_rtt_keys_available| returns true, the value returned
+ // by this function will not change for the rest of the lifetime of the
+ // QuicCryptoStream.
+ virtual ssl_early_data_reason_t EarlyDataReason() const = 0;
+
// Returns true once an encrypter has been set for the connection.
virtual bool encryption_established() const = 0;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc
index f763d2d4782..f7e24830943 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc
@@ -46,6 +46,9 @@ class MockQuicCryptoStream : public QuicCryptoStream,
std::vector<CryptoHandshakeMessage>* messages() { return &messages_; }
+ ssl_early_data_reason_t EarlyDataReason() const override {
+ return ssl_early_data_unknown;
+ }
bool encryption_established() const override { return false; }
bool one_rtt_keys_available() const override { return false; }
@@ -218,15 +221,18 @@ TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) {
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_INITIAL, data);
// Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
std::unique_ptr<NullEncrypter> encrypter =
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT);
connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
@@ -274,15 +280,18 @@ TEST_F(QuicCryptoStreamTest, RetransmitEncryptionHandshakeLevelCryptoFrames) {
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_INITIAL, data);
// Send [1000, 2000) in ENCRYPTION_HANDSHAKE.
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
std::unique_ptr<NullEncrypter> encrypter =
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT);
connection_->SetEncrypter(ENCRYPTION_HANDSHAKE, std::move(encrypter));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
EXPECT_EQ(ENCRYPTION_HANDSHAKE, connection_->encryption_level());
EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_HANDSHAKE, 1000, 0))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_HANDSHAKE, data);
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
@@ -350,6 +359,9 @@ TEST_F(QuicCryptoStreamTest, NeuterUnencryptedCryptoData) {
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_INITIAL, data);
// Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetEncrypter(
+ ENCRYPTION_ZERO_RTT,
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
std::unique_ptr<NullEncrypter> encrypter =
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT);
@@ -464,15 +476,18 @@ TEST_F(QuicCryptoStreamTest, RetransmitStreamDataWithCryptoFrames) {
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_INITIAL, data);
// Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
std::unique_ptr<NullEncrypter> encrypter =
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT);
connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+ connection_->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
@@ -588,6 +603,9 @@ TEST_F(QuicCryptoStreamTest, WriteBufferedCryptoFrames) {
// Send [1350, 2700) in ENCRYPTION_ZERO_RTT and verify no write is attempted
// because there is buffered data.
EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ connection_->SetEncrypter(
+ ENCRYPTION_ZERO_RTT,
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
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 7275adfe506..972a9ac0f86 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
@@ -194,14 +194,10 @@ class ChloAlpnExtractor : public ChloExtractor::Delegate {
if (chlo.GetStringPiece(kALPN, &alpn_value)) {
alpn_ = std::string(alpn_value);
}
- if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation,
- 1, 3);
- if (version == LegacyVersionForEncapsulation().transport_version) {
- quiche::QuicheStringPiece qlve_value;
- if (chlo.GetStringPiece(kQLVE, &qlve_value)) {
- legacy_version_encapsulation_inner_packet_ = std::string(qlve_value);
- }
+ if (version == LegacyVersionForEncapsulation().transport_version) {
+ quiche::QuicheStringPiece qlve_value;
+ if (chlo.GetStringPiece(kQLVE, &qlve_value)) {
+ legacy_version_encapsulation_inner_packet_ = std::string(qlve_value);
}
}
}
@@ -209,7 +205,6 @@ class ChloAlpnExtractor : public ChloExtractor::Delegate {
std::string&& ConsumeAlpn() { return std::move(alpn_); }
std::string&& ConsumeLegacyVersionEncapsulationInnerPacket() {
- DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation));
return std::move(legacy_version_encapsulation_inner_packet_);
}
@@ -222,7 +217,6 @@ bool MaybeHandleLegacyVersionEncapsulation(
QuicDispatcher* dispatcher,
ChloAlpnExtractor* alpn_extractor,
const ReceivedPacketInfo& packet_info) {
- DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation));
std::string legacy_version_encapsulation_inner_packet =
alpn_extractor->ConsumeLegacyVersionEncapsulationInnerPacket();
if (legacy_version_encapsulation_inner_packet.empty()) {
@@ -489,23 +483,19 @@ bool QuicDispatcher::MaybeDispatchPacket(
auto it = session_map_.find(server_connection_id);
if (it != session_map_.end()) {
DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id));
- if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation,
- 2, 3);
- 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.
- ChloAlpnExtractor 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;
- }
+ 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.
+ ChloAlpnExtractor 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;
}
}
}
@@ -676,14 +666,11 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
break;
}
- if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_dispatcher_legacy_version_encapsulation, 3, 3);
- if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
- *packet_info)) {
- break;
- }
+ if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor,
+ *packet_info)) {
+ break;
}
+
ProcessChlo({alpn_extractor.ConsumeAlpn()}, packet_info);
} break;
case kFateTimeWait:
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 1fa601f71c8..e90489a9f93 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
@@ -587,7 +587,6 @@ TEST_P(QuicDispatcherTestAllVersions, LegacyVersionEncapsulation) {
// is not currently supported in QuicDispatcher.
return;
}
- SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true);
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId server_connection_id = TestConnectionId();
QuicConfig client_config = DefaultQuicConfig();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc
index cf153e3eea7..8a075984be1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc
@@ -7,6 +7,7 @@
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_client_stats.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
@@ -207,6 +208,7 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH);
RETURN_STRING_LITERAL(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID);
RETURN_STRING_LITERAL(QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS);
+ RETURN_STRING_LITERAL(QUIC_HTTP_RECEIVE_SPDY_SETTING);
RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR);
@@ -229,6 +231,7 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED);
RETURN_STRING_LITERAL(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED);
RETURN_STRING_LITERAL(QUIC_SILENT_IDLE_TIMEOUT);
+ RETURN_STRING_LITERAL(QUIC_MISSING_WRITE_KEYS);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
@@ -585,6 +588,8 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)};
case QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS:
return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)};
+ case QUIC_HTTP_RECEIVE_SPDY_SETTING:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)};
case QUIC_HPACK_INDEX_VARINT_ERROR:
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
@@ -623,6 +628,8 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED:
return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_MISSING_WRITE_KEYS:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_LAST_ERROR:
return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)};
}
@@ -763,6 +770,13 @@ QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode(
return QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE;
}
+void RecordFailToSerializePacketLocation(
+ QuicFailToSerializePacketLocation location) {
+ QUIC_CLIENT_HISTOGRAM_ENUM("QuicSession.FailToSerializePacketLocation",
+ location, kMaxFailLocationValue,
+ "The reason why a packet fails to serialize");
+}
+
#undef RETURN_STRING_LITERAL // undef for jumbo builds
} // namespace quic
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 b57eaa76080..180dff7baf1 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
@@ -442,6 +442,9 @@ enum QuicErrorCode {
QUIC_HTTP_GOAWAY_INVALID_STREAM_ID = 166,
// Received GOAWAY frame with ID that is greater than previously received ID.
QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS = 167,
+ // HTTP/3 session received SETTINGS frame which contains HTTP/2 specific
+ // settings.
+ QUIC_HTTP_RECEIVE_SPDY_SETTING = 169,
// HPACK header block decoding errors.
// Index varint beyond implementation limit.
@@ -492,8 +495,11 @@ enum QuicErrorCode {
// The connection silently timed out due to no network activity.
QUIC_SILENT_IDLE_TIMEOUT = 168,
+ // Try to write data without the right write keys.
+ QUIC_MISSING_WRITE_KEYS = 170,
+
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 169,
+ QUIC_LAST_ERROR = 171,
};
// QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC,
// or a varint62 when doing IETF QUIC. Ensure that its value does not exceed
@@ -580,13 +586,13 @@ enum class QuicHttpQpackErrorCode {
// Convert a QuicRstStreamErrorCode to an application error code to be used in
// an IETF QUIC RESET_STREAM frame
-uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode(
+QUIC_EXPORT_PRIVATE uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode(
QuicRstStreamErrorCode rst_stream_error_code);
// Convert the application error code of an IETF QUIC RESET_STREAM frame
// to QuicRstStreamErrorCode.
-QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode(
- uint64_t ietf_error_code);
+QUIC_EXPORT_PRIVATE QuicRstStreamErrorCode
+IetfResetStreamErrorCodeToRstStreamErrorCode(uint64_t ietf_error_code);
QUIC_EXPORT_PRIVATE inline std::string HistogramEnumString(
QuicErrorCode enum_value) {
@@ -598,6 +604,36 @@ QUIC_EXPORT_PRIVATE inline std::string HistogramEnumDescription(
return "cause";
}
+enum QuicFailToSerializePacketLocation {
+ kQuicFailToAppendPacketHeaderFastPath = 0,
+ kQuicFailToAppendTypeFastPath = 1,
+ kQuicFailToAppendStreamFrameFastPath = 2,
+ kQuicFailToAddPaddingFastPath = 3,
+ kQuicFailToWriteIetfLongHeaderLengthFastPath = 4,
+ kQuicFailToEncryptPacketFastPath = 5,
+ kQuicSerializePacketNonEmptyBuffer = 6,
+ kQuicMissingInitialKey = 7,
+ kQuicMissingHandshakeKey = 8,
+ kQuicMissingZeroRttKey = 9,
+ kQuicMissingOneRttKey = 10,
+ kQuicFailToBuildPacketWithPaddingInitial = 11,
+ kQuicFailToBuildPacketInitial = 12,
+ kQuicFailToBuildPacketWithPaddingHandshake = 13,
+ kQuicFailToBuildPacketHandshake = 14,
+ kQuicFailToBuildPacketWithPaddingZeroRtt = 15,
+ kQuicFailToBuildPacketZeroRtt = 16,
+ kQuicFailToBuildPacketWithPaddingOneRtt = 17,
+ kQuicFailToBuildPacketOneRtt = 18,
+ kQuicFailToEncryptInitial = 19,
+ kQuicFailToEncryptHandshake = 20,
+ kQuicFailToEncryptZeroRtt = 21,
+ kQuicFailToEncryptOneRtt = 22,
+ kMaxFailLocationValue = kQuicFailToEncryptOneRtt
+};
+
+QUIC_EXPORT_PRIVATE void RecordFailToSerializePacketLocation(
+ QuicFailToSerializePacketLocation location);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_ERROR_CODES_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc
index e57a3e57cd0..0f567df48c2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc
@@ -13,12 +13,7 @@ namespace quic {
namespace test {
namespace {
-class QuicErrorCodesTest : public QuicTest {};
-
-TEST_F(QuicErrorCodesTest, QuicRstStreamErrorCodeToString) {
- EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD",
- QuicRstStreamErrorCodeToString(QUIC_BAD_APPLICATION_PAYLOAD));
-}
+using QuicErrorCodesTest = QuicTest;
TEST_F(QuicErrorCodesTest, QuicErrorCodeToString) {
EXPECT_STREQ("QUIC_NO_ERROR", QuicErrorCodeToString(QUIC_NO_ERROR));
@@ -94,6 +89,45 @@ TEST_F(QuicErrorCodesTest, QuicErrorCodeToTransportErrorCode) {
}
}
+using QuicRstErrorCodesTest = QuicTest;
+
+TEST_F(QuicRstErrorCodesTest, QuicRstStreamErrorCodeToString) {
+ EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD",
+ QuicRstStreamErrorCodeToString(QUIC_BAD_APPLICATION_PAYLOAD));
+}
+
+// When an IETF application protocol error code (sent on the wire in
+// RESET_STREAM and STOP_SENDING frames) is translated into a
+// QuicRstStreamErrorCode and back, it must yield the original value.
+TEST_F(QuicRstErrorCodesTest,
+ IetfResetStreamErrorCodeToRstStreamErrorCodeAndBack) {
+ for (uint64_t wire_code :
+ {static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_REJECTED),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_INCOMPLETE),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::CONNECT_ERROR),
+ static_cast<uint64_t>(QuicHttp3ErrorCode::VERSION_FALLBACK),
+ static_cast<uint64_t>(QuicHttpQpackErrorCode::DECOMPRESSION_FAILED),
+ static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR),
+ static_cast<uint64_t>(QuicHttpQpackErrorCode::DECODER_STREAM_ERROR)}) {
+ QuicRstStreamErrorCode rst_stream_error_code =
+ IetfResetStreamErrorCodeToRstStreamErrorCode(wire_code);
+ EXPECT_EQ(wire_code, RstStreamErrorCodeToIetfResetStreamErrorCode(
+ rst_stream_error_code));
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic
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 c9eabcb7ff3..e57277c672a 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
@@ -621,7 +621,7 @@ size_t QuicFramer::GetBlockedFrameSize(QuicTransportVersion version,
// static
size_t QuicFramer::GetStopSendingFrameSize(const QuicStopSendingFrame& frame) {
return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.stream_id) +
- QuicDataWriter::GetVarInt62Len(frame.application_error_code);
+ QuicDataWriter::GetVarInt62Len(frame.ietf_error_code);
}
// static
@@ -2034,6 +2034,23 @@ bool QuicFramer::HasDecrypterOfEncryptionLevel(EncryptionLevel level) const {
return decrypter_[level] != nullptr;
}
+bool QuicFramer::HasAnEncrypterForSpace(PacketNumberSpace space) const {
+ switch (space) {
+ case INITIAL_DATA:
+ return HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL);
+ case HANDSHAKE_DATA:
+ return HasEncrypterOfEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ case APPLICATION_DATA:
+ return HasEncrypterOfEncryptionLevel(ENCRYPTION_ZERO_RTT) ||
+ HasEncrypterOfEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ case NUM_PACKET_NUMBER_SPACES:
+ break;
+ }
+ QUIC_BUG << ENDPOINT
+ << "Try to send data of space: " << PacketNumberSpaceToString(space);
+ return false;
+}
+
bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
QuicDataWriter* writer,
size_t* length_field_offset) {
@@ -2948,12 +2965,6 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
}
case STOP_WAITING_FRAME: {
- if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) &&
- version_.HasIetfInvariantHeader()) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_do_not_accept_stop_waiting);
- set_detailed_error("STOP WAITING not supported in version 44+.");
- return RaiseError(QUIC_INVALID_STOP_WAITING_DATA);
- }
QuicStopWaitingFrame stop_waiting_frame;
if (!ProcessStopWaitingFrame(reader, header, &stop_waiting_frame)) {
return RaiseError(QUIC_INVALID_STOP_WAITING_DATA);
@@ -4047,7 +4058,8 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader,
return false;
}
- if (error_code >= QUIC_LAST_ERROR) {
+ if (!GetQuicReloadableFlag(quic_do_not_clip_received_error_code) &&
+ error_code >= QUIC_LAST_ERROR) {
// Ignore invalid QUIC error code if any.
error_code = QUIC_LAST_ERROR;
}
@@ -4075,7 +4087,8 @@ bool QuicFramer::ProcessGoAwayFrame(QuicDataReader* reader,
return false;
}
- if (error_code >= QUIC_LAST_ERROR) {
+ if (!GetQuicReloadableFlag(quic_do_not_clip_received_error_code) &&
+ error_code >= QUIC_LAST_ERROR) {
// Ignore invalid QUIC error code if any.
error_code = QUIC_LAST_ERROR;
}
@@ -5907,19 +5920,28 @@ bool QuicFramer::ProcessStopSendingFrame(
return false;
}
- uint64_t error_code;
- if (!reader->ReadVarInt62(&error_code)) {
+ if (!reader->ReadVarInt62(&stop_sending_frame->ietf_error_code)) {
set_detailed_error("Unable to read stop sending application error code.");
return false;
}
+
+ if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_stop_sending_uses_ietf_error_code, 2, 2);
+ stop_sending_frame->error_code =
+ IetfResetStreamErrorCodeToRstStreamErrorCode(
+ stop_sending_frame->ietf_error_code);
+ return true;
+ }
+
// TODO(fkastenholz): when error codes go to uint64_t, remove this.
- if (error_code > 0xffff) {
- stop_sending_frame->application_error_code = 0xffff;
- QUIC_DLOG(ERROR) << "Stop sending error code (" << error_code
- << ") > 0xffff";
+ if (stop_sending_frame->ietf_error_code > 0xffff) {
+ stop_sending_frame->error_code =
+ static_cast<QuicRstStreamErrorCode>(0xffff);
+ QUIC_DLOG(ERROR) << "Stop sending error code ("
+ << stop_sending_frame->ietf_error_code << ") > 0xffff";
} else {
- stop_sending_frame->application_error_code =
- static_cast<uint16_t>(error_code);
+ stop_sending_frame->error_code = static_cast<QuicRstStreamErrorCode>(
+ stop_sending_frame->ietf_error_code);
}
return true;
}
@@ -5932,7 +5954,7 @@ bool QuicFramer::AppendStopSendingFrame(
return false;
}
if (!writer->WriteVarInt62(
- static_cast<uint64_t>(stop_sending_frame.application_error_code))) {
+ static_cast<uint64_t>(stop_sending_frame.ietf_error_code))) {
set_detailed_error("Can not write application error code");
return false;
}
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 8e63fc25722..4fcd67110f6 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
@@ -581,6 +581,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// Returns true if decrypter of |level| is available.
bool HasDecrypterOfEncryptionLevel(EncryptionLevel level) const;
+ // Returns true if an encrypter of |space| is available.
+ bool HasAnEncrypterForSpace(PacketNumberSpace space) const;
+
void set_validate_flags(bool value) { validate_flags_ = value; }
Perspective perspective() const { return perspective_; }
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 c6109979c15..4da3e03fb99 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
@@ -4157,17 +4157,8 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) {
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
- if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) &&
- framer_.version().HasIetfInvariantHeader()) {
- EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
- EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_STOP_WAITING_DATA));
- EXPECT_EQ("STOP WAITING not supported in version 44+.",
- framer_.detailed_error());
- return;
- }
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-
EXPECT_THAT(framer_.error(), IsQuicNoError());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(
@@ -4184,9 +4175,8 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) {
TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) {
// The Stop Waiting frame is not in IETF QUIC
- if (VersionHasIetfQuicFrames(version_.transport_version) ||
- (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) &&
- framer_.version().HasIetfInvariantHeader())) {
+ if (VersionHasIetfQuicFrames(version_.transport_version) &&
+ framer_.version().HasIetfInvariantHeader()) {
return;
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
@@ -4408,8 +4398,9 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
{"Unable to read connection close error details.",
{
// error details length
- kVarInt62OneByte + 0x0d,
- // error details
+ kVarInt62OneByte + 0x11,
+ // error details with QuicErrorCode serialized
+ '1', '1', '5', ':',
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
@@ -4439,8 +4430,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
EXPECT_EQ(0x1234u,
visitor_.connection_close_frame_.transport_close_frame_type);
- EXPECT_THAT(visitor_.connection_close_frame_.quic_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_EQ(115u, visitor_.connection_close_frame_.quic_error_code);
} else {
// For Google QUIC frame, |quic_error_code| and |wire_error_code| has the
// same value.
@@ -4453,6 +4443,137 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
CheckFramingBoundaries(fragments, QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
+TEST_P(QuicFramerTest, ConnectionCloseFrameWithUnknownErrorCode) {
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet = {
+ // public flags (8 byte connection_id)
+ {"",
+ {0x28}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (connection close frame)
+ {"",
+ {0x02}},
+ // error code larger than QUIC_LAST_ERROR
+ {"Unable to read connection close error code.",
+ {0x00, 0x00, 0xC0, 0xDE}},
+ {"Unable to read connection close error details.",
+ {
+ // error details length
+ 0x0, 0x0d,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n'}
+ }
+ };
+
+ PacketFragments packet46 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (connection close frame)
+ {"",
+ {0x02}},
+ // error code larger than QUIC_LAST_ERROR
+ {"Unable to read connection close error code.",
+ {0x00, 0x00, 0xC0, 0xDE}},
+ {"Unable to read connection close error details.",
+ {
+ // error details length
+ 0x0, 0x0d,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n'}
+ }
+ };
+
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (IETF Transport CONNECTION_CLOSE frame)
+ {"",
+ {0x1c}},
+ // error code
+ {"Unable to read connection close error code.",
+ {kVarInt62FourBytes + 0x00, 0x00, 0xC0, 0xDE}},
+ {"Unable to read connection close frame type.",
+ {kVarInt62TwoBytes + 0x12, 0x34 }},
+ {"Unable to read connection close error details.",
+ {
+ // error details length
+ kVarInt62OneByte + 0x11,
+ // error details with QuicErrorCode larger than QUIC_LAST_ERROR
+ '8', '4', '9', ':',
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n'}
+ }
+ };
+ // clang-format on
+
+ PacketFragments& fragments =
+ VersionHasIetfQuicFrames(framer_.transport_version())
+ ? packet99
+ : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(fragments));
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_THAT(framer_.error(), IsQuicNoError());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ EXPECT_EQ(0x1234u,
+ visitor_.connection_close_frame_.transport_close_frame_type);
+ EXPECT_EQ(0xC0DEu, visitor_.connection_close_frame_.wire_error_code);
+ EXPECT_EQ(849u, visitor_.connection_close_frame_.quic_error_code);
+ } else {
+ // For Google QUIC frame, |quic_error_code| and |wire_error_code| has the
+ // same value.
+ if (GetQuicReloadableFlag(quic_do_not_clip_received_error_code)) {
+ EXPECT_EQ(0xC0DEu, visitor_.connection_close_frame_.wire_error_code);
+ EXPECT_EQ(0xC0DEu, visitor_.connection_close_frame_.quic_error_code);
+ } else {
+ EXPECT_EQ(QUIC_LAST_ERROR,
+ visitor_.connection_close_frame_.wire_error_code);
+ EXPECT_EQ(QUIC_LAST_ERROR,
+ visitor_.connection_close_frame_.quic_error_code);
+ }
+ }
+
+ ASSERT_EQ(0u, visitor_.ack_frames_.size());
+
+ CheckFramingBoundaries(fragments, QUIC_INVALID_CONNECTION_CLOSE_DATA);
+}
+
// As above, but checks that for Google-QUIC, if there happens
// to be an ErrorCode string at the start of the details, it is
// NOT extracted/parsed/folded/spindled/and/mutilated.
@@ -4800,6 +4921,101 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
CheckFramingBoundaries(fragments, QUIC_INVALID_GOAWAY_DATA);
}
+TEST_P(QuicFramerTest, GoAwayFrameWithUnknownErrorCode) {
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ // This frame is not in IETF QUIC.
+ return;
+ }
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet = {
+ // public flags (8 byte connection_id)
+ {"",
+ {0x28}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (go away frame)
+ {"",
+ {0x03}},
+ // error code larger than QUIC_LAST_ERROR
+ {"Unable to read go away error code.",
+ {0x00, 0x00, 0xC0, 0xDE}},
+ // stream id
+ {"Unable to read last good stream id.",
+ {0x01, 0x02, 0x03, 0x04}},
+ // stream id
+ {"Unable to read goaway reason.",
+ {
+ // error details length
+ 0x0, 0x0d,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n'}
+ }
+ };
+
+ PacketFragments packet46 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (go away frame)
+ {"",
+ {0x03}},
+ // error code larger than QUIC_LAST_ERROR
+ {"Unable to read go away error code.",
+ {0x00, 0x00, 0xC0, 0xDE}},
+ // stream id
+ {"Unable to read last good stream id.",
+ {0x01, 0x02, 0x03, 0x04}},
+ // stream id
+ {"Unable to read goaway reason.",
+ {
+ // error details length
+ 0x0, 0x0d,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n'}
+ }
+ };
+ // clang-format on
+
+ PacketFragments& fragments =
+ framer_.version().HasIetfInvariantHeader() ? packet46 : packet;
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(fragments));
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_THAT(framer_.error(), IsQuicNoError());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ EXPECT_EQ(kStreamId, visitor_.goaway_frame_.last_good_stream_id);
+ if (GetQuicReloadableFlag(quic_do_not_clip_received_error_code)) {
+ EXPECT_EQ(0xC0DE, visitor_.goaway_frame_.error_code);
+ } else {
+ EXPECT_EQ(QUIC_LAST_ERROR, visitor_.goaway_frame_.error_code);
+ }
+ EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
+
+ CheckFramingBoundaries(fragments, QUIC_INVALID_GOAWAY_DATA);
+}
+
TEST_P(QuicFramerTest, WindowUpdateFrame) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
// This frame is not in IETF QUIC, see MaxDataFrame and MaxStreamDataFrame
@@ -10977,7 +11193,14 @@ TEST_P(QuicFramerTest, IetfStopSendingFrame) {
PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
EXPECT_EQ(kStreamId, visitor_.stop_sending_frame_.stream_id);
- EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.application_error_code);
+ if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+ EXPECT_EQ(QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE,
+ visitor_.stop_sending_frame_.error_code);
+ } else {
+ EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.error_code);
+ }
+ EXPECT_EQ(static_cast<uint64_t>(0x7654),
+ visitor_.stop_sending_frame_.ietf_error_code);
CheckFramingBoundaries(packet99, QUIC_INVALID_STOP_SENDING_FRAME_DATA);
}
@@ -10996,7 +11219,9 @@ TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) {
QuicStopSendingFrame frame;
frame.stream_id = kStreamId;
- frame.application_error_code = 0xffff;
+ frame.error_code = QUIC_STREAM_ENCODER_STREAM_ERROR;
+ frame.ietf_error_code =
+ static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR);
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
@@ -11013,7 +11238,7 @@ TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) {
// Stream ID
kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
// Application error code
- kVarInt62FourBytes + 0x00, 0x00, 0xff, 0xff
+ kVarInt62TwoBytes + 0x02, 0x01,
};
// clang-format on
@@ -11260,7 +11485,7 @@ TEST_P(QuicFramerTest, GetRetransmittableControlFrameSize) {
QuicFramer::GetRetransmittableControlFrameSize(
framer_.transport_version(), QuicFrame(&path_challenge_frame)));
- QuicStopSendingFrame stop_sending_frame(10, 3, 20);
+ QuicStopSendingFrame stop_sending_frame(10, 3, QUIC_STREAM_CANCELLED);
EXPECT_EQ(QuicFramer::GetStopSendingFrameSize(stop_sending_frame),
QuicFramer::GetRetransmittableControlFrameSize(
framer_.transport_version(), QuicFrame(&stop_sending_frame)));
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 2a3a758b385..0ac98278019 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
@@ -186,6 +186,7 @@ class QUIC_NO_EXPORT QuicIntervalDeque {
return copy;
}
reference operator*() { return deque_->container_[index_]; }
+ reference operator*() const { return deque_->container_[index_]; }
pointer operator->() { return &deque_->container_[index_]; }
bool operator==(const Iterator& rhs) const {
return index_ == rhs.index_ && deque_ == rhs.deque_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc
index 02e33088890..79deba84848 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc
@@ -34,33 +34,18 @@ QuicNetworkBlackholeDetector::QuicNetworkBlackholeDetector(
alarm_factory->CreateAlarm(arena->New<AlarmDelegate>(this), arena)) {}
void QuicNetworkBlackholeDetector::OnAlarm() {
- if (!revert_mtu_after_two_ptos_) {
- if (path_degrading_deadline_.IsInitialized()) {
- path_degrading_deadline_ = QuicTime::Zero();
- delegate_->OnPathDegradingDetected();
- // Switch to blackhole detection mode.
- alarm_->Update(blackhole_deadline_, kAlarmGranularity);
- return;
- }
- if (blackhole_deadline_.IsInitialized()) {
- blackhole_deadline_ = QuicTime::Zero();
- delegate_->OnBlackholeDetected();
- }
- return;
- }
-
QuicTime next_deadline = GetEarliestDeadline();
if (!next_deadline.IsInitialized()) {
QUIC_BUG << "BlackholeDetector alarm fired unexpectedly";
return;
}
- QUIC_DLOG(INFO) << "BlackholeDetector alarm firing. next_deadline:"
- << next_deadline
- << ", path_degrading_deadline_:" << path_degrading_deadline_
- << ", path_mtu_reduction_deadline_:"
- << path_mtu_reduction_deadline_
- << ", blackhole_deadline_:" << blackhole_deadline_;
+ QUIC_DVLOG(1) << "BlackholeDetector alarm firing. next_deadline:"
+ << next_deadline
+ << ", path_degrading_deadline_:" << path_degrading_deadline_
+ << ", path_mtu_reduction_deadline_:"
+ << path_mtu_reduction_deadline_
+ << ", blackhole_deadline_:" << blackhole_deadline_;
if (path_degrading_deadline_ == next_deadline) {
path_degrading_deadline_ = QuicTime::Zero();
delegate_->OnPathDegradingDetected();
@@ -94,31 +79,14 @@ void QuicNetworkBlackholeDetector::RestartDetection(
blackhole_deadline_ = blackhole_deadline;
path_mtu_reduction_deadline_ = path_mtu_reduction_deadline;
- if (!revert_mtu_after_two_ptos_) {
- QUIC_BUG_IF(path_degrading_deadline_.IsInitialized() &&
- blackhole_deadline_.IsInitialized() &&
- path_degrading_deadline_ > blackhole_deadline_)
- << "Path degrading timeout is later than blackhole detection timeout";
- } else {
- QUIC_BUG_IF(blackhole_deadline_.IsInitialized() &&
- blackhole_deadline_ != GetLastDeadline())
- << "Blackhole detection deadline should be the last deadline.";
- }
+ QUIC_BUG_IF(blackhole_deadline_.IsInitialized() &&
+ blackhole_deadline_ != GetLastDeadline())
+ << "Blackhole detection deadline should be the last deadline.";
- if (!revert_mtu_after_two_ptos_) {
- alarm_->Update(path_degrading_deadline_, kAlarmGranularity);
- if (alarm_->IsSet()) {
- return;
- }
- alarm_->Update(blackhole_deadline_, kAlarmGranularity);
- } else {
- UpdateAlarm();
- }
+ UpdateAlarm();
}
QuicTime QuicNetworkBlackholeDetector::GetEarliestDeadline() const {
- DCHECK(revert_mtu_after_two_ptos_);
-
QuicTime result = QuicTime::Zero();
for (QuicTime t : {path_degrading_deadline_, blackhole_deadline_,
path_mtu_reduction_deadline_}) {
@@ -135,21 +103,18 @@ QuicTime QuicNetworkBlackholeDetector::GetEarliestDeadline() const {
}
QuicTime QuicNetworkBlackholeDetector::GetLastDeadline() const {
- DCHECK(revert_mtu_after_two_ptos_);
return std::max({path_degrading_deadline_, blackhole_deadline_,
path_mtu_reduction_deadline_});
}
void QuicNetworkBlackholeDetector::UpdateAlarm() const {
- DCHECK(revert_mtu_after_two_ptos_);
-
QuicTime next_deadline = GetEarliestDeadline();
- QUIC_DLOG(INFO) << "Updating alarm. next_deadline:" << next_deadline
- << ", path_degrading_deadline_:" << path_degrading_deadline_
- << ", path_mtu_reduction_deadline_:"
- << path_mtu_reduction_deadline_
- << ", blackhole_deadline_:" << blackhole_deadline_;
+ QUIC_DVLOG(1) << "Updating alarm. next_deadline:" << next_deadline
+ << ", path_degrading_deadline_:" << path_degrading_deadline_
+ << ", path_mtu_reduction_deadline_:"
+ << path_mtu_reduction_deadline_
+ << ", blackhole_deadline_:" << blackhole_deadline_;
alarm_->Update(next_deadline, kAlarmGranularity);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h
index 77c5c59dd7e..6952c85d22b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h
@@ -60,8 +60,6 @@ class QUIC_EXPORT_PRIVATE QuicNetworkBlackholeDetector {
// Returns true if |alarm_| is set.
bool IsDetectionInProgress() const;
- bool revert_mtu_after_two_ptos() const { return revert_mtu_after_two_ptos_; }
-
private:
friend class test::QuicConnectionPeer;
friend class test::QuicNetworkBlackholeDetectorPeer;
@@ -74,9 +72,6 @@ class QUIC_EXPORT_PRIVATE QuicNetworkBlackholeDetector {
Delegate* delegate_; // Not owned.
- const bool revert_mtu_after_two_ptos_ =
- GetQuicReloadableFlag(quic_revert_mtu_after_two_ptos);
-
// Time that Delegate::OnPathDegrading will be called. 0 means no path
// degrading detection is in progress.
QuicTime path_degrading_deadline_ = QuicTime::Zero();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc
index 3f6f7470854..d628d777396 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc
@@ -77,20 +77,6 @@ TEST_F(QuicNetworkBlackholeDetectorTest, StartAndFire) {
EXPECT_CALL(delegate_, OnPathDegradingDetected());
alarm_->Fire();
- if (!detector_.revert_mtu_after_two_ptos()) {
- // Verify blackhole detection is still in progress.
- EXPECT_TRUE(detector_.IsDetectionInProgress());
- EXPECT_EQ(clock_.Now() + blackhole_delay_ - path_degrading_delay_,
- alarm_->deadline());
-
- // Fire blackhole detection alarm.
- clock_.AdvanceTime(blackhole_delay_ - path_degrading_delay_);
- EXPECT_CALL(delegate_, OnBlackholeDetected());
- alarm_->Fire();
- EXPECT_FALSE(detector_.IsDetectionInProgress());
- return;
- }
-
// Verify path mtu reduction detection is still in progress.
EXPECT_TRUE(detector_.IsDetectionInProgress());
EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_,
@@ -135,17 +121,10 @@ TEST_F(QuicNetworkBlackholeDetectorTest, PathDegradingFiresAndRestart) {
EXPECT_CALL(delegate_, OnPathDegradingDetected());
alarm_->Fire();
- if (!detector_.revert_mtu_after_two_ptos()) {
- // Verify blackhole detection is still in progress.
- EXPECT_TRUE(detector_.IsDetectionInProgress());
- EXPECT_EQ(clock_.Now() + blackhole_delay_ - path_degrading_delay_,
- alarm_->deadline());
- } else {
- // Verify path mtu reduction detection is still in progress.
- EXPECT_TRUE(detector_.IsDetectionInProgress());
- EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_,
- alarm_->deadline());
- }
+ // Verify path mtu reduction detection is still in progress.
+ EXPECT_TRUE(detector_.IsDetectionInProgress());
+ EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_,
+ alarm_->deadline());
// After 100ms, restart detections on forward progress.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
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 5140df8f2c8..30b911fa839 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
@@ -18,6 +18,7 @@
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
@@ -133,6 +134,9 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
fully_pad_crypto_handshake_packets_(true),
latched_hard_max_packet_length_(0),
max_datagram_frame_size_(0) {
+ if (close_connection_on_serialization_failure_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_close_connection_on_serialization_failure);
+ }
SetMaxPacketLength(kDefaultMaxPacketSize);
if (!framer_->version().UsesTls()) {
// QUIC+TLS negotiates the maximum datagram frame size via the
@@ -203,9 +207,7 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
// 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";
- if (coalesced_packet_of_higher_space_) {
- RemoveSoftMaxPacketLength();
- }
+ RemoveSoftMaxPacketLength();
return;
}
QUIC_DVLOG(1) << "Setting soft max packet length to: " << length;
@@ -413,13 +415,16 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
QuicStreamOffset offset,
bool fin,
QuicFrame* frame) {
- DCHECK_GT(
- max_packet_length_,
- StreamFramePacketOverhead(
- framer_->transport_version(), GetDestinationConnectionIdLength(),
- GetSourceConnectionIdLength(), kIncludeVersion,
- IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER,
- GetRetryTokenLengthLength(), GetLengthLength(), offset));
+ // Make sure max_packet_length_ is greater than the largest possible overhead
+ // or max_packet_length_ is set to the soft limit.
+ DCHECK(max_packet_length_ >
+ StreamFramePacketOverhead(
+ framer_->transport_version(),
+ GetDestinationConnectionIdLength(),
+ GetSourceConnectionIdLength(), kIncludeVersion,
+ IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER,
+ GetRetryTokenLengthLength(), GetLengthLength(), offset) ||
+ latched_hard_max_packet_length_ > 0);
QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset, data_size))
<< "No room for Stream frame, BytesFree: " << BytesFree()
@@ -444,15 +449,10 @@ bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level,
size_t write_length,
QuicStreamOffset offset,
QuicFrame* frame) {
- size_t min_frame_size =
+ const size_t min_frame_size =
QuicFramer::GetMinCryptoFrameSize(write_length, offset);
- size_t min_plaintext_bytes = min_frame_size;
- if (!fix_extra_padding_bytes_ && queued_frames_.empty()) {
- min_plaintext_bytes =
- std::max(min_frame_size, MinPlaintextPacketSize(framer_->version()));
- }
- if (BytesFree() <= min_plaintext_bytes &&
- (!RemoveSoftMaxPacketLength() || BytesFree() <= min_plaintext_bytes)) {
+ if (BytesFree() <= min_frame_size &&
+ (!RemoveSoftMaxPacketLength() || BytesFree() <= min_frame_size)) {
return false;
}
size_t max_write_length = BytesFree() - min_frame_size;
@@ -475,12 +475,18 @@ void QuicPacketCreator::FlushCurrentPacket() {
}
DCHECK_EQ(nullptr, packet_.encrypted_buffer);
- SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize);
+ const bool success =
+ SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize);
+ if (close_connection_on_serialization_failure_ && !success) {
+ return;
+ }
OnSerializedPacket();
}
void QuicPacketCreator::OnSerializedPacket() {
- if (packet_.encrypted_buffer == nullptr) {
+ if (close_connection_on_serialization_failure_) {
+ QUIC_BUG_IF(packet_.encrypted_buffer == nullptr);
+ } else if (packet_.encrypted_buffer == nullptr) {
const std::string error_details = "Failed to SerializePacket.";
QUIC_BUG << error_details;
delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
@@ -501,6 +507,8 @@ void QuicPacketCreator::ClearPacket() {
packet_.transmission_type = NOT_RETRANSMISSION;
packet_.encrypted_buffer = nullptr;
packet_.encrypted_length = 0;
+ packet_.has_ack_frequency = false;
+ packet_.has_message = false;
packet_.fate = SEND_TO_WRITER;
QUIC_BUG_IF(packet_.release_encrypted_buffer != nullptr)
<< "packet_.release_encrypted_buffer should be empty";
@@ -548,8 +556,11 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket(
return 0;
}
}
- SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
- // TODO(b/166255274): report unrecoverable error on serialization failures.
+ const bool success =
+ SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
+ if (close_connection_on_serialization_failure_ && !success) {
+ return 0;
+ }
const size_t encrypted_length = packet_.encrypted_length;
// Clear frames in packet_. No need to DeleteFrames since frames are owned by
// initial_packet.
@@ -567,19 +578,17 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
bool fin,
TransmissionType transmission_type,
size_t* num_bytes_consumed) {
+ // TODO(b/167222597): consider using ScopedSerializationFailureHandler.
DCHECK(queued_frames_.empty());
DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
// Write out the packet header
QuicPacketHeader header;
FillPacketHeader(&header);
- if (determine_serialized_packet_fate_early_) {
- packet_.fate = delegate_->GetSerializedPacketFate(
- /*is_mtu_discovery=*/false, packet_.encryption_level);
- QUIC_DVLOG(1) << ENDPOINT << "fate of packet " << packet_.packet_number
- << ": " << SerializedPacketFateToString(packet_.fate)
- << " of "
- << EncryptionLevelToString(packet_.encryption_level);
- }
+ packet_.fate = delegate_->GetSerializedPacketFate(
+ /*is_mtu_discovery=*/false, packet_.encryption_level);
+ QUIC_DVLOG(1) << ENDPOINT << "fate of packet " << packet_.packet_number
+ << ": " << SerializedPacketFateToString(packet_.fate) << " of "
+ << EncryptionLevelToString(packet_.encryption_level);
QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize];
QuicOwnedPacketBuffer packet_buffer(delegate_->GetPacketBuffer());
@@ -595,6 +604,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
size_t length_field_offset = 0;
if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) {
QUIC_BUG << "AppendPacketHeader failed";
+ RecordFailToSerializePacketLocation(kQuicFailToAppendPacketHeaderFastPath);
return;
}
@@ -636,10 +646,12 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
bool omit_frame_length = !needs_padding;
if (!framer_->AppendTypeByte(QuicFrame(frame), omit_frame_length, &writer)) {
QUIC_BUG << "AppendTypeByte failed";
+ RecordFailToSerializePacketLocation(kQuicFailToAppendTypeFastPath);
return;
}
if (!framer_->AppendStreamFrame(frame, omit_frame_length, &writer)) {
QUIC_BUG << "AppendStreamFrame failed";
+ RecordFailToSerializePacketLocation(kQuicFailToAppendStreamFrameFastPath);
return;
}
if (needs_padding &&
@@ -647,11 +659,14 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
!writer.WritePaddingBytes(MinPlaintextPacketSize(framer_->version()) -
plaintext_bytes_written)) {
QUIC_BUG << "Unable to add padding bytes";
+ RecordFailToSerializePacketLocation(kQuicFailToAddPaddingFastPath);
return;
}
if (!framer_->WriteIetfLongHeaderLength(header, &writer, length_field_offset,
packet_.encryption_level)) {
+ RecordFailToSerializePacketLocation(
+ kQuicFailToWriteIetfLongHeaderLengthFastPath);
return;
}
@@ -666,6 +681,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
writer.length(), kMaxOutgoingPacketSize, encrypted_buffer);
if (encrypted_length == 0) {
QUIC_BUG << "Failed to encrypt packet number " << header.packet_number;
+ RecordFailToSerializePacketLocation(kQuicFailToEncryptPacketFastPath);
return;
}
// TODO(ianswett): Optimize the storage so RetransmitableFrames can be
@@ -726,21 +742,14 @@ size_t QuicPacketCreator::ExpansionOnNewFrameWithLastFrame(
return kQuicStreamPayloadLengthSize;
}
-size_t QuicPacketCreator::BytesFree() {
+size_t QuicPacketCreator::BytesFree() const {
DCHECK_GE(max_plaintext_size_, PacketSize());
return max_plaintext_size_ -
std::min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame());
}
-size_t QuicPacketCreator::PacketSize() {
- if (update_packet_size_) {
- return queued_frames_.empty() ? PacketHeaderSize() : packet_size_;
- }
- if (!queued_frames_.empty()) {
- return packet_size_;
- }
- packet_size_ = PacketHeaderSize();
- return packet_size_;
+size_t QuicPacketCreator::PacketSize() const {
+ return queued_frames_.empty() ? PacketHeaderSize() : packet_size_;
}
bool QuicPacketCreator::AddPaddedSavedFrame(
@@ -753,11 +762,23 @@ bool QuicPacketCreator::AddPaddedSavedFrame(
return false;
}
-void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
+bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
size_t encrypted_buffer_len) {
- const bool use_queued_frames_cleaner = GetQuicReloadableFlag(
- quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded);
- ScopedQueuedFramesCleaner cleaner(use_queued_frames_cleaner ? this : nullptr);
+ if (close_connection_on_serialization_failure_ &&
+ packet_.encrypted_buffer != nullptr) {
+ RecordFailToSerializePacketLocation(kQuicSerializePacketNonEmptyBuffer);
+ const std::string error_details =
+ "Packet's encrypted buffer is not empty before serialization";
+ QUIC_BUG << error_details;
+ delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
+ error_details);
+ return false;
+ }
+ const bool use_handler =
+ GetQuicReloadableFlag(
+ quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded) ||
+ close_connection_on_serialization_failure_;
+ ScopedSerializationFailureHandler handler(use_handler ? this : nullptr);
DCHECK_LT(0u, encrypted_buffer_len);
QUIC_BUG_IF(queued_frames_.empty() && pending_padding_bytes_ == 0)
@@ -765,8 +786,7 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
QuicPacketHeader header;
// FillPacketHeader increments packet_number_.
FillPacketHeader(&header);
- if (determine_serialized_packet_fate_early_ && delegate_ != nullptr) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_determine_serialized_packet_fate_early);
+ if (delegate_ != nullptr) {
packet_.fate = delegate_->GetSerializedPacketFate(
/*is_mtu_discovery=*/QuicUtils::ContainsFrameType(queued_frames_,
MTU_DISCOVERY_FRAME),
@@ -784,11 +804,29 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
<< packet_.encryption_level;
if (!framer_->HasEncrypterOfEncryptionLevel(packet_.encryption_level)) {
+ // TODO(fayang): Use QUIC_MISSING_WRITE_KEYS for serialization failures due
+ // to missing keys.
QUIC_BUG << ENDPOINT << "Attempting to serialize " << header
<< QuicFramesToString(queued_frames_)
<< " at missing encryption_level " << packet_.encryption_level
<< " using " << framer_->version();
- return;
+ switch (packet_.encryption_level) {
+ case ENCRYPTION_INITIAL:
+ RecordFailToSerializePacketLocation(kQuicMissingInitialKey);
+ break;
+ case ENCRYPTION_HANDSHAKE:
+ RecordFailToSerializePacketLocation(kQuicMissingHandshakeKey);
+ break;
+ case ENCRYPTION_ZERO_RTT:
+ RecordFailToSerializePacketLocation(kQuicMissingZeroRttKey);
+ break;
+ case ENCRYPTION_FORWARD_SECURE:
+ RecordFailToSerializePacketLocation(kQuicMissingOneRttKey);
+ break;
+ default:
+ break;
+ }
+ return false;
}
DCHECK_GE(max_plaintext_size_, packet_size_);
@@ -806,7 +844,43 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
<< latched_hard_max_packet_length_
<< ", max_packet_length_: " << max_packet_length_
<< ", header: " << header;
- return;
+ switch (packet_.encryption_level) {
+ case ENCRYPTION_INITIAL:
+ if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) {
+ RecordFailToSerializePacketLocation(
+ kQuicFailToBuildPacketWithPaddingInitial);
+ } else {
+ RecordFailToSerializePacketLocation(kQuicFailToBuildPacketInitial);
+ }
+ break;
+ case ENCRYPTION_HANDSHAKE:
+ if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) {
+ RecordFailToSerializePacketLocation(
+ kQuicFailToBuildPacketWithPaddingHandshake);
+ } else {
+ RecordFailToSerializePacketLocation(kQuicFailToBuildPacketHandshake);
+ }
+ break;
+ case ENCRYPTION_ZERO_RTT:
+ if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) {
+ RecordFailToSerializePacketLocation(
+ kQuicFailToBuildPacketWithPaddingZeroRtt);
+ } else {
+ RecordFailToSerializePacketLocation(kQuicFailToBuildPacketZeroRtt);
+ }
+ break;
+ case ENCRYPTION_FORWARD_SECURE:
+ if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) {
+ RecordFailToSerializePacketLocation(
+ kQuicFailToBuildPacketWithPaddingOneRtt);
+ } else {
+ RecordFailToSerializePacketLocation(kQuicFailToBuildPacketOneRtt);
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
}
// ACK Frames will be truncated due to length only if they're the only frame
@@ -827,11 +901,27 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
encrypted_buffer_len, encrypted_buffer.buffer);
if (encrypted_length == 0) {
QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number;
- return;
+ switch (packet_.encryption_level) {
+ case ENCRYPTION_INITIAL:
+ RecordFailToSerializePacketLocation(kQuicFailToEncryptInitial);
+ break;
+ case ENCRYPTION_HANDSHAKE:
+ RecordFailToSerializePacketLocation(kQuicFailToEncryptHandshake);
+ break;
+ case ENCRYPTION_ZERO_RTT:
+ RecordFailToSerializePacketLocation(kQuicFailToEncryptZeroRtt);
+ break;
+ case ENCRYPTION_FORWARD_SECURE:
+ RecordFailToSerializePacketLocation(kQuicFailToEncryptOneRtt);
+ break;
+ default:
+ break;
+ }
+ return false;
}
packet_size_ = 0;
- if (!use_queued_frames_cleaner) {
+ if (!use_handler) {
queued_frames_.clear();
}
packet_.encrypted_buffer = encrypted_buffer.buffer;
@@ -839,6 +929,7 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
encrypted_buffer.buffer = nullptr;
packet_.release_encrypted_buffer = std::move(encrypted_buffer).release_buffer;
+ return true;
}
std::unique_ptr<QuicEncryptedPacket>
@@ -1331,12 +1422,9 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath(
bool fin,
size_t total_bytes_consumed) {
DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
- if (GetQuicReloadableFlag(quic_check_encryption_level_in_fast_path)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_check_encryption_level_in_fast_path);
- if (AttemptingToSendUnencryptedStreamData()) {
- return QuicConsumedData(total_bytes_consumed,
- fin && (total_bytes_consumed == write_length));
- }
+ if (AttemptingToSendUnencryptedStreamData()) {
+ return QuicConsumedData(total_bytes_consumed,
+ fin && (total_bytes_consumed == write_length));
}
while (total_bytes_consumed < write_length &&
@@ -1586,9 +1674,6 @@ size_t QuicPacketCreator::GetSerializedFrameLength(const QuicFrame& frame) {
size_t serialized_frame_length = framer_->GetSerializedFrameLength(
frame, BytesFree(), queued_frames_.empty(),
/* last_frame_in_packet= */ true, GetPacketNumberLength());
- if (!fix_extra_padding_bytes_) {
- return serialized_frame_length;
- }
if (!framer_->version().HasHeaderProtection() ||
serialized_frame_length == 0) {
return serialized_frame_length;
@@ -1600,7 +1685,6 @@ size_t QuicPacketCreator::GetSerializedFrameLength(const QuicFrame& frame) {
// No extra bytes is needed.
return serialized_frame_length;
}
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_extra_padding_bytes, 1, 3);
if (BytesFree() < serialized_frame_length) {
QUIC_BUG << ENDPOINT << "Frame does not fit: " << frame;
return 0;
@@ -1639,6 +1723,13 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
}
}
+ // If this is an ACK frame, validate that it is non-empty and that
+ // largest_acked matches the max packet number.
+ DCHECK(frame.type != ACK_FRAME ||
+ (!frame.ack_frame->packets.Empty() &&
+ frame.ack_frame->packets.Max() == frame.ack_frame->largest_acked))
+ << "Invalid ACK frame: " << frame;
+
size_t frame_len = GetSerializedFrameLength(frame);
if (frame_len == 0 && RemoveSoftMaxPacketLength()) {
// Remove soft max_packet_length and retry.
@@ -1650,8 +1741,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
FlushCurrentPacket();
return false;
}
- if (update_packet_size_ && queued_frames_.empty()) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_update_packet_size);
+ if (queued_frames_.empty()) {
packet_size_ = PacketHeaderSize();
}
DCHECK_LT(0u, packet_size_);
@@ -1680,9 +1770,12 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
if (frame.type == ACK_FRAME) {
packet_.has_ack = true;
packet_.largest_acked = LargestAcked(*frame.ack_frame);
- }
- if (frame.type == STOP_WAITING_FRAME) {
+ } else if (frame.type == STOP_WAITING_FRAME) {
packet_.has_stop_waiting = true;
+ } else if (frame.type == ACK_FREQUENCY_FRAME) {
+ packet_.has_ack_frequency = true;
+ } else if (frame.type == MESSAGE_FRAME) {
+ packet_.has_message = true;
}
if (debug_delegate_ != nullptr) {
debug_delegate_->OnFrameAddedToPacket(frame);
@@ -1697,7 +1790,6 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
}
void QuicPacketCreator::MaybeAddExtraPaddingForHeaderProtection() {
- DCHECK(fix_extra_padding_bytes_);
if (!framer_->version().HasHeaderProtection() || needs_full_padding_) {
return;
}
@@ -1709,7 +1801,6 @@ void QuicPacketCreator::MaybeAddExtraPaddingForHeaderProtection() {
std::max(1 + ExpansionOnNewFrame(),
MinPlaintextPacketSize(framer_->version()) - frame_bytes) -
ExpansionOnNewFrame();
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_extra_padding_bytes, 2, 3);
// Update pending_padding_bytes_.
pending_padding_bytes_ =
std::max(pending_padding_bytes_, min_header_protection_padding);
@@ -1772,59 +1863,16 @@ void QuicPacketCreator::MaybeAddPadding() {
needs_full_padding_ = true;
}
- if (determine_serialized_packet_fate_early_) {
- if (packet_.fate == COALESCE ||
- packet_.fate == LEGACY_VERSION_ENCAPSULATE) {
- // Do not add full padding if the packet is going to be coalesced or
- // encapsulated.
- needs_full_padding_ = false;
- }
- } else {
- // Packet coalescer pads INITIAL packets, so the creator should not.
- if (framer_->version().CanSendCoalescedPackets() &&
- (packet_.encryption_level == ENCRYPTION_INITIAL ||
- packet_.encryption_level == ENCRYPTION_HANDSHAKE)) {
- // TODO(fayang): MTU discovery packets should not ever be sent as
- // ENCRYPTION_INITIAL or ENCRYPTION_HANDSHAKE.
- bool is_mtu_discovery = false;
- for (const auto& frame : packet_.nonretransmittable_frames) {
- if (frame.type == MTU_DISCOVERY_FRAME) {
- is_mtu_discovery = true;
- break;
- }
- }
- if (!is_mtu_discovery) {
- // Do not add full padding if connection tries to coalesce packet.
- needs_full_padding_ = false;
- }
- }
-
- if (disable_padding_override_) {
- needs_full_padding_ = false;
- }
+ if (packet_.fate == COALESCE || packet_.fate == LEGACY_VERSION_ENCAPSULATE) {
+ // Do not add full padding if the packet is going to be coalesced or
+ // encapsulated.
+ needs_full_padding_ = false;
}
// Header protection requires a minimum plaintext packet size.
- // TODO(fayang): remove extra_padding_bytes when deprecating
- // quic_fix_extra_padding_bytes.
- size_t extra_padding_bytes = 0;
- if (fix_extra_padding_bytes_) {
- MaybeAddExtraPaddingForHeaderProtection();
- } else {
- if (framer_->version().HasHeaderProtection()) {
- size_t frame_bytes = PacketSize() - PacketHeaderSize();
-
- if (frame_bytes + pending_padding_bytes_ <
- MinPlaintextPacketSize(framer_->version()) &&
- !needs_full_padding_) {
- extra_padding_bytes =
- MinPlaintextPacketSize(framer_->version()) - frame_bytes;
- }
- }
- }
+ MaybeAddExtraPaddingForHeaderProtection();
- if (!needs_full_padding_ && pending_padding_bytes_ == 0 &&
- extra_padding_bytes == 0) {
+ if (!needs_full_padding_ && pending_padding_bytes_ == 0) {
// Do not need padding.
return;
}
@@ -1833,7 +1881,6 @@ void QuicPacketCreator::MaybeAddPadding() {
if (!needs_full_padding_) {
padding_bytes = std::min<int16_t>(pending_padding_bytes_, BytesFree());
pending_padding_bytes_ -= padding_bytes;
- padding_bytes = std::max<int16_t>(padding_bytes, extra_padding_bytes);
}
bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)),
@@ -2018,16 +2065,83 @@ bool QuicPacketCreator::HasSoftMaxPacketLength() const {
return latched_hard_max_packet_length_ != 0;
}
-QuicPacketCreator::ScopedQueuedFramesCleaner::ScopedQueuedFramesCleaner(
- QuicPacketCreator* creator)
+void QuicPacketCreator::SetDefaultPeerAddress(QuicSocketAddress address) {
+ if (!packet_.peer_address.IsInitialized()) {
+ packet_.peer_address = address;
+ return;
+ }
+ if (packet_.peer_address != address) {
+ FlushCurrentPacket();
+ packet_.peer_address = address;
+ }
+}
+
+QuicPacketCreator::ScopedPeerAddressContext::ScopedPeerAddressContext(
+ QuicPacketCreator* creator,
+ QuicSocketAddress address)
+ : creator_(creator), old_peer_address_(creator_->packet_.peer_address) {
+ QUIC_BUG_IF(!creator_->packet_.peer_address.IsInitialized())
+ << "Context is used before seralized packet's peer address is "
+ "initialized.";
+ creator_->SetDefaultPeerAddress(address);
+}
+
+QuicPacketCreator::ScopedPeerAddressContext::~ScopedPeerAddressContext() {
+ creator_->SetDefaultPeerAddress(old_peer_address_);
+}
+
+QuicPacketCreator::ScopedSerializationFailureHandler::
+ ScopedSerializationFailureHandler(QuicPacketCreator* creator)
: creator_(creator) {}
-QuicPacketCreator::ScopedQueuedFramesCleaner::~ScopedQueuedFramesCleaner() {
+QuicPacketCreator::ScopedSerializationFailureHandler::
+ ~ScopedSerializationFailureHandler() {
if (creator_ == nullptr) {
return;
}
+ // Always clear queued_frames_.
creator_->queued_frames_.clear();
+
+ if (creator_->close_connection_on_serialization_failure_ &&
+ creator_->packet_.encrypted_buffer == nullptr) {
+ const std::string error_details = "Failed to SerializePacket.";
+ QUIC_BUG << error_details;
+ creator_->delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
+ error_details);
+ }
}
+void QuicPacketCreator::set_encryption_level(EncryptionLevel level) {
+ DCHECK(level == packet_.encryption_level || !HasPendingFrames())
+ << "Cannot update encryption level from " << packet_.encryption_level
+ << " to " << level << " when we already have pending frames: "
+ << QuicFramesToString(queued_frames_);
+ packet_.encryption_level = level;
+}
+
+bool QuicPacketCreator::AddPathResponseFrame(
+ const QuicPathFrameBuffer& data_buffer) {
+ auto path_response =
+ new QuicPathResponseFrame(kInvalidControlFrameId, data_buffer);
+ QuicFrame frame(path_response);
+ if (HasPendingFrames()) {
+ if (AddPaddedSavedFrame(frame, NOT_RETRANSMISSION)) {
+ // Frame is queued.
+ return true;
+ }
+ }
+ // Frame was not queued but queued frames were flushed.
+ DCHECK(!HasPendingFrames());
+ if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ QUIC_DVLOG(1) << ENDPOINT << "Can't send PATH_RESPONSE now";
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 5, 5);
+ delete path_response;
+ return false;
+ }
+ bool success = AddPaddedSavedFrame(frame, NOT_RETRANSMISSION);
+ QUIC_BUG_IF(!success);
+ return true;
+}
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
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 aefa975efb2..b025d06f66f 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
@@ -27,6 +27,7 @@
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -82,6 +83,20 @@ 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.
+ class QUIC_EXPORT_PRIVATE ScopedPeerAddressContext {
+ public:
+ ScopedPeerAddressContext(QuicPacketCreator* creator,
+ QuicSocketAddress address);
+ ~ScopedPeerAddressContext();
+
+ private:
+ QuicPacketCreator* creator_;
+ QuicSocketAddress old_peer_address_;
+ };
+
QuicPacketCreator(QuicConnectionId server_connection_id,
QuicFramer* framer,
DelegateInterface* delegate);
@@ -149,14 +164,14 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Returns true if current open packet can accommodate more stream frames of
// stream |id| at |offset| and data length |data_size|, false otherwise.
- // TODO(fayang): mark this const when deprecating quic_update_packet_size.
+ // TODO(fayang): mark this const by moving RemoveSoftMaxPacketLength out.
bool HasRoomForStreamFrame(QuicStreamId id,
QuicStreamOffset offset,
size_t data_size);
// Returns true if current open packet can accommodate a message frame of
// |length|.
- // TODO(fayang): mark this const when deprecating quic_update_packet_size.
+ // TODO(fayang): mark this const by moving RemoveSoftMaxPacketLength out.
bool HasRoomForMessageFrame(QuicByteCount length);
// Serializes all added frames into a single packet and invokes the delegate_
@@ -188,8 +203,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// frames in the packet. Since stream frames are slightly smaller when they
// are the last frame in a packet, this method will return a different
// value than max_packet_size - PacketSize(), in this case.
- // TODO(fayang): mark this const when deprecating quic_update_packet_size.
- size_t BytesFree();
+ size_t BytesFree() const;
// Returns the number of bytes that the packet will expand by if a new frame
// is added to the packet. If the last frame was a stream frame, it will
@@ -206,8 +220,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// if serialized with the current frames. Adding a frame to the packet
// may change the serialized length of existing frames, as per the comment
// in BytesFree.
- // TODO(fayang): mark this const when deprecating quic_update_packet_size.
- size_t PacketSize();
+ size_t PacketSize() const;
// Tries to add |frame| to the packet creator's list of frames to be
// serialized. If the frame does not fit into the current packet, flushes the
@@ -242,6 +255,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded);
+ // Add PATH_RESPONSE to current packet, flush before or afterwards if needed.
+ bool AddPathResponseFrame(const QuicPathFrameBuffer& data_buffer);
+
// Returns a dummy packet that is valid but contains no useful information.
static SerializedPacket NoPacket();
@@ -268,9 +284,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
void SetClientConnectionId(QuicConnectionId client_connection_id);
// Sets the encryption level that will be applied to new packets.
- void set_encryption_level(EncryptionLevel level) {
- packet_.encryption_level = level;
- }
+ void set_encryption_level(EncryptionLevel level);
EncryptionLevel encryption_level() { return packet_.encryption_level; }
// packet number of the last created packet, or 0 if no packets have been
@@ -451,26 +465,19 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Returns true if max_packet_length_ is currently a soft value.
bool HasSoftMaxPacketLength() const;
- void set_disable_padding_override(bool should_disable_padding) {
- disable_padding_override_ = should_disable_padding;
- }
-
- bool determine_serialized_packet_fate_early() const {
- return determine_serialized_packet_fate_early_;
- }
-
- bool coalesced_packet_of_higher_space() const {
- return coalesced_packet_of_higher_space_;
- }
+ // Use this address to sent to the peer from now on. If this address is
+ // different from the current one, flush all the queue frames first.
+ void SetDefaultPeerAddress(QuicSocketAddress address);
private:
friend class test::QuicPacketCreatorPeer;
- // Used to clear queued_frames_ of creator upon exiting the scope.
- class QUIC_EXPORT_PRIVATE ScopedQueuedFramesCleaner {
+ // Used to 1) clear queued_frames_, 2) report unrecoverable error (if
+ // serialization fails) upon exiting the scope.
+ class QUIC_EXPORT_PRIVATE ScopedSerializationFailureHandler {
public:
- explicit ScopedQueuedFramesCleaner(QuicPacketCreator* creator);
- ~ScopedQueuedFramesCleaner();
+ explicit ScopedSerializationFailureHandler(QuicPacketCreator* creator);
+ ~ScopedSerializationFailureHandler();
private:
QuicPacketCreator* creator_; // Unowned.
@@ -501,10 +508,11 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Serializes all frames which have been added and adds any which should be
// retransmitted to packet_.retransmittable_frames. All frames must fit into
- // a single packet.
- // Fails if |encrypted_buffer_len| isn't long enough for the encrypted packet.
- void SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
- size_t encrypted_buffer_len);
+ // a single packet. Returns true on success, otherwise, returns false.
+ // Fails if |encrypted_buffer| is not large enough for the encrypted packet.
+ QUIC_MUST_USE_RESULT bool SerializePacket(
+ QuicOwnedPacketBuffer encrypted_buffer,
+ size_t encrypted_buffer_len);
// Called after a new SerialiedPacket is created to call the delegate's
// OnSerializedPacket and reset state.
@@ -655,22 +663,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// negotiates this during the handshake.
QuicByteCount max_datagram_frame_size_;
- // When true, this will override the padding generation code to disable it.
- // TODO(fayang): remove this when deprecating
- // quic_determine_serialized_packet_fate_early.
- bool disable_padding_override_ = false;
-
- const bool update_packet_size_ =
- GetQuicReloadableFlag(quic_update_packet_size);
-
- const bool fix_extra_padding_bytes_ =
- GetQuicReloadableFlag(quic_fix_extra_padding_bytes);
-
- const bool determine_serialized_packet_fate_early_ =
- GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early);
-
- const bool coalesced_packet_of_higher_space_ =
- GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2);
+ const bool close_connection_on_serialization_failure_ =
+ GetQuicReloadableFlag(quic_close_connection_on_serialization_failure);
};
} // 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 60703fb4b65..4afbf06158a 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
@@ -164,10 +164,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
creator_(connection_id_, &client_framer_, &delegate_, &producer_) {
EXPECT_CALL(delegate_, GetPacketBuffer())
.WillRepeatedly(Return(QuicPacketBuffer()));
- if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early)) {
- EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _))
- .WillRepeatedly(Return(SEND_TO_WRITER));
- }
+ EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _))
+ .WillRepeatedly(Return(SEND_TO_WRITER));
creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>(
Perspective::IS_CLIENT));
creator_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<NullEncrypter>(
@@ -510,8 +508,7 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early) &&
- client_framer_.version().CanSendCoalescedPackets()) {
+ if (client_framer_.version().CanSendCoalescedPackets()) {
EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _))
.WillRepeatedly(Return(COALESCE));
}
@@ -2453,10 +2450,8 @@ class QuicPacketCreatorMultiplePacketsTest : public QuicTest {
ack_frame_(InitAckFrame(1)) {
EXPECT_CALL(delegate_, GetPacketBuffer())
.WillRepeatedly(Return(QuicPacketBuffer()));
- if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early)) {
- EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _))
- .WillRepeatedly(Return(SEND_TO_WRITER));
- }
+ EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _))
+ .WillRepeatedly(Return(SEND_TO_WRITER));
creator_.SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
@@ -2595,9 +2590,6 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_NotWritable) {
TEST_F(QuicPacketCreatorMultiplePacketsTest,
WrongEncryptionLevelForStreamDataFastPath) {
- if (!GetQuicReloadableFlag(quic_check_encryption_level_in_fast_path)) {
- return;
- }
creator_.set_encryption_level(ENCRYPTION_HANDSHAKE);
delegate_.SetCanWriteAnything();
// Create a 10000 byte IOVector.
@@ -3825,12 +3817,136 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ExtraPaddingNeeded) {
creator_.Flush();
ASSERT_FALSE(packets_[0].nonretransmittable_frames.empty());
QuicFrame padding = packets_[0].nonretransmittable_frames[0];
- if (GetQuicReloadableFlag(quic_fix_extra_padding_bytes)) {
- // Verify stream frame expansion is excluded.
- padding.padding_frame.num_padding_bytes = 3;
- } else {
- padding.padding_frame.num_padding_bytes = 4;
- }
+ // Verify stream frame expansion is excluded.
+ padding.padding_frame.num_padding_bytes = 3;
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ PeerAddressContextWithSameAddress) {
+ QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
+ creator_.SetDefaultPeerAddress(peer_addr);
+ // Send some stream data.
+ MakeIOVector("foo", &iov_);
+ EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(true));
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ 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);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ // Queue another STREAM_FRAME.
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ }
+ // After exiting the scope, the last queued frame should be flushed.
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke([=](SerializedPacket packet) {
+ EXPECT_EQ(peer_addr, packet.peer_address);
+ ASSERT_EQ(2u, packet.retransmittable_frames.size());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.back().type);
+ }));
+ creator_.FlushCurrentPacket();
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ PeerAddressContextWithDifferentAddress) {
+ QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
+ creator_.SetDefaultPeerAddress(peer_addr);
+ // Send some stream data.
+ MakeIOVector("foo", &iov_);
+ EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(true));
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+
+ QuicSocketAddress peer_addr1(QuicIpAddress::Any4(), 12346);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke([=](SerializedPacket packet) {
+ EXPECT_EQ(peer_addr, packet.peer_address);
+ ASSERT_EQ(1u, packet.retransmittable_frames.size());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ }))
+ .WillOnce(Invoke([=](SerializedPacket packet) {
+ EXPECT_EQ(peer_addr1, packet.peer_address);
+ ASSERT_EQ(1u, packet.retransmittable_frames.size());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ }));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ {
+ // Set a different address via context which should trigger flush.
+ QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr1);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ // Queue another STREAM_FRAME.
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ }
+ // After exiting the scope, the last queued frame should be flushed.
+ EXPECT_FALSE(creator_.HasPendingFrames());
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ NestedPeerAddressContextWithDifferentAddress) {
+ QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
+ creator_.SetDefaultPeerAddress(peer_addr);
+ QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr);
+
+ // Send some stream data.
+ MakeIOVector("foo", &iov_);
+ EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(true));
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ QuicSocketAddress peer_addr1(QuicIpAddress::Any4(), 12346);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke([=](SerializedPacket packet) {
+ EXPECT_EQ(peer_addr, packet.peer_address);
+ ASSERT_EQ(1u, packet.retransmittable_frames.size());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+
+ // Set up another context with a different address.
+ QuicPacketCreator::ScopedPeerAddressContext context(&creator_,
+ peer_addr1);
+ MakeIOVector("foo", &iov_);
+ EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(true));
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(
+ creator_.transport_version(), Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ // This should trigger another OnSerializedPacket() with the 2nd
+ // address.
+ creator_.FlushCurrentPacket();
+ }))
+ .WillOnce(Invoke([=](SerializedPacket packet) {
+ EXPECT_EQ(peer_addr1, packet.peer_address);
+ ASSERT_EQ(1u, packet.retransmittable_frames.size());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ }));
+ creator_.FlushCurrentPacket();
}
} // namespace
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 6ffa39a07d1..f54cf00d081 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
@@ -463,6 +463,8 @@ SerializedPacket::SerializedPacket(QuicPacketNumber packet_number,
has_stop_waiting(has_stop_waiting),
transmission_type(NOT_RETRANSMISSION),
has_ack_frame_copy(false),
+ has_ack_frequency(false),
+ has_message(false),
fate(SEND_TO_WRITER) {}
SerializedPacket::SerializedPacket(SerializedPacket&& other)
@@ -475,7 +477,10 @@ SerializedPacket::SerializedPacket(SerializedPacket&& other)
transmission_type(other.transmission_type),
largest_acked(other.largest_acked),
has_ack_frame_copy(other.has_ack_frame_copy),
- fate(other.fate) {
+ has_ack_frequency(other.has_ack_frequency),
+ has_message(other.has_message),
+ fate(other.fate),
+ peer_address(other.peer_address) {
if (this != &other) {
if (release_encrypted_buffer && encrypted_buffer != nullptr) {
release_encrypted_buffer(encrypted_buffer);
@@ -518,7 +523,10 @@ SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized,
copy->encryption_level = serialized.encryption_level;
copy->transmission_type = serialized.transmission_type;
copy->largest_acked = serialized.largest_acked;
+ copy->has_ack_frequency = serialized.has_ack_frequency;
+ copy->has_message = serialized.has_message;
copy->fate = serialized.fate;
+ copy->peer_address = serialized.peer_address;
if (copy_buffer) {
copy->encrypted_buffer = CopyBuffer(serialized);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
index 450b842fcb8..e9c811c6737 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
@@ -403,7 +403,10 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket {
// Indicates whether this packet has a copy of ack frame in
// nonretransmittable_frames.
bool has_ack_frame_copy;
+ bool has_ack_frequency;
+ bool has_message;
SerializedPacketFate fate;
+ QuicSocketAddress peer_address;
};
// Make a copy of |serialized| (including the underlying frames). |copy_buffer|
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 9cc6c295eda..9a84d975fd5 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
@@ -41,58 +41,30 @@ QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats)
time_largest_observed_(QuicTime::Zero()),
save_timestamps_(false),
stats_(stats),
- ack_mode_(ACK_DECIMATION),
num_retransmittable_packets_received_since_last_ack_sent_(0),
min_received_before_ack_decimation_(kMinReceivedBeforeAckDecimation),
ack_frequency_(kDefaultRetransmittablePacketsBeforeAck),
ack_decimation_delay_(kAckDecimationDelay),
unlimited_ack_decimation_(false),
- fast_ack_after_quiescence_(false),
one_immediate_ack_(false),
+ ignore_order_(false),
local_max_ack_delay_(
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
ack_timeout_(QuicTime::Zero()),
time_of_previous_received_packet_(QuicTime::Zero()),
- was_last_packet_missing_(false) {}
+ was_last_packet_missing_(false),
+ last_ack_frequency_frame_sequence_number_(-1) {}
QuicReceivedPacketManager::~QuicReceivedPacketManager() {}
void QuicReceivedPacketManager::SetFromConfig(const QuicConfig& config,
Perspective perspective) {
- if (remove_unused_ack_options_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_remove_unused_ack_options);
- }
- if (!remove_unused_ack_options_) {
- if (config.HasClientSentConnectionOption(kACD0, perspective)) {
- ack_mode_ = TCP_ACKING;
- }
- if (config.HasClientSentConnectionOption(kACKD, perspective)) {
- ack_mode_ = ACK_DECIMATION;
- }
- if (config.HasClientSentConnectionOption(kAKD2, perspective)) {
- ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
- }
- }
if (config.HasClientSentConnectionOption(kAKD3, perspective)) {
- if (!remove_unused_ack_options_) {
- ack_mode_ = ACK_DECIMATION;
- }
ack_decimation_delay_ = kShortAckDecimationDelay;
}
- if (!remove_unused_ack_options_) {
- if (config.HasClientSentConnectionOption(kAKD4, perspective)) {
- ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
- ack_decimation_delay_ = kShortAckDecimationDelay;
- }
- }
if (config.HasClientSentConnectionOption(kAKDU, perspective)) {
unlimited_ack_decimation_ = true;
}
- if (!remove_unused_ack_options_) {
- if (config.HasClientSentConnectionOption(kACKQ, perspective)) {
- fast_ack_after_quiescence_ = true;
- }
- }
if (config.HasClientSentConnectionOption(k1ACK, perspective)) {
one_immediate_ack_ = true;
}
@@ -189,7 +161,13 @@ const QuicFrame QuicReceivedPacketManager::GetUpdatedAckFrame(
}
}
+#if QUIC_FRAME_DEBUG
+ QuicFrame frame = QuicFrame(&ack_frame_);
+ frame.delete_forbidden = true;
+ return frame;
+#else // QUIC_FRAME_DEBUG
return QuicFrame(&ack_frame_);
+#endif // QUIC_FRAME_DEBUG
}
void QuicReceivedPacketManager::DontWaitForPacketsBefore(
@@ -218,9 +196,9 @@ void QuicReceivedPacketManager::DontWaitForPacketsBefore(
QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay(
QuicPacketNumber last_received_packet_number,
const RttStats& rtt_stats) const {
- DCHECK(simplify_received_packet_manager_ack_);
- if (last_received_packet_number <
- PeerFirstSendingPacketNumber() + min_received_before_ack_decimation_) {
+ if (AckFrequencyFrameReceived() ||
+ last_received_packet_number < PeerFirstSendingPacketNumber() +
+ min_received_before_ack_decimation_) {
return local_max_ack_delay_;
}
@@ -237,7 +215,11 @@ QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay(
void QuicReceivedPacketManager::MaybeUpdateAckFrequency(
QuicPacketNumber last_received_packet_number) {
- DCHECK(simplify_received_packet_manager_ack_);
+ if (AckFrequencyFrameReceived()) {
+ // Skip Ack Decimation below after receiving an AckFrequencyFrame from the
+ // other end point.
+ return;
+ }
if (last_received_packet_number <
PeerFirstSendingPacketNumber() + min_received_before_ack_decimation_) {
return;
@@ -250,7 +232,6 @@ void QuicReceivedPacketManager::MaybeUpdateAckFrequency(
void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
bool should_last_packet_instigate_acks,
QuicPacketNumber last_received_packet_number,
- QuicTime time_of_last_received_packet,
QuicTime now,
const RttStats* rtt_stats) {
if (!ack_frame_updated_) {
@@ -258,7 +239,8 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
return;
}
- if (was_last_packet_missing_ && last_sent_largest_acked_.IsInitialized() &&
+ if (!ignore_order_ && was_last_packet_missing_ &&
+ last_sent_largest_acked_.IsInitialized() &&
last_received_packet_number < last_sent_largest_acked_) {
// Only ack immediately if an ACK frame was sent with a larger largest acked
// than the newly received packet number.
@@ -272,85 +254,20 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
++num_retransmittable_packets_received_since_last_ack_sent_;
- if (simplify_received_packet_manager_ack_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_simplify_received_packet_manager_ack);
- MaybeUpdateAckFrequency(last_received_packet_number);
- if (num_retransmittable_packets_received_since_last_ack_sent_ >=
- ack_frequency_) {
- ack_timeout_ = now;
- return;
- }
-
- if (HasNewMissingPackets()) {
- ack_timeout_ = now;
- return;
- }
-
- MaybeUpdateAckTimeoutTo(
- now + GetMaxAckDelay(last_received_packet_number, *rtt_stats));
+ MaybeUpdateAckFrequency(last_received_packet_number);
+ if (num_retransmittable_packets_received_since_last_ack_sent_ >=
+ ack_frequency_) {
+ ack_timeout_ = now;
return;
}
- if (ack_mode_ != TCP_ACKING &&
- last_received_packet_number >= PeerFirstSendingPacketNumber() +
- min_received_before_ack_decimation_) {
- // Ack up to 10 packets at once unless ack decimation is unlimited.
- if (!unlimited_ack_decimation_ &&
- num_retransmittable_packets_received_since_last_ack_sent_ >=
- kMaxRetransmittablePacketsBeforeAck) {
- ack_timeout_ = now;
- return;
- }
- // Wait for the minimum of the ack decimation delay or the delayed ack time
- // 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);
- }
- if (fast_ack_after_quiescence_ && now - time_of_previous_received_packet_ >
- rtt_stats->SmoothedOrInitialRtt()) {
- // Ack the first packet out of queiscence faster, because QUIC does
- // not pace the first few packets and commonly these may be handshake
- // or TLP packets, which we'd like to acknowledge quickly.
- ack_delay = kAlarmGranularity;
- }
- MaybeUpdateAckTimeoutTo(now + ack_delay);
- } else {
- // Ack with a timer or every 2 packets by default.
- if (num_retransmittable_packets_received_since_last_ack_sent_ >=
- ack_frequency_) {
- ack_timeout_ = now;
- } else if (fast_ack_after_quiescence_ &&
- (now - time_of_previous_received_packet_) >
- rtt_stats->SmoothedOrInitialRtt()) {
- // Ack the first packet out of queiscence faster, because QUIC does
- // not pace the first few packets and commonly these may be handshake
- // or TLP packets, which we'd like to acknowledge quickly.
- MaybeUpdateAckTimeoutTo(now + kAlarmGranularity);
- } else {
- MaybeUpdateAckTimeoutTo(now + local_max_ack_delay_);
- }
- }
-
- // If there are new missing packets to report, send an ack immediately.
- if (HasNewMissingPackets()) {
- // TODO(haoyuewang) Remove ACK_DECIMATION_WITH_REORDERING after
- // quic_remove_unused_ack_options is deprecated.
- if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) {
- DCHECK(!remove_unused_ack_options_);
- // Wait the minimum of an eighth min_rtt and the existing ack time.
- QuicTime ack_time = now + kShortAckDecimationDelay * rtt_stats->min_rtt();
- MaybeUpdateAckTimeoutTo(ack_time);
- } else {
- ack_timeout_ = now;
- }
+ if (!ignore_order_ && HasNewMissingPackets()) {
+ ack_timeout_ = now;
+ return;
}
- if (fast_ack_after_quiescence_) {
- time_of_previous_received_packet_ = time_of_last_received_packet;
- }
+ MaybeUpdateAckTimeoutTo(
+ now + GetMaxAckDelay(last_received_packet_number, *rtt_stats));
}
void QuicReceivedPacketManager::ResetAckStates() {
@@ -406,4 +323,17 @@ bool QuicReceivedPacketManager::IsAckFrameEmpty() const {
return ack_frame_.packets.Empty();
}
+void QuicReceivedPacketManager::OnAckFrequencyFrame(
+ const QuicAckFrequencyFrame& frame) {
+ int64_t new_sequence_number = frame.sequence_number;
+ if (new_sequence_number <= last_ack_frequency_frame_sequence_number_) {
+ // Ignore old ACK_FREQUENCY frames.
+ return;
+ }
+ last_ack_frequency_frame_sequence_number_ = new_sequence_number;
+ ack_frequency_ = frame.packet_tolerance;
+ local_max_ack_delay_ = frame.max_ack_delay;
+ ignore_order_ = frame.ignore_order;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h
index 5f5525a3ab9..78ed4111585 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h
@@ -5,6 +5,8 @@
#ifndef QUICHE_QUIC_CORE_QUIC_RECEIVED_PACKET_MANAGER_H_
#define QUICHE_QUIC_CORE_QUIC_RECEIVED_PACKET_MANAGER_H_
+#include <cstddef>
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_config.h"
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
@@ -62,7 +64,6 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
// Otherwise, ACK needs to be sent by the specified time.
void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks,
QuicPacketNumber last_received_packet_number,
- QuicTime time_of_last_received_packet,
QuicTime now,
const RttStats* rtt_stats);
@@ -124,6 +125,8 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
QuicTime ack_timeout() const { return ack_timeout_; }
+ void OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame);
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicReceivedPacketManagerPeer;
@@ -138,6 +141,10 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
QuicTime::Delta GetMaxAckDelay(QuicPacketNumber last_received_packet_number,
const RttStats& rtt_stats) const;
+ bool AckFrequencyFrameReceived() const {
+ return last_ack_frequency_frame_sequence_number_ >= 0;
+ }
+
// Least packet number of the the packet sent by the peer for which it
// hasn't received an ack.
QuicPacketNumber peer_least_packet_awaiting_ack_;
@@ -165,7 +172,6 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
QuicConnectionStats* stats_;
- AckMode ack_mode_;
// How many retransmittable packets have arrived without sending an ack.
QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_;
// Ack decimation will start happening after this many packets are received.
@@ -177,13 +183,10 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
// When true, removes ack decimation's max number of packets(10) before
// sending an ack.
bool unlimited_ack_decimation_;
- // When true, use a 1ms delayed ack timer if it's been an SRTT since a packet
- // was received.
- // TODO(haoyuewang) Remove fast_ack_after_quiescence_ when
- // quic_remove_unused_ack_options flag is deprecated.
- bool fast_ack_after_quiescence_;
// When true, only send 1 immediate ACK when reordering is detected.
bool one_immediate_ack_;
+ // When true, do not ack immediately upon observation of packet reordering.
+ bool ignore_order_;
// The local node's maximum ack delay time. This is the maximum amount of
// time to wait before sending an acknowledgement.
@@ -197,17 +200,12 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
// Whether the most recent packet was missing before it was received.
bool was_last_packet_missing_;
- // TODO(haoyuewang) Remove TCP_ACKING when
- // fast_ack_after_quiescence_ when this flag is deprecated.
- const bool remove_unused_ack_options_ =
- GetQuicReloadableFlag(quic_remove_unused_ack_options);
-
- const bool simplify_received_packet_manager_ack_ =
- remove_unused_ack_options_ &&
- GetQuicReloadableFlag(quic_simplify_received_packet_manager_ack);
-
// Last sent largest acked, which gets updated when ACK was successfully sent.
QuicPacketNumber last_sent_largest_acked_;
+
+ // The sequence number of the last received AckFrequencyFrame. Negative if
+ // none received.
+ int64_t last_ack_frequency_frame_sequence_number_;
};
} // namespace quic
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 ca56662904f..c8d16388470 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
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
#include <algorithm>
+#include <cstddef>
#include <ostream>
#include <vector>
@@ -22,15 +23,6 @@ namespace test {
class QuicReceivedPacketManagerPeer {
public:
- static void SetAckMode(QuicReceivedPacketManager* manager, AckMode ack_mode) {
- manager->ack_mode_ = ack_mode;
- }
-
- static void SetFastAckAfterQuiescence(QuicReceivedPacketManager* manager,
- bool fast_ack_after_quiescence) {
- manager->fast_ack_after_quiescence_ = fast_ack_after_quiescence;
- }
-
static void SetOneImmediateAck(QuicReceivedPacketManager* manager,
bool one_immediate_ack) {
manager->one_immediate_ack_ = one_immediate_ack;
@@ -97,7 +89,7 @@ class QuicReceivedPacketManagerTest : public QuicTestWithParam<TestParams> {
received_manager_.MaybeUpdateAckTimeout(
should_last_packet_instigate_acks,
QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
- clock_.ApproximateNow(), &rtt_stats_);
+ &rtt_stats_);
}
void CheckAckTimeout(QuicTime time) {
@@ -368,8 +360,6 @@ TEST_P(QuicReceivedPacketManagerTest, AckSentEveryNthPacket) {
TEST_P(QuicReceivedPacketManagerTest, AckDecimationReducesAcks) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_,
- ACK_DECIMATION_WITH_REORDERING);
// Start ack decimation from 10th packet.
received_manager_.set_min_received_before_ack_decimation(10);
@@ -401,45 +391,8 @@ TEST_P(QuicReceivedPacketManagerTest, AckDecimationReducesAcks) {
CheckAckTimeout(clock_.ApproximateNow());
}
-TEST_P(QuicReceivedPacketManagerTest, SendDelayedAfterQuiescence) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetFastAckAfterQuiescence(&received_manager_,
- true);
- // The beginning of the connection counts as quiescence.
- QuicTime ack_time =
- clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
-
- RecordPacketReceipt(1, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 1);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Process another packet immediately after sending the ack and expect the
- // ack timeout to be set delayed ack time in the future.
- ack_time = clock_.ApproximateNow() + kDelayedAckTime;
- RecordPacketReceipt(2, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 2);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(kDelayedAckTime);
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(3, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 3);
- CheckAckTimeout(ack_time);
-}
-
TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimation) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION);
// The ack time should be based on min_rtt * 1/4, since it's less than the
// default delayed ack time.
QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
@@ -474,7 +427,6 @@ TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationMin1ms) {
return;
}
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION);
// Seed the min_rtt with a kAlarmGranularity signal.
rtt_stats_.UpdateRtt(kAlarmGranularity, QuicTime::Delta::Zero(),
clock_.ApproximateNow());
@@ -507,76 +459,6 @@ TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationMin1ms) {
}
TEST_P(QuicReceivedPacketManagerTest,
- SendDelayedAckAckDecimationAfterQuiescence) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION);
- QuicReceivedPacketManagerPeer::SetFastAckAfterQuiescence(&received_manager_,
- true);
- // The beginning of the connection counts as quiescence.
- QuicTime ack_time =
- clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(1, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 1);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Process another packet immedately after sending the ack and expect the
- // ack timeout to be set delayed ack time in the future.
- ack_time = clock_.ApproximateNow() + kDelayedAckTime;
- RecordPacketReceipt(2, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 2);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(kDelayedAckTime);
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(3, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 3);
- CheckAckTimeout(ack_time);
- // Process enough packets to get into ack decimation behavior.
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
- EXPECT_FALSE(HasPendingAck());
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (uint64_t i = 1; i < 10; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
- }
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
- CheckAckTimeout(ack_time);
-}
-
-TEST_P(QuicReceivedPacketManagerTest,
SendDelayedAckDecimationUnlimitedAggregation) {
EXPECT_FALSE(HasPendingAck());
QuicConfig config;
@@ -619,7 +501,6 @@ TEST_P(QuicReceivedPacketManagerTest,
TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION);
QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_,
0.125);
@@ -652,190 +533,123 @@ TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) {
CheckAckTimeout(clock_.ApproximateNow());
}
-TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
+TEST_F(QuicReceivedPacketManagerTest,
+ UpdateMaxAckDelayAndAckFrequencyFromAckFrequencyFrame) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_,
- ACK_DECIMATION_WITH_REORDERING);
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+ QuicAckFrequencyFrame frame;
+ frame.max_ack_delay = QuicTime::Delta::FromMilliseconds(10);
+ frame.packet_tolerance = 5;
+ received_manager_.OnAckFrequencyFrame(frame);
+
+ for (int i = 1; i <= 50; ++i) {
RecordPacketReceipt(i, clock_.ApproximateNow());
MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
+ if (i % frame.packet_tolerance == 0) {
CheckAckTimeout(clock_.ApproximateNow());
} else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
-
- // Receive one packet out of order and then the rest in order.
- // The loop leaves a one packet gap between acks sent to simulate some loss.
- for (int j = 0; j < 3; ++j) {
- // Process packet 10 first and ensure the timeout is one eighth min_rtt.
- RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11),
- clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11),
- clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck,
- kFirstDecimatedPacket + i + (j * 11));
+ CheckAckTimeout(clock_.ApproximateNow() + frame.max_ack_delay);
}
- CheckAckTimeout(clock_.ApproximateNow());
}
}
-TEST_P(QuicReceivedPacketManagerTest,
- SendDelayedAckDecimationWithLargeReordering) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
+TEST_F(QuicReceivedPacketManagerTest,
+ DisableOutOfOrderAckByIgnoreOrderFromAckFrequencyFrame) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_,
- ACK_DECIMATION_WITH_REORDERING);
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
+ QuicAckFrequencyFrame frame;
+ frame.max_ack_delay = kDelayedAckTime;
+ frame.packet_tolerance = 2;
+ frame.ignore_order = true;
+ received_manager_.OnAckFrequencyFrame(frame);
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
+ RecordPacketReceipt(4, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 4);
+ CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+ RecordPacketReceipt(5, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 5);
+ // Immediate ack is sent as this is the 2nd packet of every two packets.
+ CheckAckTimeout(clock_.ApproximateNow());
- RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19);
- ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
- CheckAckTimeout(ack_time);
+ RecordPacketReceipt(3, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 3);
+ // Don't ack as ignore_order is set by AckFrequencyFrame.
+ CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- // The 10th received packet causes an ack to be sent.
- for (int i = 1; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
- }
+ RecordPacketReceipt(2, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 2);
+ // Immediate ack is sent as this is the 2nd packet of every two packets.
CheckAckTimeout(clock_.ApproximateNow());
- // The next packet received in order will cause an immediate ack, because it
- // fills a hole.
- RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
- CheckAckTimeout(clock_.ApproximateNow());
+ RecordPacketReceipt(1, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 1);
+ // Don't ack as ignore_order is set by AckFrequencyFrame.
+ CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
}
-TEST_P(QuicReceivedPacketManagerTest,
- SendDelayedAckDecimationWithReorderingEighthRtt) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
+TEST_F(QuicReceivedPacketManagerTest,
+ DisableMissingPaketsAckByIgnoreOrderFromAckFrequencyFrame) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_,
- ACK_DECIMATION_WITH_REORDERING);
- QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_,
- 0.125);
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kAFFE});
+ received_manager_.SetFromConfig(config, Perspective::IS_CLIENT);
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
+ QuicAckFrequencyFrame frame;
+ frame.max_ack_delay = kDelayedAckTime;
+ frame.packet_tolerance = 2;
+ frame.ignore_order = true;
+ received_manager_.OnAckFrequencyFrame(frame);
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
+ RecordPacketReceipt(1, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 1);
+ CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+ RecordPacketReceipt(2, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 2);
+ // Immediate ack is sent as this is the 2nd packet of every two packets.
+ CheckAckTimeout(clock_.ApproximateNow());
- // Process packet 10 first and ensure the timeout is one eighth min_rtt.
- RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9);
- CheckAckTimeout(ack_time);
+ RecordPacketReceipt(4, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 4);
+ // Don't ack even if packet 3 is newly missing as ignore_order is set by
+ // AckFrequencyFrame.
+ CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- // The 10th received packet causes an ack to be sent.
- for (int i = 1; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket);
- }
+ RecordPacketReceipt(5, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 5);
+ // Immediate ack is sent as this is the 2nd packet of every two packets.
CheckAckTimeout(clock_.ApproximateNow());
+
+ RecordPacketReceipt(7, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 7);
+ // Don't ack even if packet 6 is newly missing as ignore_order is set by
+ // AckFrequencyFrame.
+ CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
}
-TEST_P(QuicReceivedPacketManagerTest,
- SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
+TEST_F(QuicReceivedPacketManagerTest,
+ AckDecimationDisabledWhenAckFrequencyFrameIsReceived) {
EXPECT_FALSE(HasPendingAck());
- QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_,
- ACK_DECIMATION_WITH_REORDERING);
- QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_,
- 0.125);
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
+ QuicAckFrequencyFrame frame;
+ frame.max_ack_delay = kDelayedAckTime;
+ frame.packet_tolerance = 3;
+ frame.ignore_order = true;
+ received_manager_.OnAckFrequencyFrame(frame);
+
// Process all the packets in order so there aren't missing packets.
uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+ uint64_t FiftyPacketsAfterAckDecimation = kFirstDecimatedPacket + 50;
+ for (uint64_t i = 1; i < FiftyPacketsAfterAckDecimation; ++i) {
RecordPacketReceipt(i, clock_.ApproximateNow());
MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
+ if (i % 3 == 0) {
+ // Ack every 3 packets as decimation is disabled.
CheckAckTimeout(clock_.ApproximateNow());
} else {
+ // Ack at default delay as decimation is disabled.
CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
}
}
-
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
-
- RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 1; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
- }
- CheckAckTimeout(clock_.ApproximateNow());
-
- // The next packet received in order will cause an immediate ack, because it
- // fills a hole.
- RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
- CheckAckTimeout(clock_.ApproximateNow());
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc
index 4746eaecc52..4dc25828378 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc
@@ -105,6 +105,7 @@ QuicSentPacketManager::QuicSentPacketManager(
pto_rttvar_multiplier_(4),
num_tlp_timeout_ptos_(0),
handshake_packet_acked_(false),
+ zero_rtt_packet_acked_(false),
one_rtt_packet_acked_(false),
one_rtt_packet_sent_(false),
first_pto_srtt_multiplier_(0),
@@ -559,6 +560,11 @@ QuicTime QuicSentPacketManager::GetEarliestPacketSentTimeForPto(
bool QuicSentPacketManager::ShouldArmPtoForApplicationData() const {
DCHECK(supports_multiple_packet_number_spaces());
+ if (GetQuicReloadableFlag(quic_fix_arm_pto_for_application_data)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_arm_pto_for_application_data);
+ // Do not arm PTO for application data until handshake gets confirmed.
+ return handshake_finished_;
+ }
// Application data must be ignored before handshake completes (1-RTT key
// is available). Not arming PTO for application data to prioritize the
// completion of handshake. On the server side, handshake_finished_
@@ -640,6 +646,13 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number,
QuicTime ack_receive_time,
QuicTime::Delta ack_delay_time,
QuicTime receive_timestamp) {
+ if (info->has_ack_frequency) {
+ for (const auto& frame : info->retransmittable_frames) {
+ if (frame.type == ACK_FREQUENCY_FRAME) {
+ OnAckFrequencyFrameAcked(*frame.ack_frequency_frame);
+ }
+ }
+ }
// Try to aggregate acked stream frames if acked packet is not a
// retransmission.
if (info->transmission_type == NOT_RETRANSMISSION) {
@@ -688,36 +701,58 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number,
}
bool QuicSentPacketManager::OnPacketSent(
- SerializedPacket* serialized_packet,
+ SerializedPacket* mutable_packet,
QuicTime sent_time,
TransmissionType transmission_type,
- HasRetransmittableData has_retransmittable_data) {
- QuicPacketNumber packet_number = serialized_packet->packet_number;
+ HasRetransmittableData has_retransmittable_data,
+ bool measure_rtt) {
+ const SerializedPacket& packet = *mutable_packet;
+ QuicPacketNumber packet_number = packet.packet_number;
DCHECK_LE(FirstSendingPacketNumber(), packet_number);
DCHECK(!unacked_packets_.IsUnacked(packet_number));
- QUIC_BUG_IF(serialized_packet->encrypted_length == 0)
- << "Cannot send empty packets.";
+ QUIC_BUG_IF(packet.encrypted_length == 0) << "Cannot send empty packets.";
if (pending_timer_transmission_count_ > 0) {
--pending_timer_transmission_count_;
}
bool in_flight = has_retransmittable_data == HAS_RETRANSMITTABLE_DATA;
if (using_pacing_) {
- pacing_sender_.OnPacketSent(
- sent_time, unacked_packets_.bytes_in_flight(), packet_number,
- serialized_packet->encrypted_length, has_retransmittable_data);
+ pacing_sender_.OnPacketSent(sent_time, unacked_packets_.bytes_in_flight(),
+ packet_number, packet.encrypted_length,
+ has_retransmittable_data);
} else {
- send_algorithm_->OnPacketSent(
- sent_time, unacked_packets_.bytes_in_flight(), packet_number,
- serialized_packet->encrypted_length, has_retransmittable_data);
+ send_algorithm_->OnPacketSent(sent_time, unacked_packets_.bytes_in_flight(),
+ packet_number, packet.encrypted_length,
+ has_retransmittable_data);
}
- if (serialized_packet->encryption_level == ENCRYPTION_FORWARD_SECURE) {
+ if (packet.encryption_level == ENCRYPTION_FORWARD_SECURE) {
one_rtt_packet_sent_ = true;
}
- unacked_packets_.AddSentPacket(serialized_packet, transmission_type,
- sent_time, in_flight);
+ if (GetQuicReloadableFlag(quic_deallocate_message_right_after_sent)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_deallocate_message_right_after_sent);
+ // Deallocate message data in QuicMessageFrame immediately after packet
+ // sent.
+ if (packet.has_message) {
+ for (auto& frame : mutable_packet->retransmittable_frames) {
+ if (frame.type == MESSAGE_FRAME) {
+ frame.message_frame->message_data.clear();
+ frame.message_frame->message_length = 0;
+ }
+ }
+ }
+ }
+
+ if (packet.has_ack_frequency) {
+ for (const auto& frame : packet.retransmittable_frames) {
+ if (frame.type == ACK_FREQUENCY_FRAME) {
+ OnAckFrequencyFrameSent(*frame.ack_frequency_frame);
+ }
+ }
+ }
+ unacked_packets_.AddSentPacket(mutable_packet, transmission_type, sent_time,
+ in_flight, measure_rtt);
// Reset the retransmission timer anytime a pending packet is sent.
return in_flight;
}
@@ -767,6 +802,8 @@ QuicSentPacketManager::OnRetransmissionTimeout() {
pending_timer_transmission_count_ = max_probe_packets_per_pto_;
return PTO_MODE;
}
+ QUIC_BUG << "Unknown retransmission mode " << GetRetransmissionMode();
+ return GetRetransmissionMode();
}
void QuicSentPacketManager::RetransmitCryptoPackets() {
@@ -921,6 +958,10 @@ void QuicSentPacketManager::EnableIetfPtoAndLossDetection() {
max_probe_packets_per_pto_ = 1;
skip_packet_number_for_pto_ = true;
first_pto_srtt_multiplier_ = 1.5;
+ if (GetQuicReloadableFlag(quic_default_to_2_rttvar)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_default_to_2_rttvar);
+ pto_rttvar_multiplier_ = 2;
+ }
}
void QuicSentPacketManager::StartExponentialBackoffAfterNthPto(
@@ -942,6 +983,11 @@ void QuicSentPacketManager::RetransmitDataOfSpaceIfAny(
unacked_packets_.HasRetransmittableFrames(*it) &&
unacked_packets_.GetPacketNumberSpace(it->encryption_level) == space) {
DCHECK(it->in_flight);
+ if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count) &&
+ pending_timer_transmission_count_ == 0) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_pto_pending_timer_count);
+ pending_timer_transmission_count_ = 1;
+ }
MarkForRetransmission(packet_number, PTO_RETRANSMISSION);
return;
}
@@ -1250,10 +1296,8 @@ const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay(
QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) *
(1 << consecutive_pto_count_);
}
- if (GetQuicReloadableFlag(quic_use_half_rtt_as_first_pto) &&
- enable_half_rtt_tail_loss_probe_ && consecutive_pto_count_ == 0 &&
+ if (enable_half_rtt_tail_loss_probe_ && consecutive_pto_count_ == 0 &&
handshake_finished_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_use_half_rtt_as_first_pto);
return std::max(min_tlp_timeout_, rtt_stats_.smoothed_rtt() * 0.5);
}
const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_
@@ -1432,8 +1476,9 @@ AckResult QuicSentPacketManager::OnAckFrameEnd(
last_ack_frame_.packets.Add(acked_packet.packet_number);
if (info->encryption_level == ENCRYPTION_HANDSHAKE) {
handshake_packet_acked_ = true;
- }
- if (info->encryption_level == ENCRYPTION_FORWARD_SECURE) {
+ } else if (info->encryption_level == ENCRYPTION_ZERO_RTT) {
+ zero_rtt_packet_acked_ = true;
+ } else if (info->encryption_level == ENCRYPTION_FORWARD_SECURE) {
one_rtt_packet_acked_ = true;
}
largest_packet_peer_knows_is_acked_.UpdateMax(info->largest_acked);
@@ -1488,8 +1533,13 @@ NextReleaseTimeResult QuicSentPacketManager::GetNextReleaseTime() const {
void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) {
const QuicTime::Delta min_rtt =
QuicTime::Delta::FromMicroseconds(kMinInitialRoundTripTimeUs);
- const QuicTime::Delta max_rtt =
+ QuicTime::Delta max_rtt =
QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs);
+ if (GetQuicReloadableFlag(quic_cap_large_client_initial_rtt)) {
+ // TODO(fayang): change the value of kMaxInitialRoundTripTimeUs when
+ // deprecating quic_cap_large_client_initial_rtt.
+ max_rtt = QuicTime::Delta::FromSeconds(1);
+ }
rtt_stats_.set_initial_rtt(std::max(min_rtt, std::min(max_rtt, rtt)));
}
@@ -1507,10 +1557,6 @@ QuicPacketNumber QuicSentPacketManager::GetLargestAckedPacket(
QuicPacketNumber QuicSentPacketManager::GetLeastPacketAwaitedByPeer(
EncryptionLevel encryption_level) const {
- if (!fix_packet_number_length_) {
- return GetLeastUnacked();
- }
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_packet_number_length, 1, 2);
QuicPacketNumber largest_acked;
if (supports_multiple_packet_number_spaces()) {
largest_acked = GetLargestAckedPacket(encryption_level);
@@ -1591,5 +1637,37 @@ QuicTime::Delta QuicSentPacketManager::GetPtoDelay() const {
: GetRetransmissionDelay();
}
+void QuicSentPacketManager::OnAckFrequencyFrameSent(
+ const QuicAckFrequencyFrame& ack_frequency_frame) {
+ in_use_sent_ack_delays_.emplace_back(ack_frequency_frame.max_ack_delay,
+ ack_frequency_frame.sequence_number);
+ if (ack_frequency_frame.max_ack_delay > peer_max_ack_delay_) {
+ peer_max_ack_delay_ = ack_frequency_frame.max_ack_delay;
+ }
+}
+
+void QuicSentPacketManager::OnAckFrequencyFrameAcked(
+ const QuicAckFrequencyFrame& ack_frequency_frame) {
+ int stale_entry_count = 0;
+ for (auto it = in_use_sent_ack_delays_.cbegin();
+ it != in_use_sent_ack_delays_.cend(); ++it) {
+ if (it->second < ack_frequency_frame.sequence_number) {
+ ++stale_entry_count;
+ } else {
+ break;
+ }
+ }
+ if (stale_entry_count > 0) {
+ in_use_sent_ack_delays_.pop_front_n(stale_entry_count);
+ }
+ if (in_use_sent_ack_delays_.empty()) {
+ QUIC_BUG << "in_use_sent_ack_delays_ is empty.";
+ return;
+ }
+ peer_max_ack_delay_ = std::max_element(in_use_sent_ack_delays_.cbegin(),
+ in_use_sent_ack_delays_.cend())
+ ->first;
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
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 9e5bd969047..6e36da9f6b5 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
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_CORE_QUIC_SENT_PACKET_MANAGER_H_
#include <cstddef>
+#include <cstdint>
#include <map>
#include <memory>
#include <set>
@@ -18,6 +19,7 @@
#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
+#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_sustained_bandwidth_recorder.h"
#include "net/third_party/quiche/src/quic/core/quic_transmission_info.h"
@@ -186,12 +188,14 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
}
// Called when we have sent bytes to the peer. This informs the manager both
- // the number of bytes sent and if they were retransmitted. Returns true if
- // the sender should reset the retransmission timer.
- bool OnPacketSent(SerializedPacket* serialized_packet,
+ // the number of bytes sent and if they were retransmitted and if this packet
+ // is used for rtt measuring. Returns true if the sender should reset the
+ // retransmission timer.
+ bool OnPacketSent(SerializedPacket* mutable_packet,
QuicTime sent_time,
TransmissionType transmission_type,
- HasRetransmittableData has_retransmittable_data);
+ HasRetransmittableData has_retransmittable_data,
+ bool measure_rtt);
// Called when the retransmission timer expires and returns the retransmission
// mode.
@@ -432,11 +436,15 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
return skip_packet_number_for_pto_;
}
+ bool zero_rtt_packet_acked() const { return zero_rtt_packet_acked_; }
+
bool one_rtt_packet_acked() const { return one_rtt_packet_acked_; }
void OnUserAgentIdKnown() { loss_algorithm_->OnUserAgentIdKnown(); }
- bool fix_packet_number_length() const { return fix_packet_number_length_; }
+ bool give_sent_packet_to_debug_visitor_after_sent() const {
+ return give_sent_packet_to_debug_visitor_after_sent_;
+ }
private:
friend class test::QuicConnectionPeer;
@@ -550,6 +558,14 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// retransmission timer is not armed if there is no packets in flight.
bool PeerCompletedAddressValidation() const;
+ // Called when an AckFrequencyFrame is sent.
+ void OnAckFrequencyFrameSent(
+ const QuicAckFrequencyFrame& ack_frequency_frame);
+
+ // Called when an AckFrequencyFrame is acked.
+ void OnAckFrequencyFrameAcked(
+ const QuicAckFrequencyFrame& ack_frequency_frame);
+
// Newly serialized retransmittable packets are added to this map, which
// contains owning pointers to any contained frames. If a packet is
// retransmitted, this map will contain entries for both the old and the new
@@ -629,11 +645,17 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
QuicPacketNumber
largest_packets_peer_knows_is_acked_[NUM_PACKET_NUMBER_SPACES];
- // The maximum ACK delay time that the peer uses. Initialized to be the
+ // The maximum ACK delay time that the peer might uses. Initialized to be the
// same as local_max_ack_delay_, may be changed via transport parameter
- // negotiation.
+ // negotiation or subsequently by AckFrequencyFrame.
QuicTime::Delta peer_max_ack_delay_;
+ // 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>>
+ in_use_sent_ack_delays_;
+
// Latest received ack frame.
QuicAckFrame last_ack_frame_;
@@ -677,6 +699,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// True if any ENCRYPTION_HANDSHAKE packet gets acknowledged.
bool handshake_packet_acked_;
+ // True if any 0-RTT packet gets acknowledged.
+ bool zero_rtt_packet_acked_;
+
// True if any 1-RTT packet gets acknowledged.
bool one_rtt_packet_acked_;
@@ -695,8 +720,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// available.
float pto_multiplier_without_rtt_samples_;
- const bool fix_packet_number_length_ =
- GetQuicReloadableFlag(quic_fix_packet_number_length);
+ const bool give_sent_packet_to_debug_visitor_after_sent_ =
+ GetQuicReloadableFlag(quic_give_sent_packet_to_debug_visitor_after_sent);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
index 57abfab5fda..c186f65099b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
@@ -7,6 +7,8 @@
#include <memory>
#include <utility>
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -69,7 +71,7 @@ class QuicSentPacketManagerTest : public QuicTest {
QuicFrame(QuicStreamFrame(1, false, 0, quiche::QuicheStringPiece())));
packet.has_crypto_handshake = IS_HANDSHAKE;
manager_.OnPacketSent(&packet, clock_.Now(), HANDSHAKE_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
}
void RetransmitDataPacket(uint64_t packet_number,
@@ -81,8 +83,8 @@ class QuicSentPacketManagerTest : public QuicTest {
kDefaultLength, HAS_RETRANSMITTABLE_DATA));
SerializedPacket packet(CreatePacket(packet_number, true));
packet.encryption_level = level;
- manager_.OnPacketSent(&packet, clock_.Now(), type,
- HAS_RETRANSMITTABLE_DATA);
+ manager_.OnPacketSent(&packet, clock_.Now(), type, HAS_RETRANSMITTABLE_DATA,
+ true);
}
void RetransmitDataPacket(uint64_t packet_number, TransmissionType type) {
@@ -238,7 +240,7 @@ class QuicSentPacketManagerTest : public QuicTest {
kDefaultLength, HAS_RETRANSMITTABLE_DATA));
SerializedPacket packet(CreatePacket(new_packet_number, true));
manager_.OnPacketSent(&packet, clock_.Now(), transmission_type,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
}
SerializedPacket CreateDataPacket(uint64_t packet_number) {
@@ -276,7 +278,7 @@ class QuicSentPacketManagerTest : public QuicTest {
SerializedPacket packet(CreateDataPacket(packet_number));
packet.encryption_level = encryption_level;
manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
}
void SendPingPacket(uint64_t packet_number,
@@ -287,7 +289,7 @@ class QuicSentPacketManagerTest : public QuicTest {
SerializedPacket packet(CreatePingPacket(packet_number));
packet.encryption_level = encryption_level;
manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
}
void SendCryptoPacket(uint64_t packet_number) {
@@ -300,7 +302,7 @@ class QuicSentPacketManagerTest : public QuicTest {
QuicFrame(QuicStreamFrame(1, false, 0, quiche::QuicheStringPiece())));
packet.has_crypto_handshake = IS_HANDSHAKE;
manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(true));
}
@@ -319,7 +321,7 @@ class QuicSentPacketManagerTest : public QuicTest {
packet.largest_acked = QuicPacketNumber(largest_acked);
packet.encryption_level = level;
manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
- NO_RETRANSMITTABLE_DATA);
+ NO_RETRANSMITTABLE_DATA, true);
}
void EnablePto(QuicTag tag) {
@@ -333,6 +335,18 @@ class QuicSentPacketManagerTest : public QuicTest {
EXPECT_TRUE(manager_.pto_enabled());
}
+ int GetPtoRttvarMultiplier() {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return 2;
+ }
+ if (GetQuicReloadableFlag(quic_default_to_2_rttvar) &&
+ manager_.handshake_mode_disabled()) {
+ return 2;
+ }
+ return 4;
+ }
+
+ SimpleBufferAllocator allocator_;
QuicSentPacketManager manager_;
MockClock clock_;
QuicConnectionStats stats_;
@@ -2195,7 +2209,7 @@ TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
TEST_F(QuicSentPacketManagerTest, ResumeConnectionState) {
// The sent packet manager should use the RTT from CachedNetworkParameters if
// it is provided.
- const QuicTime::Delta kRtt = QuicTime::Delta::FromMilliseconds(1234);
+ const QuicTime::Delta kRtt = QuicTime::Delta::FromMilliseconds(123);
CachedNetworkParameters cached_network_params;
cached_network_params.set_min_rtt_ms(kRtt.ToMilliseconds());
@@ -2272,7 +2286,7 @@ TEST_F(QuicSentPacketManagerTest, PathMtuIncreased) {
SerializedPacket packet(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER,
nullptr, kDefaultLength + 100, false, false);
manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
// Ack the large packet and expect the path MTU to increase.
ExpectAck(1);
@@ -2640,10 +2654,8 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
QuicTime packet1_sent_time = clock_.Now();
EXPECT_EQ(clock_.Now() + expected_pto_delay,
@@ -2693,7 +2705,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
+ std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -2719,10 +2731,8 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) {
QuicTime::Delta::Zero(), QuicTime::Zero());
QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
// Verify PTO period is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
QuicTime deadline = clock_.Now() + expected_pto_delay;
if (GetQuicReloadableFlag(quic_default_on_pto)) {
@@ -2825,10 +2835,8 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set and ack delay is included.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(clock_.Now() + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -2875,7 +2883,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
+ std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -2909,7 +2917,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
+ std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
for (size_t i = 101; i < 110; i++) {
@@ -2949,10 +2957,8 @@ TEST_F(QuicSentPacketManagerTest, StartExponentialBackoffSince2ndPto) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3160,10 +3166,8 @@ TEST_F(QuicSentPacketManagerTest, Aggressive1Pto) {
// Verify PTO period gets set correctly.
QuicTime sent_time = clock_.Now();
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(sent_time + expected_pto_delay * 2,
manager_.GetRetransmissionTime());
@@ -3224,10 +3228,8 @@ TEST_F(QuicSentPacketManagerTest, Aggressive2Ptos) {
RetransmitDataPacket(5, type, ENCRYPTION_FORWARD_SECURE);
})));
manager_.MaybeSendProbePackets();
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
// Verify PTO period gets set correctly.
@@ -3264,10 +3266,8 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) {
// Send packet 1.
SendDataPacket(1, ENCRYPTION_INITIAL);
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::Zero();
EXPECT_EQ(clock_.Now() + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3327,18 +3327,32 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) {
// Send packet 7 in handshake.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ const QuicTime packet7_sent_time = clock_.Now();
SendDataPacket(7, ENCRYPTION_HANDSHAKE);
- // Verify PTO timeout is now based on packet 6.
- expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
- QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
- EXPECT_EQ(packet6_sent_time + expected_pto_delay * 2,
- manager_.GetRetransmissionTime());
+
+ if (GetQuicReloadableFlag(quic_fix_arm_pto_for_application_data)) {
+ expected_pto_delay =
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation();
+ // Verify PTO timeout is now based on packet 7.
+ EXPECT_EQ(packet7_sent_time + expected_pto_delay * 2,
+ manager_.GetRetransmissionTime());
+
+ } else {
+ expected_pto_delay =
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+ // Verify PTO timeout is now based on packet 6.
+ EXPECT_EQ(packet6_sent_time + expected_pto_delay * 2,
+ manager_.GetRetransmissionTime());
+ }
// Neuter handshake key.
manager_.SetHandshakeConfirmed();
// Forward progress has been made, verify PTO counter gets reset. PTO timeout
// is armed by left edge.
+ expected_pto_delay =
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet4_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
}
@@ -3359,10 +3373,8 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) {
SendDataPacket(1, ENCRYPTION_INITIAL);
const QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::Zero();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3397,7 +3409,7 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) {
// Discard handshake keys.
manager_.SetHandshakeConfirmed();
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
// Verify PTO timeout is now based on packet 3 as handshake is
// complete/confirmed.
@@ -3429,10 +3441,8 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
const QuicTime packet1_sent_time = clock_.Now();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
@@ -3472,7 +3482,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
+ std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -3505,10 +3515,8 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
const QuicTime packet1_sent_time = clock_.Now();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
@@ -3538,7 +3546,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
// Verify PTO period gets set to twice the expected value and based on
// packet3 (right edge).
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
QuicTime packet3_sent_time = clock_.Now();
EXPECT_EQ(packet3_sent_time + expected_pto_delay * 2,
@@ -3555,7 +3563,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
+ std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -3595,10 +3603,9 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set using standard deviation.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->GetStandardOrMeanDeviation() +
+ srtt +
+ GetPtoRttvarMultiplier() * rtt_stats->GetStandardOrMeanDeviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(clock_.Now() + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3632,10 +3639,8 @@ TEST_F(QuicSentPacketManagerTest,
SendDataPacket(1, ENCRYPTION_INITIAL);
const QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::Zero();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3672,7 +3677,7 @@ TEST_F(QuicSentPacketManagerTest,
// Verify PTO timeout is now based on packet 3 as handshake is
// complete/confirmed.
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet3_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3712,10 +3717,8 @@ TEST_F(QuicSentPacketManagerTest,
SendDataPacket(1, ENCRYPTION_INITIAL);
const QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::Zero();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3752,7 +3755,7 @@ TEST_F(QuicSentPacketManagerTest,
// Verify PTO timeout is now based on packet 3 as handshake is
// complete/confirmed.
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet3_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3982,11 +3985,9 @@ TEST_F(QuicSentPacketManagerTest, ClearLastInflightPacketsSentTime) {
manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
ENCRYPTION_INITIAL));
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
const QuicTime::Delta pto_delay =
rtt_stats->smoothed_rtt() +
- pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::Zero();
// Verify PTO is armed based on handshake data.
EXPECT_EQ(packet2_sent_time + pto_delay, manager_.GetRetransmissionTime());
@@ -4057,10 +4058,8 @@ TEST_F(QuicSentPacketManagerTest, MaybeRetransmitInitialData) {
QuicTime packet2_sent_time = clock_.Now();
SendDataPacket(3, ENCRYPTION_HANDSHAKE);
// Verify PTO is correctly set based on packet 1.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::Zero();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -4141,7 +4140,6 @@ TEST_F(QuicSentPacketManagerTest, ClientOnlyTLPR) {
}
TEST_F(QuicSentPacketManagerTest, PtoWithTlpr) {
- SetQuicReloadableFlag(quic_use_half_rtt_as_first_pto, true);
QuicConfig config;
QuicTagVector options;
@@ -4180,16 +4178,247 @@ TEST_F(QuicSentPacketManagerTest, PtoWithTlpr) {
manager_.MaybeSendProbePackets();
// Verify PTO period gets set correctly.
- int pto_rttvar_multiplier =
- GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
expected_pto_delay =
- srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+ srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
QuicTime sent_time = clock_.Now();
EXPECT_EQ(sent_time + expected_pto_delay * 2,
manager_.GetRetransmissionTime());
}
+TEST_F(QuicSentPacketManagerTest, SendPathChallengeAndGetAck) {
+ QuicPacketNumber packet_number(1);
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, BytesInFlight(), packet_number, _, _));
+ SerializedPacket packet(packet_number, PACKET_4BYTE_PACKET_NUMBER, nullptr,
+ kDefaultLength, false, false);
+ QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7};
+ packet.nonretransmittable_frames.push_back(
+ QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer)));
+ packet.encryption_level = ENCRYPTION_FORWARD_SECURE;
+ manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
+ NO_RETRANSMITTABLE_DATA, false);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(/*rtt_updated=*/false, _, _,
+ Pointwise(PacketNumberEq(), {1}), IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+
+ // Get ACK for the packet.
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE));
+}
+
+SerializedPacket MakePacketWithAckFrequencyFrame(
+ int packet_number,
+ int ack_frequency_sequence_number,
+ QuicTime::Delta max_ack_delay) {
+ auto* ack_frequency_frame = new QuicAckFrequencyFrame();
+ ack_frequency_frame->max_ack_delay = max_ack_delay;
+ ack_frequency_frame->sequence_number = ack_frequency_sequence_number;
+ SerializedPacket packet(QuicPacketNumber(packet_number),
+ PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ /*has_ack=*/false,
+ /*has_stop_waiting=*/false);
+ packet.retransmittable_frames.push_back(QuicFrame(ack_frequency_frame));
+ packet.has_ack_frequency = true;
+ packet.encryption_level = ENCRYPTION_FORWARD_SECURE;
+ return packet;
+}
+
+TEST_F(QuicSentPacketManagerTest,
+ PeerMaxAckDelayUpdatedFromAckFrequencyFrameOneAtATime) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+ .Times(AnyNumber());
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange())
+ .Times(AnyNumber());
+
+ auto initial_peer_max_ack_delay = manager_.peer_max_ack_delay();
+ auto one_ms = QuicTime::Delta::FromMilliseconds(1);
+ auto plus_1_ms_delay = initial_peer_max_ack_delay + one_ms;
+ auto minus_1_ms_delay = initial_peer_max_ack_delay - one_ms;
+
+ // Send and Ack frame1.
+ SerializedPacket packet1 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/1, /*ack_frequency_sequence_number=*/1,
+ plus_1_ms_delay);
+ // Higher on the fly max_ack_delay changes peer_max_ack_delay.
+ manager_.OnPacketSent(&packet1, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), plus_1_ms_delay);
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), plus_1_ms_delay);
+
+ // Send and Ack frame2.
+ SerializedPacket packet2 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/2, /*ack_frequency_sequence_number=*/2,
+ minus_1_ms_delay);
+ // Lower on the fly max_ack_delay does not change peer_max_ack_delay.
+ manager_.OnPacketSent(&packet2, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), plus_1_ms_delay);
+ manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), minus_1_ms_delay);
+}
+
+TEST_F(QuicSentPacketManagerTest,
+ PeerMaxAckDelayUpdatedFromInOrderAckFrequencyFrames) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+ .Times(AnyNumber());
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange())
+ .Times(AnyNumber());
+
+ auto initial_peer_max_ack_delay = manager_.peer_max_ack_delay();
+ auto one_ms = QuicTime::Delta::FromMilliseconds(1);
+ auto extra_1_ms = initial_peer_max_ack_delay + one_ms;
+ auto extra_2_ms = initial_peer_max_ack_delay + 2 * one_ms;
+ auto extra_3_ms = initial_peer_max_ack_delay + 3 * one_ms;
+ SerializedPacket packet1 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/1, /*ack_frequency_sequence_number=*/1, extra_1_ms);
+ SerializedPacket packet2 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/2, /*ack_frequency_sequence_number=*/2, extra_3_ms);
+ SerializedPacket packet3 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/3, /*ack_frequency_sequence_number=*/3, extra_2_ms);
+
+ // Send frame1, farme2, frame3.
+ manager_.OnPacketSent(&packet1, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_1_ms);
+ manager_.OnPacketSent(&packet2, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms);
+ manager_.OnPacketSent(&packet3, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms);
+
+ // Ack frame1, farme2, frame3.
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms);
+ manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms);
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms);
+}
+
+TEST_F(QuicSentPacketManagerTest,
+ PeerMaxAckDelayUpdatedFromOutOfOrderAckedAckFrequencyFrames) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+ .Times(AnyNumber());
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange())
+ .Times(AnyNumber());
+
+ auto initial_peer_max_ack_delay = manager_.peer_max_ack_delay();
+ auto one_ms = QuicTime::Delta::FromMilliseconds(1);
+ auto extra_1_ms = initial_peer_max_ack_delay + one_ms;
+ auto extra_2_ms = initial_peer_max_ack_delay + 2 * one_ms;
+ auto extra_3_ms = initial_peer_max_ack_delay + 3 * one_ms;
+ auto extra_4_ms = initial_peer_max_ack_delay + 4 * one_ms;
+ SerializedPacket packet1 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/1, /*ack_frequency_sequence_number=*/1, extra_4_ms);
+ SerializedPacket packet2 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/2, /*ack_frequency_sequence_number=*/2, extra_3_ms);
+ SerializedPacket packet3 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/3, /*ack_frequency_sequence_number=*/3, extra_2_ms);
+ SerializedPacket packet4 = MakePacketWithAckFrequencyFrame(
+ /*packet_number=*/4, /*ack_frequency_sequence_number=*/4, extra_1_ms);
+
+ // Send frame1, farme2, frame3, frame4.
+ manager_.OnPacketSent(&packet1, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ manager_.OnPacketSent(&packet2, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ manager_.OnPacketSent(&packet3, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ manager_.OnPacketSent(&packet4, clock_.Now(), NOT_RETRANSMISSION,
+ NO_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_4_ms);
+
+ // Ack frame3.
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms);
+ // Acking frame1 do not affect peer_max_ack_delay after frame3 is acked.
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms);
+ // Acking frame2 do not affect peer_max_ack_delay after frame3 is acked.
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms);
+ // Acking frame4 updates peer_max_ack_delay.
+ manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(5));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(manager_.peer_max_ack_delay(), extra_1_ms);
+}
+
+TEST_F(QuicSentPacketManagerTest, ClearDataInMessageFrameAfterPacketSent) {
+ SetQuicReloadableFlag(quic_deallocate_message_right_after_sent, true);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+
+ QuicMessageFrame* message_frame = nullptr;
+ {
+ QuicMemSlice slice(MakeUniqueBuffer(&allocator_, 1024), 1024);
+ message_frame =
+ new QuicMessageFrame(/*message_id=*/1, QuicMemSliceSpan(&slice));
+ EXPECT_FALSE(message_frame->message_data.empty());
+ EXPECT_EQ(message_frame->message_length, 1024);
+
+ SerializedPacket packet(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER,
+ /*encrypted_buffer=*/nullptr, kDefaultLength,
+ /*has_ack=*/false,
+ /*has_stop_waiting*/ false);
+ packet.encryption_level = ENCRYPTION_FORWARD_SECURE;
+ packet.retransmittable_frames.push_back(QuicFrame(message_frame));
+ packet.has_message = true;
+ manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true);
+ }
+
+ EXPECT_TRUE(message_frame->message_data.empty());
+ EXPECT_EQ(message_frame->message_length, 0);
+}
+
} // namespace
} // namespace test
} // namespace quic
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 0f43d2fa3fa..4737902ef2c 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
@@ -89,8 +89,8 @@ QuicSession::QuicSession(
perspective() == Perspective::IS_SERVER,
nullptr),
currently_writing_stream_id_(0),
- goaway_sent_(false),
- goaway_received_(false),
+ transport_goaway_sent_(false),
+ transport_goaway_received_(false),
control_frame_manager_(this),
last_message_id_(0),
datagram_queue_(this),
@@ -100,13 +100,7 @@ QuicSession::QuicSession(
is_configured_(false),
enable_round_robin_scheduling_(false),
was_zero_rtt_rejected_(false),
- liveness_testing_in_progress_(false),
- remove_streams_waiting_for_acks_(
- GetQuicReloadableFlag(quic_remove_streams_waiting_for_acks)),
- do_not_use_stream_map_(GetQuicReloadableFlag(quic_do_not_use_stream_map)),
- remove_zombie_streams_(
- GetQuicReloadableFlag(quic_remove_zombie_streams) &&
- do_not_use_stream_map_ && remove_streams_waiting_for_acks_) {
+ liveness_testing_in_progress_(false) {
closed_streams_clean_up_alarm_ =
QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
new ClosedStreamsCleanUpDelegate(this)));
@@ -126,6 +120,12 @@ void QuicSession::Initialize() {
connection_->SetSessionNotifier(this);
connection_->SetDataProducer(this);
connection_->SetFromConfig(config_);
+ if (perspective_ == Perspective::IS_CLIENT &&
+ config_.HasClientRequestedIndependentOption(kAFFE, perspective_) &&
+ version().HasIetfQuicFrames()) {
+ connection_->set_can_receive_ack_frequency_frame();
+ config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs);
+ }
if (perspective() == Perspective::IS_CLIENT && version().UsesTls() &&
!version().HasHandshakeDone()) {
config_.SetSupportHandshakeDone();
@@ -145,15 +145,7 @@ void QuicSession::Initialize() {
GetMutableCryptoStream()->id());
}
-QuicSession::~QuicSession() {
- if (!remove_zombie_streams_) {
- QUIC_LOG_IF(WARNING, !zombie_streams_.empty())
- << "Still have zombie streams";
- } else {
- QUIC_LOG_IF(WARNING, num_zombie_streams_ > 0)
- << "Still have zombie streams";
- }
-}
+QuicSession::~QuicSession() {}
void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
DCHECK(VersionUsesHttp3(transport_version()));
@@ -265,7 +257,7 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
return;
}
- stream->OnStopSending(frame.application_error_code);
+ stream->OnStopSending(frame.error_code);
}
void QuicSession::OnPacketDecrypted(EncryptionLevel level) {
@@ -348,7 +340,7 @@ void QuicSession::OnGoAway(const QuicGoAwayFrame& /*frame*/) {
QUIC_BUG_IF(version().UsesHttp3())
<< "gQUIC GOAWAY received on version " << version();
- goaway_received_ = true;
+ transport_goaway_received_ = true;
}
void QuicSession::OnMessageReceived(quiche::QuicheStringPiece message) {
@@ -391,66 +383,17 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source);
- if (!do_not_use_stream_map_) {
- // Copy all non static streams in a new map for the ease of deleting.
- std::vector<QuicStream*> non_static_streams;
- for (const auto& it : stream_map_) {
- if (!it.second->is_static()) {
- non_static_streams.push_back(it.second.get());
- }
- }
-
- for (QuicStream* stream : non_static_streams) {
- QuicStreamId id = stream->id();
- stream->OnConnectionClosed(frame.quic_error_code, source);
- QUIC_RELOADABLE_FLAG_COUNT(
- quic_do_not_close_stream_again_on_connection_close);
- if (stream_map_.find(id) != stream_map_.end()) {
- QUIC_BUG << ENDPOINT << "Stream " << id
- << " failed to close under OnConnectionClosed";
- if (!GetQuicReloadableFlag(
- quic_do_not_close_stream_again_on_connection_close)) {
- CloseStream(id);
- }
- }
- }
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_do_not_use_stream_map, 1, 2);
- PerformActionOnActiveStreams([this, frame, source](QuicStream* stream) {
- QuicStreamId id = stream->id();
- stream->OnConnectionClosed(frame.quic_error_code, source);
- QUIC_RELOADABLE_FLAG_COUNT(
- quic_do_not_close_stream_again_on_connection_close);
- auto it = stream_map_.find(id);
- if (it != stream_map_.end()) {
- if (!remove_zombie_streams_) {
- QUIC_BUG << ENDPOINT << "Stream " << id
- << " failed to close under OnConnectionClosed";
- } else {
- QUIC_BUG_IF(!it->second->IsZombie())
- << ENDPOINT << "Non-zombie stream " << id
- << " failed to close under OnConnectionClosed";
- }
- if (!GetQuicReloadableFlag(
- quic_do_not_close_stream_again_on_connection_close)) {
- CloseStream(id);
- }
- }
- return true;
- });
- }
-
- if (!remove_zombie_streams_) {
- // Cleanup zombie stream map on connection close.
- while (!zombie_streams_.empty()) {
- ZombieStreamMap::iterator it = zombie_streams_.begin();
- closed_streams_.push_back(std::move(it->second));
- zombie_streams_.erase(it);
+ PerformActionOnActiveStreams([this, frame, source](QuicStream* stream) {
+ QuicStreamId id = stream->id();
+ stream->OnConnectionClosed(frame.quic_error_code, source);
+ auto it = stream_map_.find(id);
+ if (it != stream_map_.end()) {
+ QUIC_BUG_IF(!it->second->IsZombie())
+ << ENDPOINT << "Non-zombie stream " << id
+ << " failed to close under OnConnectionClosed";
}
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 1, 4);
- DCHECK(zombie_streams_.empty());
- }
+ return true;
+ });
closed_streams_clean_up_alarm_->Cancel();
@@ -479,7 +422,14 @@ void QuicSession::OnPacketReceived(const QuicSocketAddress& /*self_address*/,
if (is_connectivity_probe && perspective() == Perspective::IS_SERVER) {
// Server only sends back a connectivity probe after received a
// connectivity probe from a new peer address.
- connection_->SendConnectivityProbingResponsePacket(peer_address);
+ if (connection_->send_path_response()) {
+ // SendConnectivityProbingResponsePacket() will be deprecated.
+ // SendConnectivityProbingPacket() will be used to send both probing
+ // request and response as both of them are padded PING.
+ connection_->SendConnectivityProbingPacket(nullptr, peer_address);
+ } else {
+ connection_->SendConnectivityProbingResponsePacket(peer_address);
+ }
}
}
@@ -704,6 +654,34 @@ bool QuicSession::WillingAndAbleToWrite() const {
write_blocked_streams_.HasWriteBlockedDataStreams();
}
+std::string QuicSession::GetStreamsInfoForLogging() const {
+ std::string info = quiche::QuicheStrCat(
+ "num_active_streams: ", GetNumActiveStreams(),
+ ", num_pending_streams: ", pending_streams_size(),
+ ", num_outgoing_draining_streams: ", num_outgoing_draining_streams(),
+ " ");
+ // Log info for up to 5 streams.
+ size_t i = 5;
+ for (const auto& it : stream_map_) {
+ if (it.second->is_static()) {
+ continue;
+ }
+ // Calculate the stream creation delay.
+ const QuicTime::Delta delay =
+ connection_->clock()->ApproximateNow() - it.second->creation_time();
+ info = quiche::QuicheStrCat(
+ info, "{", it.second->id(), ":", delay.ToDebuggingValue(), ";",
+ it.second->stream_bytes_written(), ",", it.second->fin_sent(), ",",
+ it.second->HasBufferedData(), ",", it.second->fin_buffered(), ";",
+ it.second->stream_bytes_read(), ",", it.second->fin_received(), "}");
+ --i;
+ if (i == 0) {
+ break;
+ }
+ }
+ return info;
+}
+
bool QuicSession::HasPendingHandshake() const {
if (QuicVersionUsesCryptoFrames(transport_version())) {
return GetCryptoStream()->HasPendingCryptoRetransmission() ||
@@ -734,8 +712,15 @@ QuicConsumedData QuicSession::WritevData(
!QuicUtils::IsCryptoStreamId(transport_version(), id)) {
// Do not let streams write without encryption. The calling stream will end
// up write blocked until OnCanWrite is next called.
- QUIC_BUG << ENDPOINT << "Try to send data of stream " << id
- << " before encryption is established.";
+ if (was_zero_rtt_rejected_ && !OneRttKeysAvailable()) {
+ DCHECK(version().UsesTls() && perspective() == Perspective::IS_CLIENT);
+ QUIC_BUG_IF(type == NOT_RETRANSMISSION)
+ << ENDPOINT << "Try to send new data on stream " << id
+ << "before 1-RTT keys are available while 0-RTT is rejected.";
+ } else {
+ QUIC_BUG << ENDPOINT << "Try to send data of stream " << id
+ << " before encryption is established.";
+ }
return QuicConsumedData(0, false);
}
@@ -765,6 +750,17 @@ size_t QuicSession::SendCryptoData(EncryptionLevel level,
QuicStreamOffset offset,
TransmissionType type) {
DCHECK(QuicVersionUsesCryptoFrames(transport_version()));
+ if (connection()->check_keys_before_writing() &&
+ !connection()->framer().HasEncrypterOfEncryptionLevel(level)) {
+ const std::string error_details = quiche::QuicheStrCat(
+ "Try to send crypto data with missing keys of encryption level: ",
+ EncryptionLevelToString(level));
+ QUIC_BUG << ENDPOINT << error_details;
+ connection()->CloseConnection(
+ QUIC_MISSING_WRITE_KEYS, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return 0;
+ }
SetTransmissionType(type);
const auto current_level = connection()->encryption_level();
connection_->SetDefaultEncryptionLevel(level);
@@ -847,10 +843,10 @@ void QuicSession::SendGoAway(QuicErrorCode error_code,
const std::string& reason) {
// GOAWAY frame is not supported in v99.
DCHECK(!VersionHasIetfQuicFrames(transport_version()));
- if (goaway_sent_) {
+ if (transport_goaway_sent_) {
return;
}
- goaway_sent_ = true;
+ transport_goaway_sent_ = true;
control_frame_manager_.WriteOrBufferGoAway(
error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
}
@@ -880,31 +876,6 @@ void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
}
-void QuicSession::CloseStream(QuicStreamId stream_id) {
- QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
-
- StreamMap::iterator it = stream_map_.find(stream_id);
- if (it == stream_map_.end()) {
- // When CloseStream has been called recursively (via
- // QuicStream::OnClose), the stream will already have been deleted
- // from stream_map_, so return immediately.
- QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
- return;
- }
- QuicStream* stream = it->second.get();
- if (stream->is_static()) {
- QUIC_DVLOG(1) << ENDPOINT
- << "Try to close a static stream, id: " << stream_id
- << " Closing connection";
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Try to close a static stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- stream->CloseReadSide();
- stream->CloseWriteSide();
-}
-
void QuicSession::InsertLocallyClosedStreamsHighestOffset(
const QuicStreamId id,
QuicStreamOffset offset) {
@@ -923,26 +894,11 @@ void QuicSession::OnStreamClosed(QuicStreamId stream_id) {
const bool stream_waiting_for_acks = stream->IsWaitingForAcks();
if (stream_waiting_for_acks) {
- if (remove_zombie_streams_) {
- // The stream needs to be kept alive because it's waiting for acks.
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 2, 4);
- ++num_zombie_streams_;
- } else {
- zombie_streams_[stream_id] = std::move(it->second);
- }
+ // The stream needs to be kept alive because it's waiting for acks.
+ ++num_zombie_streams_;
} else {
- // Clean up the stream since it is no longer waiting for acks.
- if (remove_streams_waiting_for_acks_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 1, 4);
- } else {
- streams_waiting_for_acks_.erase(stream_id);
- }
closed_streams_.push_back(std::move(it->second));
- if (remove_zombie_streams_) {
- // When zombie_streams_ is removed, stream is only erased from stream map
- // if it's not zombie.
- stream_map_.erase(it);
- }
+ stream_map_.erase(it);
// Do not retransmit data of a closed stream.
streams_with_pending_retransmission_.erase(stream_id);
if (!closed_streams_clean_up_alarm_->IsSet()) {
@@ -960,18 +916,12 @@ void QuicSession::OnStreamClosed(QuicStreamId stream_id) {
DCHECK(!stream->was_draining());
InsertLocallyClosedStreamsHighestOffset(
stream_id, stream->highest_received_byte_offset());
- if (!remove_zombie_streams_) {
- stream_map_.erase(it);
- }
return;
}
const bool stream_was_draining = stream->was_draining();
QUIC_DVLOG_IF(1, stream_was_draining)
<< ENDPOINT << "Stream " << stream_id << " was draining";
- if (!remove_zombie_streams_) {
- stream_map_.erase(it);
- }
if (stream_was_draining) {
QUIC_BUG_IF(num_draining_streams_ == 0);
--num_draining_streams_;
@@ -1580,7 +1530,7 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) {
if (perspective() == Perspective::IS_CLIENT) {
// Retransmit old 0-RTT data (if any) with the new 0-RTT keys, since
// they can't be decrypted by the server.
- connection_->MarkZeroRttPacketsForRetransmission();
+ connection_->MarkZeroRttPacketsForRetransmission(0);
// Given any streams blocked by encryption a chance to write.
OnCanWrite();
}
@@ -1646,17 +1596,14 @@ void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) {
}
void QuicSession::NeuterHandshakeData() {
- if (GetQuicReloadableFlag(quic_fix_neuter_handshake_data)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_neuter_handshake_data);
- GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel(
- ENCRYPTION_HANDSHAKE);
- }
+ GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel(
+ ENCRYPTION_HANDSHAKE);
connection()->OnHandshakeComplete();
}
-void QuicSession::OnZeroRttRejected() {
+void QuicSession::OnZeroRttRejected(int reason) {
was_zero_rtt_rejected_ = true;
- connection_->MarkZeroRttPacketsForRetransmission();
+ connection_->MarkZeroRttPacketsForRetransmission(reason);
if (connection_->encryption_level() == ENCRYPTION_FORWARD_SECURE) {
QUIC_BUG << "1-RTT keys already available when 0-RTT is rejected.";
connection_->CloseConnection(
@@ -1818,11 +1765,7 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
StreamMap::iterator it = stream_map_.find(stream_id);
if (it != stream_map_.end()) {
- if (remove_zombie_streams_ && it->second->IsZombie()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 3, 4);
- return nullptr;
- }
- return it->second.get();
+ return it->second->IsZombie() ? nullptr : it->second.get();
}
if (IsClosedStream(stream_id)) {
@@ -1834,10 +1777,10 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
return nullptr;
}
- // TODO(fkastenholz): If we are creating a new stream and we have
- // sent a goaway, we should ignore the stream creation. Need to
- // add code to A) test if goaway was sent ("if (goaway_sent_)") and
- // B) reject stream creation ("return nullptr")
+ // TODO(fkastenholz): If we are creating a new stream and we have sent a
+ // goaway, we should ignore the stream creation. Need to add code to A) test
+ // if goaway was sent ("if (transport_goaway_sent_)") and B) reject stream
+ // creation ("return nullptr")
if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
return nullptr;
@@ -1968,7 +1911,7 @@ bool QuicSession::IsOpenStream(QuicStreamId id) {
DCHECK_NE(QuicUtils::GetInvalidStreamId(transport_version()), id);
const StreamMap::iterator it = stream_map_.find(id);
if (it != stream_map_.end()) {
- return remove_zombie_streams_ ? !it->second->IsZombie() : true;
+ return !it->second->IsZombie();
}
if (QuicContainsKey(pending_stream_map_, id) ||
QuicUtils::IsCryptoStreamId(transport_version(), id)) {
@@ -1987,17 +1930,6 @@ bool QuicSession::IsStaticStream(QuicStreamId id) const {
}
size_t QuicSession::GetNumActiveStreams() const {
- if (!VersionHasIetfQuicFrames(transport_version()) &&
- !GetQuicReloadableFlag(quic_get_stream_information_from_stream_map)) {
- // Exclude locally_closed_streams when determine whether to keep connection
- // alive.
- return stream_id_manager_.num_open_incoming_streams() +
- stream_id_manager_.num_open_outgoing_streams() -
- locally_closed_streams_highest_offset_.size();
- }
- if (GetQuicReloadableFlag(quic_get_stream_information_from_stream_map)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_get_stream_information_from_stream_map);
- }
DCHECK_GE(static_cast<QuicStreamCount>(stream_map_.size()),
num_static_streams_ + num_draining_streams_ + num_zombie_streams_);
return stream_map_.size() - num_draining_streams_ - num_static_streams_ -
@@ -2071,30 +2003,13 @@ bool QuicSession::IsIncomingStream(QuicStreamId id) const {
}
void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
- if (remove_streams_waiting_for_acks_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 2, 4);
- } else {
- streams_waiting_for_acks_.erase(id);
- }
-
- if (!remove_zombie_streams_) {
- auto it = zombie_streams_.find(id);
- if (it == zombie_streams_.end()) {
- return;
- }
-
- closed_streams_.push_back(std::move(it->second));
- zombie_streams_.erase(it);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 4, 4);
- auto it = stream_map_.find(id);
- if (it == stream_map_.end()) {
- return;
- }
- --num_zombie_streams_;
- closed_streams_.push_back(std::move(it->second));
- stream_map_.erase(it);
+ auto it = stream_map_.find(id);
+ if (it == stream_map_.end()) {
+ return;
}
+ --num_zombie_streams_;
+ closed_streams_.push_back(std::move(it->second));
+ stream_map_.erase(it);
if (!closed_streams_clean_up_alarm_->IsSet()) {
closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
@@ -2103,43 +2018,12 @@ void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
streams_with_pending_retransmission_.erase(id);
}
-void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) {
- if (remove_streams_waiting_for_acks_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 3, 4);
- return;
- }
- // Exclude crypto stream's status since it is counted in HasUnackedCryptoData.
- if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) {
- return;
- }
-
- streams_waiting_for_acks_.insert(id);
-
- // The number of the streams waiting for acks should not be larger than the
- // number of streams.
- DCHECK(!remove_zombie_streams_ || zombie_streams_.empty());
- if (static_cast<size_t>(stream_map_.size() + zombie_streams_.size()) <
- streams_waiting_for_acks_.size()) {
- QUIC_BUG << "More streams are waiting for acks than the number of streams. "
- << "Sizes: streams: " << stream_map_.size()
- << ", zombie streams: " << zombie_streams_.size()
- << ", vs streams waiting for acks: "
- << streams_waiting_for_acks_.size();
- }
-}
-
QuicStream* QuicSession::GetStream(QuicStreamId id) const {
auto active_stream = stream_map_.find(id);
if (active_stream != stream_map_.end()) {
return active_stream->second.get();
}
- DCHECK(!remove_zombie_streams_ || zombie_streams_.empty());
- auto zombie_stream = zombie_streams_.find(id);
- if (zombie_stream != zombie_streams_.end()) {
- return zombie_stream->second.get();
- }
-
if (QuicUtils::IsCryptoStreamId(transport_version(), id)) {
return const_cast<QuicCryptoStream*>(GetCryptoStream());
}
@@ -2280,14 +2164,6 @@ bool QuicSession::HasUnackedCryptoData() const {
}
bool QuicSession::HasUnackedStreamData() const {
- if (!remove_streams_waiting_for_acks_) {
- return !streams_waiting_for_acks_.empty();
- }
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 4, 4);
- DCHECK(!remove_zombie_streams_ || zombie_streams_.empty());
- if (!zombie_streams().empty()) {
- return true;
- }
for (const auto& it : stream_map_) {
if (it.second->IsWaitingForAcks()) {
return true;
@@ -2457,7 +2333,8 @@ QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
return connection_->GetGuaranteedLargestMessagePayload();
}
-void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
+void QuicSession::SendStopSending(QuicRstStreamErrorCode code,
+ QuicStreamId stream_id) {
control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
}
@@ -2534,8 +2411,7 @@ void QuicSession::PerformActionOnActiveStreams(
std::function<bool(QuicStream*)> action) {
std::vector<QuicStream*> active_streams;
for (const auto& it : stream_map_) {
- if (!it.second->is_static() &&
- (!remove_zombie_streams_ || !it.second->IsZombie())) {
+ if (!it.second->is_static() && !it.second->IsZombie()) {
active_streams.push_back(it.second.get());
}
}
@@ -2550,8 +2426,7 @@ void QuicSession::PerformActionOnActiveStreams(
void QuicSession::PerformActionOnActiveStreams(
std::function<bool(QuicStream*)> action) const {
for (const auto& it : stream_map_) {
- if (!it.second->is_static() &&
- (!remove_zombie_streams_ || !it.second->IsZombie()) &&
+ if (!it.second->is_static() && !it.second->IsZombie() &&
!action(it.second.get())) {
return;
}
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 e81375d231f..f5e01f85157 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
@@ -123,6 +123,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
void OnAckNeedsRetransmittableFrame() override;
void SendPing() override;
bool WillingAndAbleToWrite() const override;
+ std::string GetStreamsInfoForLogging() const override;
void OnPathDegrading() override;
void OnForwardProgressMadeAfterPathDegrading() override;
bool AllowSelfAddressChange() const override;
@@ -231,13 +232,8 @@ class QUIC_EXPORT_PRIVATE QuicSession
virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset);
// Create and transmit a STOP_SENDING frame
- virtual void SendStopSending(uint16_t code, QuicStreamId stream_id);
-
- // Close stream |stream_id|. Whether sending RST_STREAM (and STOP_SENDING)
- // depends on the sending and receiving states.
- // TODO(b/136274541): Deprecate CloseStream, instead always use ResetStream to
- // close a stream from session.
- virtual void CloseStream(QuicStreamId stream_id);
+ virtual void SendStopSending(QuicRstStreamErrorCode code,
+ QuicStreamId stream_id);
// Called by stream |stream_id| when it gets closed.
virtual void OnStreamClosed(QuicStreamId stream_id);
@@ -266,7 +262,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
void DiscardOldEncryptionKey(EncryptionLevel level) override;
void NeuterUnencryptedData() override;
void NeuterHandshakeData() override;
- void OnZeroRttRejected() override;
+ void OnZeroRttRejected(int reason) override;
bool FillTransportParameters(TransportParameters* params) override;
QuicErrorCode ProcessTransportParameters(const TransportParameters& params,
bool is_resumption,
@@ -350,10 +346,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// TODO(b/136274541): rename to CloseZombieStreams.
void OnStreamDoneWaitingForAcks(QuicStreamId id);
- // TODO(b/136274541): Remove this once quic_remove_streams_waiting_for_acks is
- // deprecated. Called when stream |id| is newly waiting for acks.
- void OnStreamWaitingForAcks(QuicStreamId id);
-
// Returns true if there is pending handshake data in the crypto stream.
// TODO(ianswett): Make this private or remove.
bool HasPendingHandshake() const;
@@ -372,9 +364,9 @@ class QUIC_EXPORT_PRIVATE QuicSession
// connection ID lengths do not change.
QuicPacketLength GetGuaranteedLargestMessagePayload() const;
- bool goaway_sent() const { return goaway_sent_; }
+ bool transport_goaway_sent() const { return transport_goaway_sent_; }
- bool goaway_received() const { return goaway_received_; }
+ bool transport_goaway_received() const { return transport_goaway_received_; }
// Returns the Google QUIC error code
QuicErrorCode error() const { return on_closed_frame_.quic_error_code; }
@@ -499,8 +491,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
return liveness_testing_in_progress_;
}
- bool remove_zombie_streams() const { return remove_zombie_streams_; }
-
protected:
using StreamMap = QuicHashMap<QuicStreamId, std::unique_ptr<QuicStream>>;
@@ -574,8 +564,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
ClosedStreams* closed_streams() { return &closed_streams_; }
- const ZombieStreamMap& zombie_streams() const { return zombie_streams_; }
-
void set_largest_peer_created_stream_id(
QuicStreamId largest_peer_created_stream_id);
@@ -626,8 +614,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool was_zero_rtt_rejected() const { return was_zero_rtt_rejected_; }
- bool do_not_use_stream_map() const { return do_not_use_stream_map_; }
-
size_t num_outgoing_draining_streams() const {
return num_outgoing_draining_streams_;
}
@@ -759,9 +745,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
QuicWriteBlockedList write_blocked_streams_;
ClosedStreams closed_streams_;
- // Streams which are closed, but need to be kept alive. Currently, the only
- // reason is the stream's sent data (including FIN) does not get fully acked.
- ZombieStreamMap zombie_streams_;
QuicConfig config_;
@@ -772,11 +755,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// which are waiting for the first byte of payload to arrive.
PendingStreamMap pending_stream_map_;
- // TODO(b/136274541): Remove this once quic_remove_streams_waiting_for_acks is
- // deprecated. Set of stream ids that are waiting for acks excluding crypto
- // stream id.
- QuicHashSet<QuicStreamId> streams_waiting_for_acks_;
-
// TODO(fayang): Consider moving LegacyQuicStreamIdManager into
// UberQuicStreamIdManager.
// Manages stream IDs for Google QUIC.
@@ -810,11 +788,15 @@ class QUIC_EXPORT_PRIVATE QuicSession
// call stack of OnCanWrite.
QuicStreamId currently_writing_stream_id_;
- // Whether a GoAway has been sent.
- bool goaway_sent_;
+ // Whether a transport layer GOAWAY frame has been sent.
+ // Such a frame only exists in Google QUIC, therefore |transport_goaway_sent_|
+ // is always false when using IETF QUIC.
+ bool transport_goaway_sent_;
- // Whether a GoAway has been received.
- bool goaway_received_;
+ // Whether a transport layer GOAWAY frame has been received.
+ // Such a frame only exists in Google QUIC, therefore
+ // |transport_goaway_received_| is always false when using IETF QUIC.
+ bool transport_goaway_received_;
QuicControlFrameManager control_frame_manager_;
@@ -855,15 +837,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
// This indicates a liveness testing is in progress, and push back the
// creation of new outgoing bidirectional streams.
bool liveness_testing_in_progress_;
-
- // Latched value of flag quic_remove_streams_waiting_for_acks.
- const bool remove_streams_waiting_for_acks_;
-
- // Latched value of flag quic_do_not_use_stream_map.
- const bool do_not_use_stream_map_;
-
- // Latched value of flag quic_remove_zombie_streams.
- const bool remove_zombie_streams_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
index 67cb2be7792..e5b6cff3a03 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
@@ -115,6 +115,9 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
}
// QuicCryptoStream implementation
+ ssl_early_data_reason_t EarlyDataReason() const override {
+ return ssl_early_data_unknown;
+ }
bool encryption_established() const override {
return encryption_established_;
}
@@ -165,10 +168,9 @@ class TestStream : public QuicStream {
StreamType type)
: QuicStream(id, session, is_static, type) {}
- TestStream(PendingStream* pending, StreamType type)
- : QuicStream(pending, type, /*is_static=*/false) {}
+ TestStream(PendingStream* pending, QuicSession* session, StreamType type)
+ : QuicStream(pending, session, type, /*is_static=*/false) {}
- using QuicStream::CloseReadSide;
using QuicStream::CloseWriteSide;
using QuicStream::WriteMemSlices;
@@ -258,8 +260,9 @@ class TestSession : public QuicSession {
TestStream* CreateIncomingStream(PendingStream* pending) override {
QuicStreamId id = pending->id();
TestStream* stream = new TestStream(
- pending, DetermineStreamType(id, connection()->version(), perspective(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ pending, this,
+ DetermineStreamType(id, connection()->version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
++num_incoming_streams_created_;
return stream;
@@ -364,7 +367,6 @@ class TestSession : public QuicSession {
using QuicSession::GetNextOutgoingBidirectionalStreamId;
using QuicSession::GetNextOutgoingUnidirectionalStreamId;
using QuicSession::stream_map;
- using QuicSession::zombie_streams;
private:
StrictMock<TestCryptoStream> crypto_stream_;
@@ -1425,7 +1427,7 @@ TEST_P(QuicSessionTestServer, SendGoAway) {
.WillOnce(
Invoke(connection_, &MockQuicConnection::ReallySendControlFrame));
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
- EXPECT_TRUE(session_.goaway_sent());
+ EXPECT_TRUE(session_.transport_goaway_sent());
const QuicStreamId kTestStreamId = 5u;
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
@@ -1443,7 +1445,7 @@ TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&ClearControlFrame));
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
- EXPECT_TRUE(session_.goaway_sent());
+ EXPECT_TRUE(session_.transport_goaway_sent());
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
}
@@ -1460,6 +1462,10 @@ TEST_P(QuicSessionTestServer, InvalidGoAway) {
// Test that server session will send a connectivity probe in response to a
// connectivity probe on the same path.
TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) {
+ if (connection_->send_path_response() &&
+ VersionHasIetfQuicFrames(transport_version())) {
+ return;
+ }
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
QuicSocketAddress old_peer_address =
QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
@@ -1472,10 +1478,17 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) {
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, WritePacket(_, _, _, new_peer_address, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(_))
- .WillOnce(Invoke(
- connection_,
- &MockQuicConnection::ReallySendConnectivityProbingResponsePacket));
+ if (connection_->send_path_response()) {
+ EXPECT_CALL(*connection_, SendConnectivityProbingPacket(_, _))
+ .WillOnce(
+ Invoke(connection_,
+ &MockQuicConnection::ReallySendConnectivityProbingPacket));
+ } else {
+ EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(_))
+ .WillOnce(Invoke(
+ connection_,
+ &MockQuicConnection::ReallySendConnectivityProbingResponsePacket));
+ }
if (VersionHasIetfQuicFrames(transport_version())) {
// Need to explicitly do this to emulate the reception of a PathChallenge,
// which stores its payload for use in generating the response.
@@ -1491,7 +1504,8 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) {
// packet, the response has both of them AND we do not do migration. This for
// IETF QUIC only.
TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbes) {
- if (!VersionHasIetfQuicFrames(transport_version())) {
+ if (connection_->send_path_response() ||
+ !VersionHasIetfQuicFrames(transport_version())) {
return;
}
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -2207,6 +2221,17 @@ TEST_P(QuicSessionTestClient, IncomingStreamWithClientInitiatedStreamId) {
session_.OnStreamFrame(frame);
}
+TEST_P(QuicSessionTestClient, MinAckDelaySetOnTheClientQuicConfig) {
+ if (!session_.version().HasIetfQuicFrames()) {
+ return;
+ }
+ session_.config()->SetClientConnectionOptions({kAFFE});
+ session_.Initialize();
+ ASSERT_EQ(session_.config()->GetMinAckDelayToSendMs(),
+ kDefaultMinAckDelayTimeMs);
+ ASSERT_TRUE(session_.connection()->can_receive_ack_frequency_frame());
+}
+
TEST_P(QuicSessionTestClient, FailedToCreateStreamIfTooCloseToIdleTimeout) {
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_TRUE(session_.CanOpenNextOutgoingBidirectionalStream());
@@ -2235,11 +2260,9 @@ TEST_P(QuicSessionTestServer, ZombieStreams) {
EXPECT_TRUE(stream2->IsWaitingForAcks());
CloseStream(stream2->id());
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
ASSERT_EQ(1u, session_.closed_streams()->size());
EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id());
session_.OnStreamDoneWaitingForAcks(stream2->id());
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
EXPECT_EQ(1u, session_.closed_streams()->size());
EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id());
}
@@ -2294,7 +2317,6 @@ TEST_P(QuicSessionTestServer, TestZombieStreams) {
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
session_.OnStopSendingFrame(frame);
}
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
ASSERT_EQ(1u, session_.closed_streams()->size());
EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id());
@@ -2316,7 +2338,6 @@ TEST_P(QuicSessionTestServer, TestZombieStreams) {
// QUIC it sends both a RST_STREAM and a STOP_SENDING (each of which
// closes in only one direction).
stream4->Reset(QUIC_STREAM_CANCELLED);
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id()));
EXPECT_EQ(2u, session_.closed_streams()->size());
}
@@ -2560,17 +2581,13 @@ TEST_P(QuicSessionTestServer, LocallyResetZombieStreams) {
session_.set_writev_consumes_all_data(true);
TestStream* stream2 = session_.CreateOutgoingBidirectionalStream();
std::string body(100, '.');
- stream2->CloseReadSide();
+ QuicStreamPeer::CloseReadSide(stream2);
stream2->WriteOrBufferData(body, true, nullptr);
EXPECT_TRUE(stream2->IsWaitingForAcks());
// Verify stream2 is a zombie streams.
- if (!session_.remove_zombie_streams()) {
- EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
- } else {
- ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream2->id()));
- auto* stream = session_.stream_map().find(stream2->id())->second.get();
- EXPECT_TRUE(stream->IsZombie());
- }
+ ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream2->id()));
+ auto* stream = session_.stream_map().find(stream2->id())->second.get();
+ EXPECT_TRUE(stream->IsZombie());
QuicStreamFrame frame(stream2->id(), true, 0, 100);
EXPECT_CALL(*stream2, HasPendingRetransmission())
@@ -2584,7 +2601,6 @@ TEST_P(QuicSessionTestServer, LocallyResetZombieStreams) {
stream2->Reset(QUIC_STREAM_CANCELLED);
// Verify stream 2 gets closed.
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
EXPECT_TRUE(session_.IsClosedStream(stream2->id()));
EXPECT_CALL(*stream2, OnCanWrite()).Times(0);
session_.OnCanWrite();
@@ -2599,7 +2615,6 @@ TEST_P(QuicSessionTestServer, CleanUpClosedStreamsAlarm) {
EXPECT_FALSE(stream2->IsWaitingForAcks());
CloseStream(stream2->id());
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
EXPECT_EQ(1u, session_.closed_streams()->size());
EXPECT_TRUE(
QuicSessionPeer::GetCleanUpClosedStreamsAlarm(&session_)->IsSet());
@@ -2616,15 +2631,10 @@ TEST_P(QuicSessionTestServer, WriteUnidirectionalStream) {
session_.ActivateStream(QuicWrapUnique(stream4));
std::string body(100, '.');
stream4->WriteOrBufferData(body, false, nullptr);
- EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id()));
stream4->WriteOrBufferData(body, true, nullptr);
- if (!session_.remove_zombie_streams()) {
- EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), stream4->id()));
- } else {
- ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream4->id()));
- auto* stream = session_.stream_map().find(stream4->id())->second.get();
- EXPECT_TRUE(stream->IsZombie());
- }
+ ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream4->id()));
+ auto* stream = session_.stream_map().find(stream4->id())->second.get();
+ EXPECT_TRUE(stream->IsZombie());
}
TEST_P(QuicSessionTestServer, ReceivedDataOnWriteUnidirectionalStream) {
@@ -2809,7 +2819,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInvalidStreamId) {
return;
}
// Check that "invalid" stream ids are rejected.
- QuicStopSendingFrame frame(1, -1, 123);
+ QuicStopSendingFrame frame(1, -1, QUIC_STREAM_CANCELLED);
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
@@ -2822,7 +2832,8 @@ TEST_P(QuicSessionTestServer, OnStopSendingReadUnidirectional) {
return;
}
// It's illegal to send STOP_SENDING with a stream ID that is read-only.
- QuicStopSendingFrame frame(1, GetNthClientInitiatedUnidirectionalId(1), 123);
+ QuicStopSendingFrame frame(1, GetNthClientInitiatedUnidirectionalId(1),
+ QUIC_STREAM_CANCELLED);
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
@@ -2840,7 +2851,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingStaticStreams) {
stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL);
QuicSessionPeer::ActivateStream(&session_, std::move(fake_static_stream));
// Check that a stream id in the static stream map is ignored.
- QuicStopSendingFrame frame(1, stream_id, 123);
+ QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED);
EXPECT_CALL(*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
"Received STOP_SENDING for a static stream", _));
@@ -2858,7 +2869,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingForWriteClosedStream) {
QuicStreamPeer::SetFinSent(stream);
stream->CloseWriteSide();
EXPECT_TRUE(stream->write_side_closed());
- QuicStopSendingFrame frame(1, stream_id, 123);
+ QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED);
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
session_.OnStopSendingFrame(frame);
}
@@ -2872,7 +2883,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingClosedStream) {
TestStream* stream = session_.CreateOutgoingBidirectionalStream();
QuicStreamId stream_id = stream->id();
CloseStream(stream_id);
- QuicStopSendingFrame frame(1, stream_id, 123);
+ QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED);
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
session_.OnStopSendingFrame(frame);
}
@@ -2885,7 +2896,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputNonExistentLocalStream) {
}
QuicStopSendingFrame frame(1, GetNthServerInitiatedBidirectionalId(123456),
- 123);
+ QUIC_STREAM_CANCELLED);
EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_STREAM_WRONG_DIRECTION,
"Data for nonexistent stream", _))
.Times(1);
@@ -2898,7 +2909,8 @@ TEST_P(QuicSessionTestServer, OnStopSendingNewStream) {
if (!VersionHasIetfQuicFrames(transport_version())) {
return;
}
- QuicStopSendingFrame frame(1, GetNthClientInitiatedBidirectionalId(1), 123);
+ QuicStopSendingFrame frame(1, GetNthClientInitiatedBidirectionalId(1),
+ QUIC_STREAM_CANCELLED);
// A Rst will be sent as a response for STOP_SENDING.
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1);
@@ -2925,12 +2937,10 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputValidStream) {
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream));
QuicStreamId stream_id = stream->id();
- QuicStopSendingFrame frame(1, stream_id, 123);
+ QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED);
// Expect a reset to come back out.
EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(
- *connection_,
- OnStreamReset(stream_id, static_cast<QuicRstStreamErrorCode>(123)));
+ EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_STREAM_CANCELLED));
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
session_.OnStopSendingFrame(frame);
@@ -2952,6 +2962,9 @@ TEST_P(QuicSessionTestServer, WriteBufferedCryptoFrames) {
EXPECT_TRUE(session_.WillingAndAbleToWrite());
EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ connection_->SetEncrypter(
+ ENCRYPTION_ZERO_RTT,
+ std::make_unique<NullEncrypter>(connection_->perspective()));
crypto_stream->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 350, 1000))
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc
index 5fd63585c18..d973549e555 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc
@@ -109,12 +109,8 @@ QuicByteCount GetReceivedFlowControlWindow(QuicSession* session,
// static
const SpdyPriority QuicStream::kDefaultPriority;
-// static
-const int QuicStream::kDefaultUrgency;
-
PendingStream::PendingStream(QuicStreamId id, QuicSession* session)
: id_(id),
- session_(session),
stream_delegate_(session),
stream_bytes_read_(0),
fin_received_(false),
@@ -125,8 +121,8 @@ PendingStream::PendingStream(QuicStreamId id, QuicSession* session)
GetReceivedFlowControlWindow(session, id),
GetInitialStreamFlowControlWindowToSend(session, id),
kStreamReceiveWindowLimit,
- session_->flow_controller()->auto_tune_receive_window(),
- session_->flow_controller()),
+ session->flow_controller()->auto_tune_receive_window(),
+ session->flow_controller()),
sequencer_(this) {}
void PendingStream::OnDataAvailable() {
@@ -267,9 +263,12 @@ void PendingStream::StopReading() {
sequencer_.StopReading();
}
-QuicStream::QuicStream(PendingStream* pending, StreamType type, bool is_static)
+QuicStream::QuicStream(PendingStream* pending,
+ QuicSession* session,
+ StreamType type,
+ bool is_static)
: QuicStream(pending->id_,
- pending->session_,
+ session,
std::move(pending->sequencer_),
is_static,
type,
@@ -362,6 +361,7 @@ QuicStream::QuicStream(QuicStreamId id,
session->IsIncomingStream(id_),
session->version())
: type),
+ creation_time_(session->connection()->clock()->ApproximateNow()),
perspective_(session->perspective()) {
if (type_ == WRITE_UNIDIRECTIONAL) {
fin_received_ = true;
@@ -388,6 +388,16 @@ QuicStream::~QuicStream() {
}
}
+// static
+int QuicStream::DefaultUrgency() {
+ if (GetQuicReloadableFlag(quic_http3_new_default_urgency_value)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_http3_new_default_urgency_value);
+ return 3;
+ } else {
+ return 1;
+ }
+}
+
void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
DCHECK_EQ(frame.stream_id, id_);
@@ -475,7 +485,7 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
sequencer_.OnStreamFrame(frame);
}
-bool QuicStream::OnStopSending(uint16_t code) {
+bool QuicStream::OnStopSending(QuicRstStreamErrorCode code) {
// Do not reset the stream if all data has been sent and acknowledged.
if (write_side_closed() && !IsWaitingForAcks()) {
QUIC_DVLOG(1) << ENDPOINT
@@ -493,11 +503,10 @@ bool QuicStream::OnStopSending(uint16_t code) {
return false;
}
- stream_error_ = static_cast<QuicRstStreamErrorCode>(code);
+ stream_error_ = code;
- session()->SendRstStream(id(),
- static_cast<quic::QuicRstStreamErrorCode>(code),
- stream_bytes_written(), /*send_rst_only = */ true);
+ session()->SendRstStream(id(), code, stream_bytes_written(),
+ /*send_rst_only = */ true);
rst_sent_ = true;
CloseWriteSide();
return true;
@@ -1009,8 +1018,7 @@ bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset,
fin_outstanding_ = false;
fin_lost_ = false;
}
- if (!IsWaitingForAcks() && (!session()->remove_zombie_streams() ||
- (read_side_closed_ && write_side_closed_))) {
+ if (!IsWaitingForAcks() && read_side_closed_ && write_side_closed_) {
session_->OnStreamDoneWaitingForAcks(id_);
}
return new_data_acked;
@@ -1206,10 +1214,6 @@ void QuicStream::WriteBufferedData() {
if (consumed_data.bytes_consumed > 0 || consumed_data.fin_consumed) {
busy_counter_ = 0;
}
-
- if (IsWaitingForAcks()) {
- session_->OnStreamWaitingForAcks(id_);
- }
}
uint64_t QuicStream::BufferedDataBytes() const {
@@ -1309,16 +1313,6 @@ void QuicStream::OnDeadlinePassed() {
Reset(QUIC_STREAM_TTL_EXPIRED);
}
-void QuicStream::SendStopSending(uint16_t code) {
- if (!VersionHasIetfQuicFrames(transport_version())) {
- // If the connection is not version 99, do nothing.
- // Do not QUIC_BUG or anything; the application really does not need to know
- // what version the connection is in.
- return;
- }
- session_->SendStopSending(code, id_);
-}
-
bool QuicStream::IsFlowControlBlocked() const {
if (!flow_controller_.has_value()) {
QUIC_BUG << "Trying to access non-existent flow controller.";
@@ -1347,7 +1341,7 @@ void QuicStream::UpdateReceiveWindowSize(QuicStreamOffset size) {
spdy::SpdyStreamPrecedence QuicStream::CalculateDefaultPriority(
const QuicSession* session) {
if (VersionUsesHttp3(session->transport_version())) {
- return spdy::SpdyStreamPrecedence(QuicStream::kDefaultUrgency);
+ return spdy::SpdyStreamPrecedence(DefaultUrgency());
}
if (session->use_http2_priority_write_scheduler()) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h
index 35901906b4f..f0a5a714a21 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h
@@ -90,9 +90,7 @@ class QUIC_EXPORT_PRIVATE PendingStream
// ID of this stream.
QuicStreamId id_;
- // Session which owns this.
- // TODO(b/136274541): Remove session pointer from streams.
- QuicSession* session_;
+ // |stream_delegate_| must outlive this stream.
StreamDelegateInterface* stream_delegate_;
// Bytes read refers to payload bytes only: they do not include framing,
@@ -113,6 +111,7 @@ class QUIC_EXPORT_PRIVATE PendingStream
class QUIC_EXPORT_PRIVATE QuicStream
: public QuicStreamSequencer::StreamInterface {
public:
+ // Default priority for Google QUIC.
// This is somewhat arbitrary. It's possible, but unlikely, we will either
// fail to set a priority client-side, or cancel a stream before stripping the
// priority from the wire server-side. In either case, start out with a
@@ -121,10 +120,6 @@ class QUIC_EXPORT_PRIVATE QuicStream
static_assert(kDefaultPriority ==
(spdy::kV3LowestPriority + spdy::kV3HighestPriority) / 2,
"Unexpected value of kDefaultPriority");
- // On the other hand, when using IETF QUIC, use the default value defined by
- // the priority extension at
- // https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html#default.
- static const int kDefaultUrgency = 1;
// Creates a new stream with stream_id |id| associated with |session|. If
// |is_static| is true, then the stream will be given precedence
@@ -136,12 +131,21 @@ class QUIC_EXPORT_PRIVATE QuicStream
QuicSession* session,
bool is_static,
StreamType type);
- QuicStream(PendingStream* pending, StreamType type, bool is_static);
+ QuicStream(PendingStream* pending,
+ QuicSession* session,
+ StreamType type,
+ bool is_static);
QuicStream(const QuicStream&) = delete;
QuicStream& operator=(const QuicStream&) = delete;
virtual ~QuicStream();
+ // Default priority for IETF QUIC, defined by the priority extension at
+ // https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html#urgency.
+ // TODO(bnc): Remove this method and reinstate static const int
+ // kDefaultUrgency member when removing quic_http3_new_default_urgency_value.
+ static int DefaultUrgency();
+
// QuicStreamSequencer::StreamInterface implementation.
QuicStreamId id() const override { return id_; }
// Called by the stream subclass after it has consumed the final incoming
@@ -338,29 +342,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
StreamType type() const { return type_; }
- // Creates and sends a STOP_SENDING frame. This can be called regardless of
- // the version that has been negotiated. If not IETF QUIC/Version 99 then the
- // method is a noop, relieving the application of the necessity of
- // understanding the connection's QUIC version and knowing whether it can call
- // this method or not.
- void SendStopSending(uint16_t code);
-
// Handle received StopSending frame. Returns true if the processing finishes
// gracefully.
- virtual bool OnStopSending(uint16_t code);
-
- // Close the write side of the socket. Further writes will fail.
- // Can be called by the subclass or internally.
- // Does not send a FIN. May cause the stream to be closed.
- virtual void CloseWriteSide();
-
- // Close the read side of the stream. May cause the stream to be closed.
- // Subclasses and consumers should use StopReading to terminate reading early
- // if expecting a FIN. Can be used directly by subclasses if not expecting a
- // FIN.
- // TODO(fayang): move this to protected when removing
- // QuicSession::CloseStream.
- void CloseReadSide();
+ virtual bool OnStopSending(QuicRstStreamErrorCode code);
// Returns true if the stream is static.
bool is_static() const { return is_static_; }
@@ -370,6 +354,10 @@ class QUIC_EXPORT_PRIVATE QuicStream
static spdy::SpdyStreamPrecedence CalculateDefaultPriority(
const QuicSession* session);
+ QuicTime creation_time() const { return creation_time_; }
+
+ bool fin_buffered() const { return fin_buffered_; }
+
protected:
// Called when data of [offset, offset + data_length] is buffered in send
// buffer.
@@ -414,13 +402,16 @@ class QUIC_EXPORT_PRIVATE QuicStream
// empty.
void SetFinSent();
+ // Close the write side of the socket. Further writes will fail.
+ // Can be called by the subclass or internally.
+ // Does not send a FIN. May cause the stream to be closed.
+ virtual void CloseWriteSide();
+
void set_rst_received(bool rst_received) { rst_received_ = rst_received; }
void set_stream_error(QuicRstStreamErrorCode error) { stream_error_ = error; }
StreamDelegateInterface* stream_delegate() { return stream_delegate_; }
- bool fin_buffered() const { return fin_buffered_; }
-
const QuicSession* session() const { return session_; }
QuicSession* session() { return session_; }
@@ -461,6 +452,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
// WriteOrBufferData, Writev and WriteBufferedData.
void WriteBufferedData();
+ // Close the read side of the stream. May cause the stream to be closed.
+ void CloseReadSide();
+
// Called when bytes are sent to the peer.
void AddBytesSent(QuicByteCount bytes);
@@ -553,6 +547,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
// write unidirectional.
const StreamType type_;
+ // Creation time of this stream, as reported by the QuicClock.
+ const QuicTime creation_time_;
+
Perspective perspective_;
};
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 206fb7123b9..f2b5563344b 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
@@ -58,8 +58,11 @@ class TestStream : public QuicStream {
sequencer()->set_level_triggered(true);
}
- TestStream(PendingStream* pending, StreamType type, bool is_static)
- : QuicStream(pending, type, is_static) {}
+ TestStream(PendingStream* pending,
+ QuicSession* session,
+ StreamType type,
+ bool is_static)
+ : QuicStream(pending, session, type, is_static) {}
MOCK_METHOD(void, OnDataAvailable, (), (override));
@@ -169,11 +172,12 @@ TEST_P(QuicStreamTest, PendingStreamStaticness) {
Initialize();
PendingStream pending(kTestStreamId + 2, session_.get());
- TestStream stream(&pending, StreamType::BIDIRECTIONAL, false);
+ TestStream stream(&pending, session_.get(), StreamType::BIDIRECTIONAL, false);
EXPECT_FALSE(stream.is_static());
PendingStream pending2(kTestStreamId + 3, session_.get());
- TestStream stream2(&pending2, StreamType::BIDIRECTIONAL, true);
+ TestStream stream2(&pending2, session_.get(), StreamType::BIDIRECTIONAL,
+ true);
EXPECT_TRUE(stream2.is_static());
}
@@ -233,7 +237,8 @@ TEST_P(QuicStreamTest, FromPendingStream) {
QuicStreamFrame frame2(kTestStreamId + 2, true, 3, ".");
pending.OnStreamFrame(frame2);
- TestStream stream(&pending, StreamType::READ_UNIDIRECTIONAL, false);
+ TestStream stream(&pending, session_.get(), StreamType::READ_UNIDIRECTIONAL,
+ false);
EXPECT_EQ(3, stream.num_frames_received());
EXPECT_EQ(3u, stream.stream_bytes_read());
EXPECT_EQ(1, stream.num_duplicate_frames_received());
@@ -251,8 +256,8 @@ TEST_P(QuicStreamTest, FromPendingStreamThenData) {
QuicStreamFrame frame(kTestStreamId + 2, false, 2, ".");
pending.OnStreamFrame(frame);
- auto stream =
- new TestStream(&pending, StreamType::READ_UNIDIRECTIONAL, false);
+ auto stream = new TestStream(&pending, session_.get(),
+ StreamType::READ_UNIDIRECTIONAL, false);
session_->ActivateStream(QuicWrapUnique(stream));
QuicStreamFrame frame2(kTestStreamId + 2, true, 3, ".");
@@ -455,7 +460,7 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) {
// Now close the stream, and expect that we send a RST.
EXPECT_CALL(*session_, SendRstStream(_, _, _, _));
- stream_->CloseReadSide();
+ QuicStreamPeer::CloseReadSide(stream_);
stream_->CloseWriteSide();
EXPECT_FALSE(session_->HasUnackedStreamData());
EXPECT_FALSE(fin_sent());
@@ -483,7 +488,7 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) {
EXPECT_FALSE(rst_sent());
// Now close the stream, and expect that we do not send a RST.
- stream_->CloseReadSide();
+ QuicStreamPeer::CloseReadSide(stream_);
stream_->CloseWriteSide();
EXPECT_TRUE(fin_sent());
EXPECT_FALSE(rst_sent());
@@ -508,7 +513,7 @@ TEST_P(QuicStreamTest, OnlySendOneRst) {
// Now close the stream (any further resets being sent would break the
// expectation above).
- stream_->CloseReadSide();
+ QuicStreamPeer::CloseReadSide(stream_);
stream_->CloseWriteSide();
EXPECT_FALSE(fin_sent());
EXPECT_TRUE(rst_sent());
@@ -642,7 +647,7 @@ TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) {
CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
stream_->OnStreamReset(rst_frame);
EXPECT_TRUE(stream_->HasReceivedFinalOffset());
- stream_->CloseReadSide();
+ QuicStreamPeer::CloseReadSide(stream_);
stream_->CloseWriteSide();
}
@@ -1554,30 +1559,6 @@ TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresEarlyRetransmitData) {
stream_->RetransmitStreamData(0, 100, false, PTO_RETRANSMISSION);
}
-// Test that QuicStream::StopSending A) is a no-op if the connection is not in
-// version 99, B) that it properly invokes QuicSession::StopSending, and C) that
-// the correct data is passed along, including getting the stream ID.
-TEST_P(QuicStreamTest, CheckStopSending) {
- Initialize();
- const int kStopSendingCode = 123;
- // These must start as false.
- EXPECT_FALSE(stream_->write_side_closed());
- EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
- // Expect to actually see a stop sending if and only if we are in version 99.
- if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- EXPECT_CALL(*session_, SendStopSending(kStopSendingCode, stream_->id()))
- .Times(1);
- } else {
- EXPECT_CALL(*session_, SendStopSending(_, _)).Times(0);
- }
- stream_->SendStopSending(kStopSendingCode);
- // Sending a STOP_SENDING does not actually close the local stream.
- // Our implementation waits for the responding RESET_STREAM to effect the
- // closes. Therefore, read- and write-side closes should both be false.
- EXPECT_FALSE(stream_->write_side_closed());
- EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
-}
-
// Test that OnStreamReset does one-way (read) closes if version 99, two way
// (read and write) if not version 99.
TEST_P(QuicStreamTest, OnStreamResetReadOrReadWrite) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc
index eeaf297c1ca..bf352f363ad 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc
@@ -108,6 +108,75 @@ void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet,
}
}
+void QuicTraceVisitor::OnPacketSent(
+ QuicPacketNumber packet_number,
+ QuicPacketLength packet_length,
+ bool /*has_crypto_handshake*/,
+ TransmissionType /*transmission_type*/,
+ EncryptionLevel encryption_level,
+ const QuicFrames& retransmittable_frames,
+ const QuicFrames& /*nonretransmittable_frames*/,
+ QuicTime sent_time) {
+ quic_trace::Event* event = trace_.add_events();
+ event->set_event_type(quic_trace::PACKET_SENT);
+ event->set_time_us(ConvertTimestampToRecordedFormat(sent_time));
+ event->set_packet_number(packet_number.ToUint64());
+ event->set_packet_size(packet_length);
+ event->set_encryption_level(EncryptionLevelToProto(encryption_level));
+
+ for (const QuicFrame& frame : retransmittable_frames) {
+ switch (frame.type) {
+ case STREAM_FRAME:
+ case RST_STREAM_FRAME:
+ case CONNECTION_CLOSE_FRAME:
+ case WINDOW_UPDATE_FRAME:
+ case BLOCKED_FRAME:
+ case PING_FRAME:
+ case HANDSHAKE_DONE_FRAME:
+ case ACK_FREQUENCY_FRAME:
+ PopulateFrameInfo(frame, event->add_frames());
+ break;
+
+ case PADDING_FRAME:
+ case MTU_DISCOVERY_FRAME:
+ case STOP_WAITING_FRAME:
+ case ACK_FRAME:
+ QUIC_BUG
+ << "Frames of type are not retransmittable and are not supposed "
+ "to be in retransmittable_frames";
+ break;
+
+ // New IETF frames, not used in current gQUIC version.
+ case NEW_CONNECTION_ID_FRAME:
+ case RETIRE_CONNECTION_ID_FRAME:
+ case MAX_STREAMS_FRAME:
+ case STREAMS_BLOCKED_FRAME:
+ case PATH_RESPONSE_FRAME:
+ case PATH_CHALLENGE_FRAME:
+ case STOP_SENDING_FRAME:
+ case MESSAGE_FRAME:
+ case CRYPTO_FRAME:
+ case NEW_TOKEN_FRAME:
+ break;
+
+ // Ignore gQUIC-specific frames.
+ case GOAWAY_FRAME:
+ break;
+
+ case NUM_FRAME_TYPES:
+ QUIC_BUG << "Unknown frame type encountered";
+ break;
+ }
+ }
+
+ // Output PCC DebugState on packet sent for analysis.
+ if (connection_->sent_packet_manager()
+ .GetSendAlgorithm()
+ ->GetCongestionControlType() == kPCC) {
+ PopulateTransportState(event->mutable_transport_state());
+ }
+}
+
void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame,
quic_trace::Frame* frame_record) {
switch (frame.type) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h
index c9732cf423c..889d90a06c0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h
@@ -18,10 +18,21 @@ class QUIC_NO_EXPORT QuicTraceVisitor : public QuicConnectionDebugVisitor {
public:
explicit QuicTraceVisitor(const QuicConnection* connection);
+ // TODO(wub): Delete when deprecating
+ // --quic_give_sent_packet_to_debug_visitor_after_sent.
void OnPacketSent(const SerializedPacket& serialized_packet,
TransmissionType transmission_type,
QuicTime sent_time) override;
+ void OnPacketSent(QuicPacketNumber packet_number,
+ QuicPacketLength packet_length,
+ bool has_crypto_handshake,
+ TransmissionType transmission_type,
+ EncryptionLevel encryption_level,
+ const QuicFrames& retransmittable_frames,
+ const QuicFrames& nonretransmittable_frames,
+ QuicTime sent_time) override;
+
void OnIncomingAck(QuicPacketNumber ack_packet_number,
EncryptionLevel ack_decrypted_level,
const QuicAckFrame& ack_frame,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc
index a27b769bccd..02b34b57a14 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc
@@ -13,20 +13,23 @@ QuicTransmissionInfo::QuicTransmissionInfo()
transmission_type(NOT_RETRANSMISSION),
in_flight(false),
state(OUTSTANDING),
- has_crypto_handshake(false) {}
+ has_crypto_handshake(false),
+ has_ack_frequency(false) {}
QuicTransmissionInfo::QuicTransmissionInfo(EncryptionLevel level,
TransmissionType transmission_type,
QuicTime sent_time,
QuicPacketLength bytes_sent,
- bool has_crypto_handshake)
+ bool has_crypto_handshake,
+ bool has_ack_frequency)
: encryption_level(level),
bytes_sent(bytes_sent),
sent_time(sent_time),
transmission_type(transmission_type),
in_flight(false),
state(OUTSTANDING),
- has_crypto_handshake(has_crypto_handshake) {}
+ has_crypto_handshake(has_crypto_handshake),
+ has_ack_frequency(has_ack_frequency) {}
QuicTransmissionInfo::QuicTransmissionInfo(const QuicTransmissionInfo& other) =
default;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h
index 60236650724..acc5667e9fd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h
@@ -25,7 +25,8 @@ struct QUIC_EXPORT_PRIVATE QuicTransmissionInfo {
TransmissionType transmission_type,
QuicTime sent_time,
QuicPacketLength bytes_sent,
- bool has_crypto_handshake);
+ bool has_crypto_handshake,
+ bool has_ack_frequency);
QuicTransmissionInfo(const QuicTransmissionInfo& other);
@@ -43,6 +44,8 @@ struct QUIC_EXPORT_PRIVATE QuicTransmissionInfo {
SentPacketState state;
// True if the packet contains stream data from the crypto stream.
bool has_crypto_handshake;
+ // True if the packet contains ack frequency frame.
+ bool has_ack_frequency;
// Records the first sent packet after this packet was detected lost. Zero if
// this packet has not been detected lost. This is used to keep lost packet
// for another RTT (for potential spurious loss detection)
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
index fb2e9c89c4f..4027ffa60ee 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
@@ -299,7 +299,6 @@ std::string SerializedPacketFateToString(SerializedPacketFate fate) {
RETURN_STRING_LITERAL(COALESCE);
RETURN_STRING_LITERAL(BUFFER);
RETURN_STRING_LITERAL(SEND_TO_WRITER);
- RETURN_STRING_LITERAL(FAILED_TO_WRITE_COALESCED_PACKET);
RETURN_STRING_LITERAL(LEGACY_VERSION_ENCAPSULATE);
default:
return quiche::QuicheStrCat("Unknown(", static_cast<int>(fate), ")");
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.h b/chromium/net/third_party/quiche/src/quic/core/quic_types.h
index 55c5046b23a..13307bb9d6f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_types.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.h
@@ -46,9 +46,6 @@ using PacketTimeVector = std::vector<std::pair<QuicPacketNumber, QuicTime>>;
enum : size_t { kQuicPathFrameBufferSize = 8 };
using QuicPathFrameBuffer = std::array<uint8_t, kQuicPathFrameBufferSize>;
-// Application error code used in the QUIC Stop Sending frame.
-using QuicApplicationErrorCode = uint16_t;
-
// The connection id sequence number specifies the order that connection
// ids must be used in. This is also the sequence number carried in
// the IETF QUIC NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames.
@@ -533,6 +530,9 @@ enum SentPacketState : uint8_t {
PTO_RETRANSMITTED,
// This packet has been retransmitted for probing purpose.
PROBE_RETRANSMITTED,
+ // Do not collect RTT sample if this packet is the largest_acked of an
+ // incoming ACK.
+ NOT_CONTRIBUTING_RTT,
LAST_PACKET_STATE = PROBE_RETRANSMITTED,
};
@@ -687,8 +687,6 @@ enum PacketNumberSpace : uint8_t {
QUIC_EXPORT_PRIVATE std::string PacketNumberSpaceToString(
PacketNumberSpace packet_number_space);
-enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING };
-
// Used to return the result of processing a received ACK frame.
enum AckResult {
PACKETS_NEWLY_ACKED,
@@ -709,10 +707,6 @@ enum SerializedPacketFate : uint8_t {
COALESCE, // Try to coalesce packet.
BUFFER, // Buffer packet in buffered_packets_.
SEND_TO_WRITER, // Send packet to writer.
- // TODO(fayang): remove FAILED_TO_WRITE_COALESCED_PACKET when deprecating
- // quic_determine_serialized_packet_fate_early.
- FAILED_TO_WRITE_COALESCED_PACKET, // Packet cannot be coalesced, error occurs
- // when sending existing coalesced packet.
LEGACY_VERSION_ENCAPSULATE, // Perform Legacy Version Encapsulation on this
// packet.
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc
index c5ab345f433..ea68727211c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc
@@ -68,11 +68,7 @@ QuicUdpSocketFd CreateNonblockingSocket(int address_family) {
<< strerror(errno);
return kQuicInvalidSocketFd;
}
-
- return fd;
-
#else
-
// Create a socket and use fcntl to set it to nonblocking.
// This implementation is used when building for iOS, OSX and old versions of
// Linux (< 2.6.27) and old versions of Android (< API 21).
@@ -98,10 +94,10 @@ QuicUdpSocketFd CreateNonblockingSocket(int address_family) {
close(fd);
return kQuicInvalidSocketFd;
}
+#endif
+ SetGoogleSocketOptions(fd);
return fd;
-
-#endif
} // End CreateNonblockingSocket
void SetV4SelfIpInControlMessage(const QuicIpAddress& self_address,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
index dd70f823be6..3e377cfa21b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
@@ -128,12 +128,14 @@ QuicUnackedPacketMap::~QuicUnackedPacketMap() {
}
}
-void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet,
+void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* mutable_packet,
TransmissionType transmission_type,
QuicTime sent_time,
- bool set_in_flight) {
- QuicPacketNumber packet_number = packet->packet_number;
- QuicPacketLength bytes_sent = packet->encrypted_length;
+ bool set_in_flight,
+ bool measure_rtt) {
+ const SerializedPacket& packet = *mutable_packet;
+ QuicPacketNumber packet_number = packet.packet_number;
+ QuicPacketLength bytes_sent = packet.encrypted_length;
QUIC_BUG_IF(largest_sent_packet_.IsInitialized() &&
largest_sent_packet_ >= packet_number)
<< "largest_sent_packet_: " << largest_sent_packet_
@@ -144,12 +146,17 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet,
unacked_packets_.back().state = NEVER_SENT;
}
- const bool has_crypto_handshake =
- packet->has_crypto_handshake == IS_HANDSHAKE;
- QuicTransmissionInfo info(packet->encryption_level, transmission_type,
- sent_time, bytes_sent, has_crypto_handshake);
- info.largest_acked = packet->largest_acked;
- largest_sent_largest_acked_.UpdateMax(packet->largest_acked);
+ const bool has_crypto_handshake = packet.has_crypto_handshake == IS_HANDSHAKE;
+ QuicTransmissionInfo info(packet.encryption_level, transmission_type,
+ sent_time, bytes_sent, has_crypto_handshake,
+ packet.has_ack_frequency);
+ info.largest_acked = packet.largest_acked;
+ largest_sent_largest_acked_.UpdateMax(packet.largest_acked);
+
+ if (!measure_rtt) {
+ QUIC_BUG_IF(set_in_flight);
+ info.state = NOT_CONTRIBUTING_RTT;
+ }
largest_sent_packet_ = packet_number;
if (set_in_flight) {
@@ -170,7 +177,7 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet,
last_crypto_packet_sent_time_ = sent_time;
}
- packet->retransmittable_frames.swap(
+ mutable_packet->retransmittable_frames.swap(
unacked_packets_.back().retransmittable_frames);
}
@@ -240,7 +247,8 @@ bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
// Packet can be used for RTT measurement if it may yet be acked as the
// largest observed packet by the receiver.
return QuicUtils::IsAckable(info.state) &&
- (!largest_acked_.IsInitialized() || packet_number > largest_acked_);
+ (!largest_acked_.IsInitialized() || packet_number > largest_acked_) &&
+ info.state != NOT_CONTRIBUTING_RTT;
}
bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
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 9f67e2b74c8..595f435e0fc 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
@@ -30,16 +30,17 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap {
QuicUnackedPacketMap& operator=(const QuicUnackedPacketMap&) = delete;
~QuicUnackedPacketMap();
- // Adds |serialized_packet| to the map and marks it as sent at |sent_time|.
+ // Adds |mutable_packet| to the map and marks it as sent at |sent_time|.
// Marks the packet as in flight if |set_in_flight| is true.
// Packets marked as in flight are expected to be marked as missing when they
// don't arrive, indicating the need for retransmission.
- // Any AckNotifierWrappers in |serialized_packet| are swapped from the
- // serialized packet into the QuicTransmissionInfo.
- void AddSentPacket(SerializedPacket* serialized_packet,
+ // Any retransmittible_frames in |mutable_packet| are swapped from
+ // |mutable_packet| into the QuicTransmissionInfo.
+ void AddSentPacket(SerializedPacket* mutable_packet,
TransmissionType transmission_type,
QuicTime sent_time,
- bool set_in_flight);
+ bool set_in_flight,
+ bool measure_rtt);
// Returns true if the packet |packet_number| is unacked.
bool IsUnacked(QuicPacketNumber packet_number) const;
@@ -114,10 +115,13 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap {
typedef std::deque<QuicTransmissionInfo> UnackedPacketMap;
typedef UnackedPacketMap::const_iterator const_iterator;
+ typedef UnackedPacketMap::const_reverse_iterator const_reverse_iterator;
typedef UnackedPacketMap::iterator iterator;
const_iterator begin() const { return unacked_packets_.begin(); }
const_iterator end() const { return unacked_packets_.end(); }
+ const_reverse_iterator rbegin() const { return unacked_packets_.rbegin(); }
+ const_reverse_iterator rend() const { return unacked_packets_.rend(); }
iterator begin() { return unacked_packets_.begin(); }
iterator end() { return unacked_packets_.end(); }
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc
index 330cc11c8b0..96ba08acb35 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc
@@ -153,7 +153,8 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam<Perspective> {
info->first_sent_after_loss = QuicPacketNumber(new_packet_number);
SerializedPacket packet(
CreateRetransmittablePacketForStream(new_packet_number, stream_id));
- unacked_packets_.AddSentPacket(&packet, transmission_type, now_, true);
+ unacked_packets_.AddSentPacket(&packet, transmission_type, now_, true,
+ true);
}
QuicUnackedPacketMap unacked_packets_;
QuicTime now_;
@@ -169,7 +170,8 @@ INSTANTIATE_TEST_SUITE_P(Tests,
TEST_P(QuicUnackedPacketMapTest, RttOnly) {
// Acks are only tracked for RTT measurement purposes.
SerializedPacket packet(CreateNonRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, false);
+ unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, false,
+ true);
uint64_t unacked[] = {1};
VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked));
@@ -185,7 +187,7 @@ TEST_P(QuicUnackedPacketMapTest, RttOnly) {
TEST_P(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) {
// Simulate a retransmittable packet being sent and acked.
SerializedPacket packet(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true, true);
uint64_t unacked[] = {1};
VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked));
@@ -211,7 +213,7 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) {
TEST_P(QuicUnackedPacketMapTest, StopRetransmission) {
const QuicStreamId stream_id = 2;
SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
- unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true, true);
uint64_t unacked[] = {1};
VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked));
@@ -229,7 +231,7 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmission) {
TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) {
const QuicStreamId stream_id = 2;
SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
- unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true, true);
uint64_t unacked[] = {1};
VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked));
@@ -247,7 +249,8 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) {
TEST_P(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) {
const QuicStreamId stream_id = 2;
SerializedPacket packet1(CreateRetransmittablePacketForStream(1, stream_id));
- unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true,
+ true);
RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION);
uint64_t unacked[] = {1, 2};
@@ -266,7 +269,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittedPacket) {
// Simulate a retransmittable packet being sent, retransmitted, and the first
// transmission being acked.
SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true,
+ true);
RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION);
uint64_t unacked[] = {1, 2};
@@ -301,9 +305,11 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittedPacket) {
TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
// Simulate a retransmittable packet being sent and retransmitted twice.
SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true,
+ true);
SerializedPacket packet2(CreateRetransmittablePacket(2));
- unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true,
+ true);
uint64_t unacked[] = {1, 2};
VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked));
@@ -319,7 +325,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
RetransmitAndSendPacket(1, 3, LOSS_RETRANSMISSION);
SerializedPacket packet4(CreateRetransmittablePacket(4));
- unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true,
+ true);
uint64_t unacked2[] = {1, 3, 4};
VerifyUnackedPackets(unacked2, QUICHE_ARRAYSIZE(unacked2));
@@ -334,7 +341,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
unacked_packets_.RemoveRetransmittability(QuicPacketNumber(4));
RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
SerializedPacket packet6(CreateRetransmittablePacket(6));
- unacked_packets_.AddSentPacket(&packet6, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet6, NOT_RETRANSMISSION, now_, true,
+ true);
std::vector<uint64_t> unacked3 = {3, 5, 6};
std::vector<uint64_t> retransmittable3 = {3, 5, 6};
@@ -366,9 +374,11 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) {
// Simulate a retransmittable packet being sent and retransmitted twice.
SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true,
+ true);
SerializedPacket packet2(CreateRetransmittablePacket(2));
- unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true,
+ true);
uint64_t unacked[] = {1, 2};
VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked));
@@ -394,7 +404,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) {
// TLP 3 (formerly 1) as 4, and don't remove 1 from unacked.
RetransmitAndSendPacket(3, 4, TLP_RETRANSMISSION);
SerializedPacket packet5(CreateRetransmittablePacket(5));
- unacked_packets_.AddSentPacket(&packet5, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet5, NOT_RETRANSMISSION, now_, true,
+ true);
uint64_t unacked3[] = {1, 3, 4, 5};
VerifyUnackedPackets(unacked3, QUICHE_ARRAYSIZE(unacked3));
@@ -423,9 +434,11 @@ TEST_P(QuicUnackedPacketMapTest, SendWithGap) {
// Simulate a retransmittable packet being sent, retransmitted, and the first
// transmission being acked.
SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true,
+ true);
SerializedPacket packet3(CreateRetransmittablePacket(3));
- unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true,
+ true);
RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.GetLeastUnacked());
@@ -571,7 +584,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) {
// Send packet 1.
SerializedPacket packet1(CreateRetransmittablePacket(1));
packet1.encryption_level = ENCRYPTION_INITIAL;
- unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true,
+ true);
EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.largest_sent_packet());
EXPECT_EQ(QuicPacketNumber(1),
unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace(
@@ -583,7 +597,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) {
// Send packet 2.
SerializedPacket packet2(CreateRetransmittablePacket(2));
packet2.encryption_level = ENCRYPTION_HANDSHAKE;
- unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true,
+ true);
EXPECT_EQ(QuicPacketNumber(2u), unacked_packets_.largest_sent_packet());
EXPECT_EQ(QuicPacketNumber(1),
unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace(
@@ -598,7 +613,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) {
// Send packet 3.
SerializedPacket packet3(CreateRetransmittablePacket(3));
packet3.encryption_level = ENCRYPTION_ZERO_RTT;
- unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true,
+ true);
EXPECT_EQ(QuicPacketNumber(3u), unacked_packets_.largest_sent_packet());
EXPECT_EQ(QuicPacketNumber(1),
unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace(
@@ -618,7 +634,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) {
// Send packet 4.
SerializedPacket packet4(CreateRetransmittablePacket(4));
packet4.encryption_level = ENCRYPTION_FORWARD_SECURE;
- unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true);
+ unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true,
+ true);
EXPECT_EQ(QuicPacketNumber(4u), unacked_packets_.largest_sent_packet());
EXPECT_EQ(QuicPacketNumber(1),
unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace(
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 aaadac11c9e..b6619d4398e 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
@@ -173,6 +173,7 @@ const char* QuicUtils::SentPacketStateToString(SentPacketState state) {
RETURN_STRING_LITERAL(RTO_RETRANSMITTED);
RETURN_STRING_LITERAL(PTO_RETRANSMITTED);
RETURN_STRING_LITERAL(PROBE_RETRANSMITTED);
+ RETURN_STRING_LITERAL(NOT_CONTRIBUTING_RTT)
}
return "INVALID_SENT_PACKET_STATE";
}
@@ -304,6 +305,9 @@ bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) {
case PADDING_FRAME:
case STOP_WAITING_FRAME:
case MTU_DISCOVERY_FRAME:
+ case PATH_CHALLENGE_FRAME:
+ case PATH_RESPONSE_FRAME:
+ case NEW_CONNECTION_ID_FRAME:
return false;
default:
return true;
@@ -653,5 +657,18 @@ EncryptionLevel QuicUtils::GetEncryptionLevel(
}
}
+// static
+bool QuicUtils::IsProbingFrame(QuicFrameType type) {
+ switch (type) {
+ case PATH_CHALLENGE_FRAME:
+ case PATH_RESPONSE_FRAME:
+ case NEW_CONNECTION_ID_FRAME:
+ case PADDING_FRAME:
+ return true;
+ default:
+ return false;
+ }
+}
+
#undef RETURN_STRING_LITERAL // undef for jumbo builds
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
index 9e190e0b386..05c7124194a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
@@ -230,6 +230,9 @@ class QUIC_EXPORT_PRIVATE QuicUtils {
// exceeds this value, it will result in a stream ID that exceeds the
// implementation limit on stream ID size.
static QuicStreamCount GetMaxStreamCount();
+
+ // Return true if this frame is an IETF probing frame.
+ static bool IsProbingFrame(QuicFrameType type);
};
template <typename Mask>
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc
index 52bb9a2d2f0..7cf6a1d8c24 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc
@@ -19,7 +19,7 @@ QuicVersionManager::QuicVersionManager(
GetQuicReloadableFlag(quic_disable_version_draft_29)),
disable_version_draft_27_(
GetQuicReloadableFlag(quic_disable_version_draft_27)),
- enable_version_t051_(GetQuicReloadableFlag(quic_enable_version_t051)),
+ disable_version_t051_(GetQuicReloadableFlag(quic_disable_version_t051)),
disable_version_t050_(GetQuicReloadableFlag(quic_disable_version_t050)),
disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)),
disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)),
@@ -61,7 +61,8 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
GetQuicReloadableFlag(quic_disable_version_draft_29) ||
disable_version_draft_27_ !=
GetQuicReloadableFlag(quic_disable_version_draft_27) ||
- enable_version_t051_ != GetQuicReloadableFlag(quic_enable_version_t051) ||
+ disable_version_t051_ !=
+ GetQuicReloadableFlag(quic_disable_version_t051) ||
disable_version_t050_ !=
GetQuicReloadableFlag(quic_disable_version_t050) ||
disable_version_q050_ !=
@@ -74,7 +75,7 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
GetQuicReloadableFlag(quic_disable_version_draft_29);
disable_version_draft_27_ =
GetQuicReloadableFlag(quic_disable_version_draft_27);
- enable_version_t051_ = GetQuicReloadableFlag(quic_enable_version_t051);
+ disable_version_t051_ = GetQuicReloadableFlag(quic_disable_version_t051);
disable_version_t050_ = GetQuicReloadableFlag(quic_disable_version_t050);
disable_version_q050_ = GetQuicReloadableFlag(quic_disable_version_q050);
disable_version_q046_ = GetQuicReloadableFlag(quic_disable_version_q046);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
index cbf5de1cd92..9c742f5eece 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
@@ -50,14 +50,16 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
// Should be called in constructor and RefilterSupportedVersions.
void AddCustomAlpn(const std::string& alpn);
+ bool disable_version_q050() const { return disable_version_q050_; }
+
private:
// Cached value of reloadable flags.
// quic_disable_version_draft_29 flag
bool disable_version_draft_29_;
// quic_disable_version_draft_27 flag
bool disable_version_draft_27_;
- // quic_enable_version_t051 flag
- bool enable_version_t051_;
+ // quic_disable_version_t051 flag
+ bool disable_version_t051_;
// quic_disable_version_t050 flag
bool disable_version_t050_;
// quic_disable_version_q050 flag
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 4b10cb78a78..d3f707bdda7 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
@@ -49,7 +49,7 @@ void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) {
} else if (version == ParsedQuicVersion::Draft27()) {
SetQuicReloadableFlag(quic_disable_version_draft_27, disable);
} else if (version == ParsedQuicVersion::T051()) {
- SetQuicReloadableFlag(quic_enable_version_t051, enable);
+ SetQuicReloadableFlag(quic_disable_version_t051, disable);
} else if (version == ParsedQuicVersion::T050()) {
SetQuicReloadableFlag(quic_disable_version_t050, disable);
} else if (version == ParsedQuicVersion::Q050()) {
@@ -360,7 +360,6 @@ ParsedQuicVersion ParseQuicVersionString(
return version;
}
}
- if (GetQuicReloadableFlag(quic_fix_print_draft_version)) {
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
if (version.UsesHttp3() &&
version_string ==
@@ -368,7 +367,6 @@ ParsedQuicVersion ParseQuicVersionString(
return version;
}
}
- }
// Reading from the client so this should not be considered an ERROR.
QUIC_DLOG(INFO) << "Unsupported QUIC version string: \"" << version_string
<< "\".";
@@ -424,7 +422,7 @@ ParsedQuicVersionVector FilterSupportedVersions(
filtered_versions.push_back(version);
}
} else if (version == ParsedQuicVersion::T051()) {
- if (GetQuicReloadableFlag(quic_enable_version_t051)) {
+ if (!GetQuicReloadableFlag(quic_disable_version_t051)) {
filtered_versions.push_back(version);
}
} else if (version == ParsedQuicVersion::T050()) {
@@ -563,16 +561,14 @@ std::string ParsedQuicVersionToString(ParsedQuicVersion version) {
if (version == UnsupportedQuicVersion()) {
return "0";
}
- if (GetQuicReloadableFlag(quic_fix_print_draft_version)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_print_draft_version);
- if (version == ParsedQuicVersion::Draft29()) {
- DCHECK(version.UsesHttp3());
- return "draft29";
- } else if (version == ParsedQuicVersion::Draft27()) {
- DCHECK(version.UsesHttp3());
- return "draft27";
- }
+ if (version == ParsedQuicVersion::Draft29()) {
+ DCHECK(version.UsesHttp3());
+ return "draft29";
+ } else if (version == ParsedQuicVersion::Draft27()) {
+ DCHECK(version.UsesHttp3());
+ return "draft27";
}
+
return QuicVersionLabelToString(CreateQuicVersionLabel(version));
}
@@ -667,7 +663,6 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
void QuicVersionInitializeSupportForIetfDraft() {
// Enable necessary flags.
- SetQuicRestartFlag(quic_enable_tls_resumption_v4, true);
SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
index 1eff47a845f..fa32de3f9b8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
@@ -236,14 +236,10 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) {
EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("T050"));
EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("h3-T050"));
EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("ff00001d"));
- if (GetQuicReloadableFlag(quic_fix_print_draft_version)) {
- EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("draft29"));
- }
+ EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("draft29"));
EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("h3-29"));
EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("ff00001b"));
- if (GetQuicReloadableFlag(quic_fix_print_draft_version)) {
- EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("draft27"));
- }
+ EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("draft27"));
EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("h3-27"));
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
@@ -407,17 +403,8 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) {
EXPECT_EQ("Q046", ParsedQuicVersionToString(ParsedQuicVersion::Q046()));
EXPECT_EQ("Q050", ParsedQuicVersionToString(ParsedQuicVersion::Q050()));
EXPECT_EQ("T050", ParsedQuicVersionToString(ParsedQuicVersion::T050()));
- if (GetQuicReloadableFlag(quic_fix_print_draft_version)) {
- EXPECT_EQ("draft27",
- ParsedQuicVersionToString(ParsedQuicVersion::Draft27()));
- EXPECT_EQ("draft29",
- ParsedQuicVersionToString(ParsedQuicVersion::Draft29()));
- } else {
- EXPECT_EQ("ff00001b",
- ParsedQuicVersionToString(ParsedQuicVersion::Draft27()));
- EXPECT_EQ("ff00001d",
- ParsedQuicVersionToString(ParsedQuicVersion::Draft29()));
- }
+ EXPECT_EQ("draft27", ParsedQuicVersionToString(ParsedQuicVersion::Draft27()));
+ EXPECT_EQ("draft29", ParsedQuicVersionToString(ParsedQuicVersion::Draft29()));
ParsedQuicVersionVector versions_vector = {ParsedQuicVersion::Q043()};
EXPECT_EQ("Q043", ParsedQuicVersionVectorToString(versions_vector));
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc
index 3c1edc43e2f..b3602a6618a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc
@@ -149,8 +149,17 @@ void QuicWriteBlockedList::UpdateBytesForStream(QuicStreamId stream_id,
if (batch_write_stream_id_[last_priority_popped_] == stream_id) {
// If this was the last data stream popped by PopFront, update the
// bytes remaining in its batch write.
- bytes_left_for_batch_write_[last_priority_popped_] -=
- static_cast<int32_t>(bytes);
+ if (fix_bytes_left_for_batch_write_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_bytes_left_for_batch_write);
+ // TODO(fayang): change this static_cast to static_cast<uint32_t> when
+ // deprecating quic_fix_bytes_left_for_batch_write.
+ bytes_left_for_batch_write_[last_priority_popped_] -=
+ std::min(bytes_left_for_batch_write_[last_priority_popped_],
+ static_cast<int32_t>(bytes));
+ } else {
+ bytes_left_for_batch_write_[last_priority_popped_] -=
+ static_cast<int32_t>(bytes);
+ }
}
}
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 fd875bccbb5..08f70b39515 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
@@ -13,6 +13,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
#include "net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h"
#include "net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h"
@@ -103,6 +104,8 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
// Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given
// priority. This is decremented with each write the stream does until it is
// done with its batch write.
+ // TODO(fayang): switch this to uint32_t when deprecating
+ // quic_fix_bytes_left_for_batch_write.
int32_t bytes_left_for_batch_write_[spdy::kV3LowestPriority + 1];
// Tracks the last priority popped for UpdateBytesForStream.
spdy::SpdyPriority last_priority_popped_;
@@ -153,6 +156,9 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
StaticStreamCollection static_stream_collection_;
spdy::WriteSchedulerType scheduler_type_;
+
+ const bool fix_bytes_left_for_batch_write_ =
+ GetQuicReloadableFlag(quic_fix_bytes_left_for_batch_write);
};
} // 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 dfaab5143dd..ba3f9d4de4a 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
@@ -295,6 +295,10 @@ bool TlsClientHandshaker::EarlyDataAccepted() const {
return SSL_early_data_accepted(ssl()) == 1;
}
+ssl_early_data_reason_t TlsClientHandshaker::EarlyDataReason() const {
+ return TlsHandshaker::EarlyDataReason();
+}
+
bool TlsClientHandshaker::ReceivedInchoateReject() const {
QUIC_BUG_IF(!one_rtt_keys_available_);
// REJ messages are a QUIC crypto feature, so TLS always returns false.
@@ -382,10 +386,16 @@ void TlsClientHandshaker::SetWriteSecret(
if (level == ENCRYPTION_FORWARD_SECURE || level == ENCRYPTION_ZERO_RTT) {
encryption_established_ = true;
}
- if (level == ENCRYPTION_FORWARD_SECURE) {
+ const bool postpone_discarding_zero_rtt_keys =
+ GetQuicReloadableFlag(quic_postpone_discarding_zero_rtt_keys);
+ if (!postpone_discarding_zero_rtt_keys &&
+ level == ENCRYPTION_FORWARD_SECURE) {
handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT);
}
TlsHandshaker::SetWriteSecret(level, cipher, write_secret);
+ if (postpone_discarding_zero_rtt_keys && level == ENCRYPTION_FORWARD_SECURE) {
+ handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT);
+ }
}
void TlsClientHandshaker::OnHandshakeConfirmed() {
@@ -456,6 +466,14 @@ void TlsClientHandshaker::CloseConnection(QuicErrorCode error,
}
void TlsClientHandshaker::FinishHandshake() {
+ // Fill crypto_negotiated_params_:
+ const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
+ if (cipher) {
+ crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher);
+ }
+ crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl());
+ crypto_negotiated_params_->peer_signature_algorithm =
+ SSL_get_peer_signature_algorithm(ssl());
if (SSL_in_early_data(ssl())) {
// SSL_do_handshake returns after sending the ClientHello if the session is
// 0-RTT-capable, which means that FinishHandshake will get called twice -
@@ -470,14 +488,6 @@ void TlsClientHandshaker::FinishHandshake() {
}
QUIC_LOG(INFO) << "Client: handshake finished";
state_ = STATE_HANDSHAKE_COMPLETE;
- // Fill crypto_negotiated_params_:
- const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
- if (cipher) {
- crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher);
- }
- crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl());
- crypto_negotiated_params_->peer_signature_algorithm =
- SSL_get_peer_signature_algorithm(ssl());
std::string error_details;
if (!ProcessTransportParameters(&error_details)) {
@@ -522,7 +532,7 @@ void TlsClientHandshaker::HandleZeroRttReject() {
DCHECK(session_cache_);
// Disable encrytion to block outgoing data until 1-RTT keys are available.
encryption_established_ = false;
- handshaker_delegate()->OnZeroRttRejected();
+ handshaker_delegate()->OnZeroRttRejected(EarlyDataReason());
SSL_reset_early_data_reject(ssl());
session_cache_->ClearEarlyData(server_id_);
AdvanceHandshake();
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 bf05ca88fb4..2a09fb83818 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
@@ -46,6 +46,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
int num_sent_client_hellos() const override;
bool IsResumption() const override;
bool EarlyDataAccepted() const override;
+ ssl_early_data_reason_t EarlyDataReason() const override;
bool ReceivedInchoateReject() const override;
int num_scup_messages_received() const override;
std::string chlo_hash() const override;
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 e2988d9a9c9..132e6365786 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
@@ -174,7 +174,6 @@ class TlsClientHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
server_id_(kServerHostname, kServerPort, false),
server_compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
- SetQuicRestartFlag(quic_enable_tls_resumption_v4, true);
SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true);
crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
std::make_unique<TestProofVerifier>(),
@@ -376,6 +375,8 @@ TEST_P(TlsClientHandshakerTest, ResumptionRejection) {
EXPECT_TRUE(stream()->one_rtt_keys_available());
EXPECT_FALSE(stream()->IsResumption());
EXPECT_FALSE(stream()->EarlyDataAccepted());
+ EXPECT_EQ(stream()->EarlyDataReason(),
+ ssl_early_data_unsupported_for_session);
}
TEST_P(TlsClientHandshakerTest, ZeroRttResumption) {
@@ -399,6 +400,9 @@ TEST_P(TlsClientHandshakerTest, ZeroRttResumption) {
// messages from the server.
stream()->CryptoConnect();
EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_NE(stream()->crypto_negotiated_params().cipher_suite, 0);
+ EXPECT_NE(stream()->crypto_negotiated_params().key_exchange_group, 0);
+ EXPECT_NE(stream()->crypto_negotiated_params().peer_signature_algorithm, 0);
// Finish the handshake with the server.
QuicConfig config;
crypto_test_utils::HandshakeWithFakeServer(
@@ -410,6 +414,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRttResumption) {
EXPECT_TRUE(stream()->one_rtt_keys_available());
EXPECT_TRUE(stream()->IsResumption());
EXPECT_TRUE(stream()->EarlyDataAccepted());
+ EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_accepted);
}
TEST_P(TlsClientHandshakerTest, ZeroRttRejection) {
@@ -458,6 +463,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRttRejection) {
EXPECT_TRUE(stream()->one_rtt_keys_available());
EXPECT_TRUE(stream()->IsResumption());
EXPECT_FALSE(stream()->EarlyDataAccepted());
+ EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_peer_declined);
}
TEST_P(TlsClientHandshakerTest, ZeroRttAndResumptionRejection) {
@@ -506,6 +512,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRttAndResumptionRejection) {
EXPECT_TRUE(stream()->one_rtt_keys_available());
EXPECT_FALSE(stream()->IsResumption());
EXPECT_FALSE(stream()->EarlyDataAccepted());
+ EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_session_not_resumed);
}
TEST_P(TlsClientHandshakerTest, ClientSendsNoSNI) {
@@ -553,16 +560,11 @@ TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) {
[kTestAlpn](const std::vector<quiche::QuicheStringPiece>& alpns) {
return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
});
-#if BORINGSSL_API_VERSION > 10
EXPECT_CALL(*server_connection_,
CloseConnection(QUIC_HANDSHAKE_FAILED,
"TLS handshake failure (ENCRYPTION_INITIAL) 120: "
"no application protocol",
_));
-#else // BORINGSSL_API_VERSION <= 10
- EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not select ALPN", _));
-#endif // BORINGSSL_API_VERSION
stream()->CryptoConnect();
crypto_test_utils::AdvanceHandshake(connection_, stream(), 0,
@@ -570,13 +572,8 @@ TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) {
EXPECT_FALSE(stream()->one_rtt_keys_available());
EXPECT_FALSE(server_stream()->one_rtt_keys_available());
-#if BORINGSSL_API_VERSION > 10
EXPECT_FALSE(stream()->encryption_established());
EXPECT_FALSE(server_stream()->encryption_established());
-#else // BORINGSSL_API_VERSION <= 10
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(server_stream()->encryption_established());
-#endif // BORINGSSL_API_VERSION
}
TEST_P(TlsClientHandshakerTest, ZeroRTTNotAttemptedOnALPNChange) {
@@ -603,6 +600,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRTTNotAttemptedOnALPNChange) {
EXPECT_TRUE(stream()->encryption_established());
EXPECT_TRUE(stream()->one_rtt_keys_available());
EXPECT_FALSE(stream()->EarlyDataAccepted());
+ EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_alpn_mismatch);
}
TEST_P(TlsClientHandshakerTest, InvalidSNI) {
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 1b200636a91..04fab15201a 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
@@ -57,6 +57,10 @@ size_t TlsHandshaker::BufferSizeLimitForLevel(EncryptionLevel level) const {
ssl(), TlsConnection::BoringEncryptionLevel(level));
}
+ssl_early_data_reason_t TlsHandshaker::EarlyDataReason() const {
+ return SSL_get_early_data_reason(ssl());
+}
+
const EVP_MD* TlsHandshaker::Prf(const SSL_CIPHER* cipher) {
return EVP_get_digestbynid(SSL_CIPHER_get_prf_nid(cipher));
}
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 3d5f1e2d26a..2b3c9fc20a1 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
@@ -44,14 +44,11 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate,
return parser_error_detail_;
}
- // From QuicCryptoStream
- virtual bool encryption_established() const = 0;
- virtual bool one_rtt_keys_available() const = 0;
- virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
- const = 0;
- virtual CryptoMessageParser* crypto_message_parser() { return this; }
- virtual HandshakeState GetHandshakeState() const = 0;
+ // The following methods provide implementations to subclasses of
+ // TlsHandshaker which use them to implement methods of QuicCryptoStream.
+ CryptoMessageParser* crypto_message_parser() { return this; }
size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
+ ssl_early_data_reason_t EarlyDataReason() const;
protected:
virtual void AdvanceHandshake() = 0;
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
deleted file mode 100644
index caf9a9c6b1b..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
+++ /dev/null
@@ -1,453 +0,0 @@
-// Copyright (c) 2017 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 <memory>
-#include <string>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h"
-#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h"
-#include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-
-namespace quic {
-namespace test {
-namespace {
-
-using ::testing::_;
-using ::testing::ElementsAreArray;
-using ::testing::Return;
-
-class TestProofVerifier : public ProofVerifier {
- public:
- TestProofVerifier()
- : verifier_(crypto_test_utils::ProofVerifierForTesting()) {}
-
- QuicAsyncStatus VerifyProof(
- const std::string& hostname,
- const uint16_t port,
- const std::string& server_config,
- QuicTransportVersion quic_version,
- quiche::QuicheStringPiece chlo_hash,
- const std::vector<std::string>& certs,
- const std::string& cert_sct,
- const std::string& signature,
- const ProofVerifyContext* context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- std::unique_ptr<ProofVerifierCallback> callback) override {
- return verifier_->VerifyProof(
- hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
- signature, context, error_details, details, std::move(callback));
- }
-
- QuicAsyncStatus VerifyCertChain(
- const std::string& hostname,
- const uint16_t port,
- const std::vector<std::string>& certs,
- const std::string& ocsp_response,
- const std::string& cert_sct,
- const ProofVerifyContext* context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- std::unique_ptr<ProofVerifierCallback> callback) override {
- if (!active_) {
- return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response,
- cert_sct, context, error_details,
- details, std::move(callback));
- }
- pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>(
- hostname, port, certs, ocsp_response, cert_sct, context, error_details,
- details, std::move(callback), verifier_.get()));
- return QUIC_PENDING;
- }
-
- std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
- return nullptr;
- }
-
- void Activate() { active_ = true; }
-
- size_t NumPendingCallbacks() const { return pending_ops_.size(); }
-
- void InvokePendingCallback(size_t n) {
- CHECK(NumPendingCallbacks() > n);
- pending_ops_[n]->Run();
- auto it = pending_ops_.begin() + n;
- pending_ops_.erase(it);
- }
-
- private:
- // Implementation of ProofVerifierCallback that fails if the callback is ever
- // run.
- class FailingProofVerifierCallback : public ProofVerifierCallback {
- public:
- void Run(bool /*ok*/,
- const std::string& /*error_details*/,
- std::unique_ptr<ProofVerifyDetails>* /*details*/) override {
- FAIL();
- }
- };
-
- class VerifyChainPendingOp {
- public:
- VerifyChainPendingOp(const std::string& hostname,
- const uint16_t port,
- const std::vector<std::string>& certs,
- const std::string& ocsp_response,
- const std::string& cert_sct,
- const ProofVerifyContext* context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- std::unique_ptr<ProofVerifierCallback> callback,
- ProofVerifier* delegate)
- : hostname_(hostname),
- port_(port),
- certs_(certs),
- ocsp_response_(ocsp_response),
- cert_sct_(cert_sct),
- context_(context),
- error_details_(error_details),
- details_(details),
- callback_(std::move(callback)),
- delegate_(delegate) {}
-
- void Run() {
- // TestProofVerifier depends on crypto_test_utils::ProofVerifierForTesting
- // running synchronously. It passes a FailingProofVerifierCallback and
- // runs the original callback after asserting that the verification ran
- // synchronously.
- QuicAsyncStatus status = delegate_->VerifyCertChain(
- hostname_, port_, certs_, ocsp_response_, cert_sct_, context_,
- error_details_, details_,
- std::make_unique<FailingProofVerifierCallback>());
- ASSERT_NE(status, QUIC_PENDING);
- callback_->Run(status == QUIC_SUCCESS, *error_details_, details_);
- }
-
- private:
- std::string hostname_;
- const uint16_t port_;
- std::vector<std::string> certs_;
- std::string ocsp_response_;
- std::string cert_sct_;
- const ProofVerifyContext* context_;
- std::string* error_details_;
- std::unique_ptr<ProofVerifyDetails>* details_;
- std::unique_ptr<ProofVerifierCallback> callback_;
- ProofVerifier* delegate_;
- };
-
- std::unique_ptr<ProofVerifier> verifier_;
- bool active_ = false;
- std::vector<std::unique_ptr<VerifyChainPendingOp>> pending_ops_;
-};
-
-class TestQuicCryptoStream : public QuicCryptoStream {
- public:
- explicit TestQuicCryptoStream(QuicSession* session)
- : QuicCryptoStream(session) {}
-
- ~TestQuicCryptoStream() override = default;
-
- virtual TlsHandshaker* handshaker() const = 0;
-
- bool encryption_established() const override {
- return handshaker()->encryption_established();
- }
-
- bool one_rtt_keys_available() const override {
- return handshaker()->one_rtt_keys_available();
- }
-
- const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
- const override {
- return handshaker()->crypto_negotiated_params();
- }
-
- CryptoMessageParser* crypto_message_parser() override {
- return handshaker()->crypto_message_parser();
- }
-
- void WriteCryptoData(EncryptionLevel level,
- quiche::QuicheStringPiece data) override {
- pending_writes_.push_back(std::make_pair(std::string(data), level));
- }
-
- void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
- void OnOneRttPacketAcknowledged() override {}
- void OnHandshakePacketSent() override {}
-
- HandshakeState GetHandshakeState() const override {
- return handshaker()->GetHandshakeState();
- }
- void SetServerApplicationStateForResumption(
- std::unique_ptr<ApplicationState> /*application_state*/) override {}
-
- const std::vector<std::pair<std::string, EncryptionLevel>>& pending_writes() {
- return pending_writes_;
- }
-
- // Sends the pending frames to |stream| and clears the array of pending
- // writes.
- void SendCryptoMessagesToPeer(QuicCryptoStream* stream) {
- QUIC_LOG(INFO) << "Sending " << pending_writes_.size() << " frames";
- // This is a minimal re-implementation of QuicCryptoStream::OnDataAvailable.
- // It doesn't work to call QuicStream::OnStreamFrame because
- // QuicCryptoStream::OnDataAvailable currently (as an implementation detail)
- // relies on the QuicConnection to know the EncryptionLevel to pass into
- // CryptoMessageParser::ProcessInput. Since the crypto messages in this test
- // never reach the framer or connection and never get encrypted/decrypted,
- // QuicCryptoStream::OnDataAvailable isn't able to call ProcessInput with
- // the correct EncryptionLevel. Instead, that can be short-circuited by
- // directly calling ProcessInput here.
- for (size_t i = 0; i < pending_writes_.size(); ++i) {
- if (!stream->crypto_message_parser()->ProcessInput(
- pending_writes_[i].first, pending_writes_[i].second)) {
- OnUnrecoverableError(stream->crypto_message_parser()->error(),
- stream->crypto_message_parser()->error_detail());
- break;
- }
- }
- pending_writes_.clear();
- }
-
- private:
- std::vector<std::pair<std::string, EncryptionLevel>> pending_writes_;
-};
-
-class MockProofHandler : public QuicCryptoClientStream::ProofHandler {
- public:
- MockProofHandler() = default;
- ~MockProofHandler() override {}
-
- MOCK_METHOD( // NOLINT(build/deprecated)
- void,
- OnProofValid,
- (const QuicCryptoClientConfig::CachedState&),
- (override));
- MOCK_METHOD( // NOLINT(build/deprecated)
- void,
- OnProofVerifyDetailsAvailable,
- (const ProofVerifyDetails&),
- (override));
-};
-
-class TestQuicCryptoClientStream : public TestQuicCryptoStream {
- public:
- explicit TestQuicCryptoClientStream(QuicSession* session)
- : TestQuicCryptoClientStream(session,
- QuicServerId("test.example.com", 443),
- std::make_unique<TestProofVerifier>()) {}
-
- TestQuicCryptoClientStream(QuicSession* session,
- const QuicServerId& server_id,
- std::unique_ptr<ProofVerifier> proof_verifier)
- : TestQuicCryptoStream(session),
- crypto_config_(std::move(proof_verifier),
- /*session_cache*/ nullptr),
- handshaker_(new TlsClientHandshaker(
- server_id,
- this,
- session,
- crypto_test_utils::ProofVerifyContextForTesting(),
- &crypto_config_,
- &proof_handler_,
- /*has_application_state = */ false)) {}
-
- ~TestQuicCryptoClientStream() override = default;
-
- TlsHandshaker* handshaker() const override { return handshaker_.get(); }
- TlsClientHandshaker* client_handshaker() const { return handshaker_.get(); }
- const MockProofHandler& proof_handler() { return proof_handler_; }
- void OnHandshakeDoneReceived() override {}
-
- bool CryptoConnect() { return handshaker_->CryptoConnect(); }
-
- TestProofVerifier* GetTestProofVerifier() const {
- return static_cast<TestProofVerifier*>(crypto_config_.proof_verifier());
- }
-
- private:
- MockProofHandler proof_handler_;
- QuicCryptoClientConfig crypto_config_;
- std::unique_ptr<TlsClientHandshaker> handshaker_;
-};
-
-class TestTlsServerHandshaker : public TlsServerHandshaker {
- public:
- TestTlsServerHandshaker(QuicSession* session,
- const QuicCryptoServerConfig& crypto_config,
- TestQuicCryptoStream* test_stream)
- : TlsServerHandshaker(session, crypto_config),
- test_stream_(test_stream) {}
-
- void WriteCryptoData(EncryptionLevel level,
- quiche::QuicheStringPiece data) override {
- test_stream_->WriteCryptoData(level, data);
- }
-
- private:
- TestQuicCryptoStream* test_stream_;
-};
-
-class TestQuicCryptoServerStream : public TestQuicCryptoStream {
- public:
- TestQuicCryptoServerStream(QuicSession* session)
- : TestQuicCryptoStream(session),
- crypto_config_(QuicCryptoServerConfig::TESTING,
- QuicRandom::GetInstance(),
- std::make_unique<FakeProofSource>(),
- KeyExchangeSource::Default()),
- handshaker_(
- new TestTlsServerHandshaker(session, crypto_config_, this)) {}
-
- ~TestQuicCryptoServerStream() override = default;
-
- void CancelOutstandingCallbacks() {
- handshaker_->CancelOutstandingCallbacks();
- }
-
- void OnPacketDecrypted(EncryptionLevel level) override {
- handshaker_->OnPacketDecrypted(level);
- }
- void OnHandshakeDoneReceived() override { DCHECK(false); }
-
- TlsHandshaker* handshaker() const override { return handshaker_.get(); }
-
- FakeProofSource* GetFakeProofSource() const {
- return static_cast<FakeProofSource*>(crypto_config_.proof_source());
- }
-
- private:
- QuicCryptoServerConfig crypto_config_;
- std::unique_ptr<TlsServerHandshaker> handshaker_;
-};
-
-void ExchangeHandshakeMessages(TestQuicCryptoStream* client,
- TestQuicCryptoServerStream* server) {
- while (!client->pending_writes().empty() ||
- !server->pending_writes().empty()) {
- client->SendCryptoMessagesToPeer(server);
- server->SendCryptoMessagesToPeer(client);
- }
-}
-
-class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
- public:
- TlsHandshakerTest()
- : version_(GetParam()),
- client_conn_(new MockQuicConnection(&conn_helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT,
- {version_})),
- server_conn_(new MockQuicConnection(&conn_helper_,
- &alarm_factory_,
- Perspective::IS_SERVER,
- {version_})),
- client_session_(client_conn_, /*create_mock_crypto_stream=*/false),
- server_session_(server_conn_, /*create_mock_crypto_stream=*/false) {
- client_stream_ = new TestQuicCryptoClientStream(&client_session_);
- client_session_.SetCryptoStream(client_stream_);
- server_stream_ = new TestQuicCryptoServerStream(&server_session_);
- server_session_.SetCryptoStream(server_stream_);
- client_session_.Initialize();
- server_session_.Initialize();
- EXPECT_FALSE(client_stream_->encryption_established());
- EXPECT_FALSE(client_stream_->one_rtt_keys_available());
- EXPECT_FALSE(server_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->one_rtt_keys_available());
- const std::string default_alpn =
- AlpnForVersion(client_session_.connection()->version());
- ON_CALL(client_session_, GetAlpnsToOffer())
- .WillByDefault(Return(std::vector<std::string>({default_alpn})));
- ON_CALL(server_session_, SelectAlpn(_))
- .WillByDefault(
- [default_alpn](
- const std::vector<quiche::QuicheStringPiece>& alpns) {
- return std::find(alpns.begin(), alpns.end(), default_alpn);
- });
- }
-
- void ExpectHandshakeSuccessful() {
- EXPECT_TRUE(client_stream_->one_rtt_keys_available());
- EXPECT_TRUE(client_stream_->encryption_established());
- EXPECT_TRUE(server_stream_->one_rtt_keys_available());
- EXPECT_TRUE(server_stream_->encryption_established());
- EXPECT_EQ(HANDSHAKE_COMPLETE, client_stream_->GetHandshakeState());
- EXPECT_EQ(HANDSHAKE_CONFIRMED, server_stream_->GetHandshakeState());
-
- const auto& client_crypto_params =
- client_stream_->crypto_negotiated_params();
- const auto& server_crypto_params =
- server_stream_->crypto_negotiated_params();
- // The TLS params should be filled in on the client.
- EXPECT_NE(0, client_crypto_params.cipher_suite);
- EXPECT_NE(0, client_crypto_params.key_exchange_group);
- EXPECT_NE(0, client_crypto_params.peer_signature_algorithm);
-
- // The cipher suite and key exchange group should match on the client and
- // server.
- EXPECT_EQ(client_crypto_params.cipher_suite,
- server_crypto_params.cipher_suite);
- EXPECT_EQ(client_crypto_params.key_exchange_group,
- server_crypto_params.key_exchange_group);
- // We don't support client certs on the server (yet), so the server
- // shouldn't have a peer signature algorithm to report.
- EXPECT_EQ(0, server_crypto_params.peer_signature_algorithm);
- }
-
- ParsedQuicVersion version_;
- MockQuicConnectionHelper conn_helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicConnection* client_conn_;
- MockQuicConnection* server_conn_;
- MockQuicSession client_session_;
- MockQuicSession server_session_;
-
- TestQuicCryptoClientStream* client_stream_;
- TestQuicCryptoServerStream* server_stream_;
-};
-
-std::vector<ParsedQuicVersion> AllSupportedTlsVersions() {
- std::vector<ParsedQuicVersion> tls_versions;
- for (const ParsedQuicVersion& version : AllSupportedVersions()) {
- if (version.handshake_protocol == PROTOCOL_TLS1_3) {
- tls_versions.push_back(version);
- }
- }
- return tls_versions;
-}
-
-INSTANTIATE_TEST_SUITE_P(TlsHandshakerTests,
- TlsHandshakerTest,
- ::testing::ValuesIn(AllSupportedTlsVersions()),
- ::testing::PrintToStringParamName());
-
-TEST_P(TlsHandshakerTest, CryptoHandshake) {
- EXPECT_FALSE(client_conn_->IsHandshakeComplete());
- EXPECT_FALSE(server_conn_->IsHandshakeComplete());
-
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable);
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ExpectHandshakeSuccessful();
-}
-
-} // namespace
-} // namespace test
-} // namespace quic
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 46e4b81704f..a8f926ea457 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
@@ -175,6 +175,10 @@ void TlsServerHandshaker::OnConnectionClosed(QuicErrorCode /*error*/,
state_ = STATE_CONNECTION_CLOSED;
}
+ssl_early_data_reason_t TlsServerHandshaker::EarlyDataReason() const {
+ return TlsHandshaker::EarlyDataReason();
+}
+
bool TlsServerHandshaker::encryption_established() const {
return encryption_established_;
}
@@ -287,6 +291,19 @@ bool TlsServerHandshaker::ProcessTransportParameters(
// Notify QuicConnectionDebugVisitor.
session()->connection()->OnTransportParametersReceived(client_params);
+ // Chrome clients before 86.0.4233.0 did not send the
+ // key_update_not_yet_supported transport parameter, but they did send a
+ // Google-internal transport parameter with identifier 0x4751. We treat
+ // reception of 0x4751 as having received key_update_not_yet_supported to
+ // ensure we do not use key updates with those older clients.
+ // TODO(dschinazi) remove this workaround once all of our QUIC+TLS Finch
+ // experiments have a min_version greater than 86.0.4233.0.
+ if (client_params.custom_parameters.find(
+ static_cast<TransportParameters::TransportParameterId>(0x4751)) !=
+ client_params.custom_parameters.end()) {
+ client_params.key_update_not_yet_supported = true;
+ }
+
// When interoperating with non-Google implementations that do not send
// the version extension, set it to what we expect.
if (client_params.version == 0) {
@@ -388,7 +405,10 @@ void TlsServerHandshaker::FinishHandshake() {
return;
}
- QUIC_DLOG(INFO) << "Server: handshake finished";
+ ssl_early_data_reason_t reason_code = EarlyDataReason();
+ QUIC_DLOG(INFO) << "Server: handshake finished. Early data reason "
+ << reason_code << " ("
+ << CryptoUtils::EarlyDataReasonToString(reason_code) << ")";
state_ = STATE_HANDSHAKE_COMPLETE;
one_rtt_keys_available_ = true;
@@ -442,7 +462,6 @@ int TlsServerHandshaker::SessionTicketSeal(uint8_t* out,
size_t* out_len,
size_t max_out_len,
quiche::QuicheStringPiece in) {
- QUIC_CODE_COUNT(quic_tls_ticket_seal);
DCHECK(proof_source_->GetTicketCrypter());
std::vector<uint8_t> ticket = proof_source_->GetTicketCrypter()->Encrypt(in);
if (max_out_len < ticket.size()) {
@@ -462,7 +481,6 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
size_t* out_len,
size_t max_out_len,
quiche::QuicheStringPiece in) {
- QUIC_CODE_COUNT(quic_tls_ticket_open);
DCHECK(proof_source_->GetTicketCrypter());
if (!ticket_decryption_callback_) {
@@ -496,7 +514,6 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
memcpy(out, decrypted_session_ticket_.data(),
decrypted_session_ticket_.size());
*out_len = decrypted_session_ticket_.size();
- QUIC_RESTART_FLAG_COUNT(quic_enable_tls_resumption_v4);
return ssl_ticket_aead_success;
}
@@ -532,19 +549,8 @@ int TlsServerHandshaker::SelectCertificate(int* out_alert) {
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
- std::vector<CRYPTO_BUFFER*> certs;
- certs.resize(chain->certs.size());
- for (size_t i = 0; i < certs.size(); i++) {
- certs[i] = CRYPTO_BUFFER_new(
- reinterpret_cast<const uint8_t*>(chain->certs[i].data()),
- chain->certs[i].length(), nullptr);
- }
-
- tls_connection_.SetCertChain(certs);
-
- for (size_t i = 0; i < certs.size(); i++) {
- CRYPTO_BUFFER_free(certs[i]);
- }
+ CryptoBuffers cert_buffers = chain->ToCryptoBuffers();
+ tls_connection_.SetCertChain(cert_buffers.value);
std::string error_details;
if (!ProcessTransportParameters(&error_details)) {
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 b0212db06ad..063e5ca827b 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
@@ -56,6 +56,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
const ProofSource::Details* ProofSourceDetails() const override;
// From QuicCryptoServerStreamBase and TlsHandshaker
+ ssl_early_data_reason_t EarlyDataReason() const override;
bool encryption_established() const override;
bool one_rtt_keys_available() const override;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
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 05b7d686f67..295af9d6ee7 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
@@ -42,13 +42,13 @@ namespace {
const char kServerHostname[] = "test.example.com";
const uint16_t kServerPort = 443;
-class TlsServerHandshakerTest : public QuicTest {
+class TlsServerHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
public:
TlsServerHandshakerTest()
: server_compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- server_id_(kServerHostname, kServerPort, false) {
- SetQuicRestartFlag(quic_enable_tls_resumption_v4, true);
+ server_id_(kServerHostname, kServerPort, false),
+ supported_versions_({GetParam()}) {
SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true);
client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
crypto_test_utils::ProofVerifierForTesting(),
@@ -223,21 +223,26 @@ class TlsServerHandshakerTest : public QuicTest {
std::pair<size_t, size_t> moved_messages_counts_ = {0, 0};
// Which QUIC versions the client and server support.
- ParsedQuicVersionVector supported_versions_ = AllSupportedVersionsWithTls();
+ ParsedQuicVersionVector supported_versions_;
};
-TEST_F(TlsServerHandshakerTest, NotInitiallyConected) {
+INSTANTIATE_TEST_SUITE_P(TlsServerHandshakerTests,
+ TlsServerHandshakerTest,
+ ::testing::ValuesIn(AllSupportedVersionsWithTls()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(TlsServerHandshakerTest, NotInitiallyConected) {
EXPECT_FALSE(server_stream()->encryption_established());
EXPECT_FALSE(server_stream()->one_rtt_keys_available());
}
-TEST_F(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) {
+TEST_P(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) {
CompleteCryptoHandshake();
EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol());
ExpectHandshakeSuccessful();
}
-TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) {
+TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) {
EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
// Enable FakeProofSource to capture call to ComputeTlsSignature and run it
@@ -255,7 +260,7 @@ TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) {
ExpectHandshakeSuccessful();
}
-TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) {
+TEST_P(TlsServerHandshakerTest, CancelPendingProofSource) {
EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
// Enable FakeProofSource to capture call to ComputeTlsSignature and run it
@@ -271,7 +276,7 @@ TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) {
proof_source_->InvokePendingCallback(0);
}
-TEST_F(TlsServerHandshakerTest, ExtractSNI) {
+TEST_P(TlsServerHandshakerTest, ExtractSNI) {
CompleteCryptoHandshake();
ExpectHandshakeSuccessful();
@@ -279,7 +284,7 @@ TEST_F(TlsServerHandshakerTest, ExtractSNI) {
"test.example.com");
}
-TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) {
+TEST_P(TlsServerHandshakerTest, ConnectionClosedOnTlsError) {
EXPECT_CALL(*server_connection_,
CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
@@ -297,11 +302,10 @@ TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) {
EXPECT_FALSE(server_stream()->one_rtt_keys_available());
}
-TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) {
+TEST_P(TlsServerHandshakerTest, ClientSendingBadALPN) {
const std::string kTestBadClientAlpn = "bad-client-alpn";
EXPECT_CALL(*client_session_, GetAlpnsToOffer())
.WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn})));
-#if BORINGSSL_API_VERSION > 10
EXPECT_CALL(*server_connection_,
CloseConnection(QUIC_HANDSHAKE_FAILED,
"TLS handshake failure (ENCRYPTION_INITIAL) 120: "
@@ -314,26 +318,9 @@ TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) {
EXPECT_FALSE(client_stream()->encryption_established());
EXPECT_FALSE(server_stream()->one_rtt_keys_available());
EXPECT_FALSE(server_stream()->encryption_established());
-#else // BORINGSSL_API_VERSION <=10
- EXPECT_CALL(
- *client_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _));
- EXPECT_CALL(*server_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not receive a known ALPN", _));
-
- // Process two flights of handshake messages.
- AdvanceHandshakeWithFakeClient();
- AdvanceHandshakeWithFakeClient();
-
- EXPECT_FALSE(client_stream()->one_rtt_keys_available());
- EXPECT_TRUE(client_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->one_rtt_keys_available());
- EXPECT_TRUE(server_stream()->encryption_established());
-#endif // BORINGSSL_API_VERSION
}
-TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) {
+TEST_P(TlsServerHandshakerTest, CustomALPNNegotiation) {
EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
@@ -357,7 +344,7 @@ TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) {
ExpectHandshakeSuccessful();
}
-TEST_F(TlsServerHandshakerTest, RejectInvalidSNI) {
+TEST_P(TlsServerHandshakerTest, RejectInvalidSNI) {
server_id_ = QuicServerId("invalid!.example.com", kServerPort, false);
InitializeFakeClient();
static_cast<TlsClientHandshaker*>(
@@ -370,7 +357,7 @@ TEST_F(TlsServerHandshakerTest, RejectInvalidSNI) {
EXPECT_FALSE(server_stream()->one_rtt_keys_available());
}
-TEST_F(TlsServerHandshakerTest, Resumption) {
+TEST_P(TlsServerHandshakerTest, Resumption) {
// Do the first handshake
InitializeFakeClient();
CompleteCryptoHandshake();
@@ -389,7 +376,7 @@ TEST_F(TlsServerHandshakerTest, Resumption) {
EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
-TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
+TEST_P(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
// Do the first handshake
InitializeFakeClient();
CompleteCryptoHandshake();
@@ -412,7 +399,7 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
-TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
+TEST_P(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
// Do the first handshake
InitializeFakeClient();
CompleteCryptoHandshake();
@@ -429,7 +416,7 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
-TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) {
+TEST_P(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) {
// Do the first handshake
InitializeFakeClient();
CompleteCryptoHandshake();
@@ -453,7 +440,7 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) {
EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
-TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) {
+TEST_P(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) {
InitializeServerConfigWithFailingProofSource();
InitializeServer();
InitializeFakeClient();
@@ -465,7 +452,7 @@ TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) {
EXPECT_EQ(moved_messages_counts_.second, 0u);
}
-TEST_F(TlsServerHandshakerTest, ZeroRttResumption) {
+TEST_P(TlsServerHandshakerTest, ZeroRttResumption) {
std::vector<uint8_t> application_state = {0, 1, 2, 3};
// Do the first handshake
@@ -488,7 +475,7 @@ TEST_F(TlsServerHandshakerTest, ZeroRttResumption) {
EXPECT_TRUE(server_stream()->IsZeroRtt());
}
-TEST_F(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) {
+TEST_P(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) {
std::vector<uint8_t> original_application_state = {1, 2};
std::vector<uint8_t> new_application_state = {3, 4};
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 b017a84fcbf..7b2b32f894f 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
@@ -76,20 +76,18 @@ void UberReceivedPacketManager::MaybeUpdateAckTimeout(
bool should_last_packet_instigate_acks,
EncryptionLevel decrypted_packet_level,
QuicPacketNumber last_received_packet_number,
- QuicTime time_of_last_received_packet,
QuicTime now,
const RttStats* rtt_stats) {
if (!supports_multiple_packet_number_spaces_) {
received_packet_managers_[0].MaybeUpdateAckTimeout(
- should_last_packet_instigate_acks, last_received_packet_number,
- time_of_last_received_packet, now, rtt_stats);
+ should_last_packet_instigate_acks, last_received_packet_number, now,
+ rtt_stats);
return;
}
received_packet_managers_[QuicUtils::GetPacketNumberSpace(
decrypted_packet_level)]
.MaybeUpdateAckTimeout(should_last_packet_instigate_acks,
- last_received_packet_number,
- time_of_last_received_packet, now, rtt_stats);
+ last_received_packet_number, now, rtt_stats);
}
void UberReceivedPacketManager::ResetAckStates(
@@ -216,20 +214,20 @@ void UberReceivedPacketManager::set_max_ack_ranges(size_t max_ack_ranges) {
}
}
-void UberReceivedPacketManager::set_max_ack_delay(
- QuicTime::Delta max_ack_delay) {
- if (!supports_multiple_packet_number_spaces_) {
- received_packet_managers_[0].set_local_max_ack_delay(max_ack_delay);
- return;
- }
- received_packet_managers_[APPLICATION_DATA].set_local_max_ack_delay(
- max_ack_delay);
-}
-
void UberReceivedPacketManager::set_save_timestamps(bool save_timestamps) {
for (auto& received_packet_manager : received_packet_managers_) {
received_packet_manager.set_save_timestamps(save_timestamps);
}
}
+void UberReceivedPacketManager::OnAckFrequencyFrame(
+ const QuicAckFrequencyFrame& frame) {
+ if (!supports_multiple_packet_number_spaces_) {
+ QUIC_BUG << "Received AckFrequencyFrame when multiple packet number spaces "
+ "is not supported";
+ return;
+ }
+ received_packet_managers_[APPLICATION_DATA].OnAckFrequencyFrame(frame);
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h
index 9cfa247130c..17b5e268063 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_
#define QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
namespace quic {
@@ -46,7 +47,6 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager {
void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks,
EncryptionLevel decrypted_packet_level,
QuicPacketNumber last_received_packet_number,
- QuicTime time_of_last_received_packet,
QuicTime now,
const RttStats* rtt_stats);
@@ -90,8 +90,7 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager {
void set_max_ack_ranges(size_t max_ack_ranges);
- // Set the max ack delay to use for application data.
- void set_max_ack_delay(QuicTime::Delta max_ack_delay);
+ void OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame);
void set_save_timestamps(bool save_timestamps);
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 1b5a1966fc2..b7063d2fede 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
@@ -18,20 +18,6 @@ namespace test {
class UberReceivedPacketManagerPeer {
public:
- static void SetAckMode(UberReceivedPacketManager* manager, AckMode ack_mode) {
- for (auto& received_packet_manager : manager->received_packet_managers_) {
- received_packet_manager.ack_mode_ = ack_mode;
- }
- }
-
- static void SetFastAckAfterQuiescence(UberReceivedPacketManager* manager,
- bool fast_ack_after_quiescence) {
- for (auto& received_packet_manager : manager->received_packet_managers_) {
- received_packet_manager.fast_ack_after_quiescence_ =
- fast_ack_after_quiescence;
- }
- }
-
static void SetAckDecimationDelay(UberReceivedPacketManager* manager,
float ack_decimation_delay) {
for (auto& received_packet_manager : manager->received_packet_managers_) {
@@ -99,7 +85,7 @@ class UberReceivedPacketManagerTest : public QuicTest {
manager_->MaybeUpdateAckTimeout(
should_last_packet_instigate_acks, decrypted_packet_level,
QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
- clock_.ApproximateNow(), &rtt_stats_);
+ &rtt_stats_);
}
void CheckAckTimeout(QuicTime time) {
@@ -315,8 +301,6 @@ TEST_F(UberReceivedPacketManagerTest, AckSentEveryNthPacket) {
TEST_F(UberReceivedPacketManagerTest, AckDecimationReducesAcks) {
EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
- ACK_DECIMATION_WITH_REORDERING);
// Start ack decimation from 10th packet.
manager_->set_min_received_before_ack_decimation(10);
@@ -348,59 +332,8 @@ TEST_F(UberReceivedPacketManagerTest, AckDecimationReducesAcks) {
CheckAckTimeout(clock_.ApproximateNow());
}
-TEST_F(UberReceivedPacketManagerTest, SendDelayedAfterQuiescence) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(),
- true);
- // The beginning of the connection counts as quiescence.
- QuicTime ack_time =
- clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
-
- RecordPacketReceipt(1, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 1);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Process another packet immediately after sending the ack and expect the
- // ack timeout to be set delayed ack time in the future.
- ack_time = clock_.ApproximateNow() + kDelayedAckTime;
- RecordPacketReceipt(2, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 2);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(kDelayedAckTime);
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(3, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 3);
- CheckAckTimeout(ack_time);
-}
-
-TEST_F(UberReceivedPacketManagerTest, SendDelayedMaxAckDelay) {
- EXPECT_FALSE(HasPendingAck());
- QuicTime::Delta max_ack_delay = QuicTime::Delta::FromMilliseconds(100);
- manager_->set_max_ack_delay(max_ack_delay);
- QuicTime ack_time = clock_.ApproximateNow() + max_ack_delay;
-
- RecordPacketReceipt(1, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 1);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(max_ack_delay);
- CheckAckTimeout(clock_.ApproximateNow());
-}
-
TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) {
EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
// The ack time should be based on min_rtt * 1/4, since it's less than the
// default delayed ack time.
QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
@@ -431,76 +364,6 @@ TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) {
}
TEST_F(UberReceivedPacketManagerTest,
- SendDelayedAckAckDecimationAfterQuiescence) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
- UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(),
- true);
- // The beginning of the connection counts as quiescence.
- QuicTime ack_time =
- clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(1, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 1);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Process another packet immedately after sending the ack and expect the
- // ack timeout to be set delayed ack time in the future.
- ack_time = clock_.ApproximateNow() + kDelayedAckTime;
- RecordPacketReceipt(2, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 2);
- CheckAckTimeout(ack_time);
- // Simulate delayed ack alarm firing.
- clock_.AdvanceTime(kDelayedAckTime);
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(3, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, 3);
- CheckAckTimeout(ack_time);
- // Process enough packets to get into ack decimation behavior.
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
- EXPECT_FALSE(HasPendingAck());
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (uint64_t i = 1; i < 10; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
- }
- CheckAckTimeout(clock_.ApproximateNow());
-
- // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
- RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
- CheckAckTimeout(ack_time);
-}
-
-TEST_F(UberReceivedPacketManagerTest,
SendDelayedAckDecimationUnlimitedAggregation) {
EXPECT_FALSE(HasPendingAck());
QuicConfig config;
@@ -543,7 +406,6 @@ TEST_F(UberReceivedPacketManagerTest,
TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125);
// The ack time should be based on min_rtt/8, since it's less than the
@@ -575,190 +437,6 @@ TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) {
CheckAckTimeout(clock_.ApproximateNow());
}
-TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
- ACK_DECIMATION_WITH_REORDERING);
-
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
-
- // Receive one packet out of order and then the rest in order.
- // The loop leaves a one packet gap between acks sent to simulate some loss.
- for (int j = 0; j < 3; ++j) {
- // Process packet 10 first and ensure the timeout is one eighth min_rtt.
- RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11),
- clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11));
- ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11),
- clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck,
- kFirstDecimatedPacket + i + (j * 11));
- }
- CheckAckTimeout(clock_.ApproximateNow());
- }
-}
-
-TEST_F(UberReceivedPacketManagerTest,
- SendDelayedAckDecimationWithLargeReordering) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
- ACK_DECIMATION_WITH_REORDERING);
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
-
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
-
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
-
- RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19);
- ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 1; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
- }
- CheckAckTimeout(clock_.ApproximateNow());
-
- // The next packet received in order will cause an immediate ack, because it
- // fills a hole.
- RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
- CheckAckTimeout(clock_.ApproximateNow());
-}
-
-TEST_F(UberReceivedPacketManagerTest,
- SendDelayedAckDecimationWithReorderingEighthRtt) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
- ACK_DECIMATION_WITH_REORDERING);
- UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125);
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
-
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
-
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
-
- // Process packet 10 first and ensure the timeout is one eighth min_rtt.
- RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 1; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket);
- }
- CheckAckTimeout(clock_.ApproximateNow());
-}
-
-TEST_F(UberReceivedPacketManagerTest,
- SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
- if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) {
- return;
- }
- EXPECT_FALSE(HasPendingAck());
- UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
- ACK_DECIMATION_WITH_REORDERING);
- UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125);
-
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
- // Process all the packets in order so there aren't missing packets.
- uint64_t kFirstDecimatedPacket = 101;
- for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
- RecordPacketReceipt(i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, i);
- if (i % 2 == 0) {
- // Ack every 2 packets by default.
- CheckAckTimeout(clock_.ApproximateNow());
- } else {
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
- }
- }
-
- RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
- CheckAckTimeout(ack_time);
-
- RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19);
- CheckAckTimeout(ack_time);
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 1; i < 9; ++i) {
- RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
- }
- CheckAckTimeout(clock_.ApproximateNow());
-
- // The next packet received in order will cause an immediate ack, because it
- // fills a hole.
- RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
- MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
- CheckAckTimeout(clock_.ApproximateNow());
-}
-
TEST_F(UberReceivedPacketManagerTest,
DontWaitForPacketsBeforeMultiplePacketNumberSpaces) {
manager_->EnableMultiplePacketNumberSpacesSupport();
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h
new file mode 100644
index 00000000000..0df0c4050be
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h
@@ -0,0 +1,25 @@
+// Copyright 2020 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_PLATFORM_API_QUIC_TESTVALUE_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_TESTVALUE_H_
+
+#include "net/quic/platform/impl/quic_testvalue_impl.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+
+// Interface allowing injection of test-specific code in production codepaths.
+// |label| is an arbitrary value identifying the location, and |var| is a
+// pointer to the value to be modified.
+//
+// Note that this method does nothing in Chromium.
+template <class T>
+void AdjustTestValue(quiche::QuicheStringPiece label, T* var) {
+ AdjustTestValueImpl(label, var);
+}
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_API_QUIC_TESTVALUE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h
index 2b1f9c3fbc5..10307efc298 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h
@@ -20,6 +20,10 @@ inline bool GetGooglePacketHeadersFromControlMessage(
packet_headers_len);
}
+inline void SetGoogleSocketOptions(int fd) {
+ SetGoogleSocketOptionsImpl(fd);
+}
+
} // namespace quic
#endif // QUICHE_QUIC_PLATFORM_API_QUIC_UDP_SOCKET_PLATFORM_API_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc
index 9c2f1382887..fe855765940 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc
@@ -109,15 +109,9 @@ TEST_F(QuicTransportClientSessionTest, SuccessfulConnection) {
EXPECT_TRUE(session_->IsSessionReady());
QuicStream* client_indication_stream;
- if (session_->remove_zombie_streams()) {
- client_indication_stream =
- QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()]
- .get();
- } else {
- client_indication_stream = QuicSessionPeer::zombie_streams(
- session_.get())[ClientIndicationStream()]
- .get();
- }
+ client_indication_stream =
+ QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()]
+ .get();
ASSERT_TRUE(client_indication_stream != nullptr);
const std::string client_indication = DataInStream(client_indication_stream);
const std::string expected_client_indication{
@@ -141,15 +135,9 @@ TEST_F(QuicTransportClientSessionTest, SuccessfulConnectionWithPath) {
EXPECT_TRUE(session_->IsSessionReady());
QuicStream* client_indication_stream;
- if (session_->remove_zombie_streams()) {
- client_indication_stream =
- QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()]
- .get();
- } else {
- client_indication_stream = QuicSessionPeer::zombie_streams(
- session_.get())[ClientIndicationStream()]
- .get();
- }
+ client_indication_stream =
+ QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()]
+ .get();
ASSERT_TRUE(client_indication_stream != nullptr);
const std::string client_indication = DataInStream(client_indication_stream);
const std::string expected_client_indication{
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
index 6f9c8c6e837..1949df17a85 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
@@ -210,26 +210,6 @@ void QuicConnectionPeer::ReInitializeMtuDiscoverer(
}
// static
-void QuicConnectionPeer::SetAckMode(QuicConnection* connection,
- AckMode ack_mode) {
- for (auto& received_packet_manager :
- connection->uber_received_packet_manager_.received_packet_managers_) {
- received_packet_manager.ack_mode_ = ack_mode;
- }
-}
-
-// static
-void QuicConnectionPeer::SetFastAckAfterQuiescence(
- QuicConnection* connection,
- bool fast_ack_after_quiescence) {
- for (auto& received_packet_manager :
- connection->uber_received_packet_manager_.received_packet_managers_) {
- received_packet_manager.fast_ack_after_quiescence_ =
- fast_ack_after_quiescence;
- }
-}
-
-// static
void QuicConnectionPeer::SetAckDecimationDelay(QuicConnection* connection,
float ack_decimation_delay) {
for (auto& received_packet_manager :
@@ -392,5 +372,12 @@ size_t QuicConnectionPeer::NumUndecryptablePackets(QuicConnection* connection) {
return connection->undecryptable_packets_.size();
}
+// static
+const QuicCircularDeque<std::pair<QuicPathFrameBuffer, QuicSocketAddress>>&
+QuicConnectionPeer::pending_path_challenge_payloads(
+ QuicConnection* connection) {
+ return connection->pending_path_challenge_payloads_;
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
index 01d16f2ca68..b470653b793 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
@@ -102,9 +102,6 @@ class QuicConnectionPeer {
QuicConnection* connection,
QuicPacketCount packets_between_probes_base,
QuicPacketNumber next_probe_at);
- static void SetAckMode(QuicConnection* connection, AckMode ack_mode);
- static void SetFastAckAfterQuiescence(QuicConnection* connection,
- bool fast_ack_after_quiescence);
static void SetAckDecimationDelay(QuicConnection* connection,
float ack_decimation_delay);
static bool HasRetransmittableFrames(QuicConnection* connection,
@@ -156,6 +153,10 @@ class QuicConnectionPeer {
const QuicConnectionId& server_connection_id);
static size_t NumUndecryptablePackets(QuicConnection* connection);
+
+ static const QuicCircularDeque<
+ std::pair<QuicPathFrameBuffer, QuicSocketAddress>>&
+ pending_path_challenge_payloads(QuicConnection* connection);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc
index 151575a0db0..f94620bd5d5 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc
@@ -111,7 +111,9 @@ SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames(
bool success = creator->AddFrame(frame, NOT_RETRANSMISSION);
DCHECK(success);
}
- creator->SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
+ const bool success = creator->SerializePacket(
+ QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
+ DCHECK(success);
SerializedPacket packet = std::move(creator->packet_);
// The caller takes ownership of the QuicEncryptedPacket.
creator->packet_.encrypted_buffer = nullptr;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
index 68236917921..05d74d75701 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
@@ -137,12 +137,6 @@ const QuicSession::ClosedStreams& QuicSessionPeer::closed_streams(
}
// static
-QuicSession::ZombieStreamMap& QuicSessionPeer::zombie_streams(
- QuicSession* session) {
- return session->zombie_streams_;
-}
-
-// static
void QuicSessionPeer::ActivateStream(QuicSession* session,
std::unique_ptr<QuicStream> stream) {
return session->ActivateStream(std::move(stream));
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
index 1366ddbdbec..ffd6c6f300f 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
@@ -58,7 +58,6 @@ class QuicSessionPeer {
GetLocallyClosedStreamsHighestOffset(QuicSession* session);
static QuicSession::StreamMap& stream_map(QuicSession* session);
static const QuicSession::ClosedStreams& closed_streams(QuicSession* session);
- static QuicSession::ZombieStreamMap& zombie_streams(QuicSession* session);
static void ActivateStream(QuicSession* session,
std::unique_ptr<QuicStream> stream);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc
index 85a86b70bca..f311079a350 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc
@@ -252,7 +252,7 @@ void ImmediateGoAwaySession::OnNewEncryptionKeyAvailable(
QuicSimpleServerSession::OnNewEncryptionKeyAvailable(level,
std::move(encrypter));
if (VersionUsesHttp3(transport_version())) {
- if (IsEncryptionEstablished() && !http3_goaway_sent()) {
+ if (IsEncryptionEstablished() && !goaway_sent()) {
SendHttp3GoAway();
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
index 7ee037a38a6..ed7dc7592f3 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
@@ -14,6 +14,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
@@ -27,6 +28,7 @@
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_error_code_wrappers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
@@ -583,7 +585,7 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket packet) {
OnPacketSent(packet.encryption_level, packet.transmission_type);
QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent(
&packet, clock_.ApproximateNow(), NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
+ HAS_RETRANSMITTABLE_DATA, true);
}
MockQuicSession::MockQuicSession(QuicConnection* connection)
@@ -643,6 +645,10 @@ MockQuicCryptoStream::MockQuicCryptoStream(QuicSession* session)
MockQuicCryptoStream::~MockQuicCryptoStream() {}
+ssl_early_data_reason_t MockQuicCryptoStream::EarlyDataReason() const {
+ return ssl_early_data_unknown;
+}
+
bool MockQuicCryptoStream::encryption_established() const {
return false;
}
@@ -1309,5 +1315,207 @@ QuicMemSlice MemSliceFromString(quiche::QuicheStringPiece data) {
return QuicMemSlice(std::move(buffer), data.size());
}
+bool TaggingEncrypter::EncryptPacket(
+ uint64_t /*packet_number*/,
+ quiche::QuicheStringPiece /*associated_data*/,
+ quiche::QuicheStringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) {
+ const size_t len = plaintext.size() + kTagSize;
+ if (max_output_length < len) {
+ return false;
+ }
+ // Memmove is safe for inplace encryption.
+ memmove(output, plaintext.data(), plaintext.size());
+ output += plaintext.size();
+ memset(output, tag_, kTagSize);
+ *output_length = len;
+ return true;
+}
+
+bool TaggingDecrypter::DecryptPacket(
+ uint64_t /*packet_number*/,
+ quiche::QuicheStringPiece /*associated_data*/,
+ quiche::QuicheStringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t /*max_output_length*/) {
+ if (ciphertext.size() < kTagSize) {
+ return false;
+ }
+ if (!CheckTag(ciphertext, GetTag(ciphertext))) {
+ return false;
+ }
+ *output_length = ciphertext.size() - kTagSize;
+ memcpy(output, ciphertext.data(), *output_length);
+ return true;
+}
+
+bool TaggingDecrypter::CheckTag(quiche::QuicheStringPiece ciphertext,
+ uint8_t tag) {
+ for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) {
+ if (ciphertext.data()[i] != tag) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TestPacketWriter::TestPacketWriter(ParsedQuicVersion version,
+ MockClock* clock,
+ Perspective perspective)
+ : version_(version),
+ framer_(SupportedVersions(version_),
+ QuicUtils::InvertPerspective(perspective)),
+ clock_(clock) {
+ QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
+ TestConnectionId());
+ framer_.framer()->SetInitialObfuscators(TestConnectionId());
+
+ for (int i = 0; i < 128; ++i) {
+ PacketBuffer* p = new PacketBuffer();
+ packet_buffer_pool_.push_back(p);
+ packet_buffer_pool_index_[p->buffer] = p;
+ packet_buffer_free_list_.push_back(p);
+ }
+}
+
+TestPacketWriter::~TestPacketWriter() {
+ EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size())
+ << packet_buffer_pool_.size() - packet_buffer_free_list_.size()
+ << " out of " << packet_buffer_pool_.size()
+ << " packet buffers have been leaked.";
+ for (auto p : packet_buffer_pool_) {
+ delete p;
+ }
+}
+
+WriteResult TestPacketWriter::WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& /*self_address*/,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* /*options*/) {
+ last_write_peer_address_ = peer_address;
+ // If the buffer is allocated from the pool, return it back to the pool.
+ // Note the buffer content doesn't change.
+ if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) !=
+ packet_buffer_pool_index_.end()) {
+ FreePacketBuffer(buffer);
+ }
+
+ QuicEncryptedPacket packet(buffer, buf_len);
+ ++packets_write_attempts_;
+
+ if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
+ final_bytes_of_previous_packet_ = final_bytes_of_last_packet_;
+ memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4,
+ sizeof(final_bytes_of_last_packet_));
+ }
+
+ if (use_tagging_decrypter_) {
+ if (framer_.framer()->version().KnowsWhichDecrypterToUse()) {
+ framer_.framer()->InstallDecrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingDecrypter>());
+ framer_.framer()->InstallDecrypter(ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingDecrypter>());
+ framer_.framer()->InstallDecrypter(ENCRYPTION_ZERO_RTT,
+ std::make_unique<TaggingDecrypter>());
+ framer_.framer()->InstallDecrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingDecrypter>());
+ } else {
+ framer_.framer()->SetDecrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingDecrypter>());
+ }
+ } else if (framer_.framer()->version().KnowsWhichDecrypterToUse()) {
+ framer_.framer()->InstallDecrypter(
+ ENCRYPTION_HANDSHAKE,
+ std::make_unique<NullDecrypter>(framer_.framer()->perspective()));
+ framer_.framer()->InstallDecrypter(
+ ENCRYPTION_ZERO_RTT,
+ std::make_unique<NullDecrypter>(framer_.framer()->perspective()));
+ framer_.framer()->InstallDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullDecrypter>(framer_.framer()->perspective()));
+ }
+ EXPECT_TRUE(framer_.ProcessPacket(packet))
+ << framer_.framer()->detailed_error() << " perspective "
+ << framer_.framer()->perspective();
+ if (block_on_next_write_) {
+ write_blocked_ = true;
+ block_on_next_write_ = false;
+ }
+ if (next_packet_too_large_) {
+ next_packet_too_large_ = false;
+ return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
+ }
+ if (always_get_packet_too_large_) {
+ return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
+ }
+ if (IsWriteBlocked()) {
+ return WriteResult(is_write_blocked_data_buffered_
+ ? WRITE_STATUS_BLOCKED_DATA_BUFFERED
+ : WRITE_STATUS_BLOCKED,
+ 0);
+ }
+
+ if (ShouldWriteFail()) {
+ return WriteResult(WRITE_STATUS_ERROR, 0);
+ }
+
+ last_packet_size_ = packet.length();
+ last_packet_header_ = framer_.header();
+ if (!framer_.connection_close_frames().empty()) {
+ ++connection_close_packets_;
+ }
+ if (!write_pause_time_delta_.IsZero()) {
+ clock_->AdvanceTime(write_pause_time_delta_);
+ }
+ if (is_batch_mode_) {
+ bytes_buffered_ += last_packet_size_;
+ return WriteResult(WRITE_STATUS_OK, 0);
+ }
+ return WriteResult(WRITE_STATUS_OK, last_packet_size_);
+}
+
+QuicPacketBuffer TestPacketWriter::GetNextWriteLocation(
+ const QuicIpAddress& /*self_address*/,
+ const QuicSocketAddress& /*peer_address*/) {
+ return {AllocPacketBuffer(), [this](const char* p) { FreePacketBuffer(p); }};
+}
+
+WriteResult TestPacketWriter::Flush() {
+ flush_attempts_++;
+ if (block_on_next_flush_) {
+ block_on_next_flush_ = false;
+ SetWriteBlocked();
+ return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1);
+ }
+ if (write_should_fail_) {
+ return WriteResult(WRITE_STATUS_ERROR, /*errno*/ -1);
+ }
+ int bytes_flushed = bytes_buffered_;
+ bytes_buffered_ = 0;
+ return WriteResult(WRITE_STATUS_OK, bytes_flushed);
+}
+
+char* TestPacketWriter::AllocPacketBuffer() {
+ PacketBuffer* p = packet_buffer_free_list_.front();
+ EXPECT_FALSE(p->in_use);
+ p->in_use = true;
+ packet_buffer_free_list_.pop_front();
+ return p->buffer;
+}
+
+void TestPacketWriter::FreePacketBuffer(const char* buffer) {
+ auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer));
+ ASSERT_TRUE(iter != packet_buffer_pool_index_.end());
+ PacketBuffer* p = iter->second;
+ ASSERT_TRUE(p->in_use);
+ p->in_use = false;
+ packet_buffer_free_list_.push_back(p);
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
index aac4a2ca212..457663e8817 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
@@ -27,11 +27,14 @@
#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -529,6 +532,7 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_METHOD(void, OnForwardProgressMadeAfterPathDegrading, (), (override));
MOCK_METHOD(bool, WillingAndAbleToWrite, (), (const, override));
MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override));
+ MOCK_METHOD(std::string, GetStreamsInfoForLogging, (), (const, override));
MOCK_METHOD(void,
OnSuccessfulVersionNegotiation,
(const ParsedQuicVersion& version),
@@ -813,7 +817,7 @@ class MockQuicSession : public QuicSession {
MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override));
MOCK_METHOD(void,
SendStopSending,
- (uint16_t code, QuicStreamId stream_id),
+ (QuicRstStreamErrorCode code, QuicStreamId stream_id),
(override));
MOCK_METHOD(std::vector<std::string>, GetAlpnsToOffer, (), (const, override));
MOCK_METHOD(std::vector<quiche::QuicheStringPiece>::const_iterator,
@@ -850,6 +854,7 @@ class MockQuicCryptoStream : public QuicCryptoStream {
~MockQuicCryptoStream() override;
+ ssl_early_data_reason_t EarlyDataReason() const override;
bool encryption_established() const override;
bool one_rtt_keys_available() const override;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
@@ -1365,12 +1370,26 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
MockQuicConnectionDebugVisitor();
~MockQuicConnectionDebugVisitor() override;
+ // TODO(wub): Delete when deprecating
+ // --quic_give_sent_packet_to_debug_visitor_after_sent.
MOCK_METHOD(void,
OnPacketSent,
(const SerializedPacket&, TransmissionType, QuicTime),
(override));
MOCK_METHOD(void,
+ OnPacketSent,
+ (QuicPacketNumber,
+ QuicPacketLength,
+ bool,
+ TransmissionType,
+ EncryptionLevel,
+ const QuicFrames&,
+ const QuicFrames&,
+ QuicTime),
+ (override));
+
+ MOCK_METHOD(void,
OnCoalescedPacketSent,
(const QuicCoalescedPacket&, size_t),
(override));
@@ -1464,6 +1483,9 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
OnTransportParametersReceived,
(const TransportParameters&),
(override));
+
+ MOCK_METHOD(void, OnZeroRttRejected, (int), (override));
+ MOCK_METHOD(void, OnZeroRttPacketAcked, (), (override));
};
class MockReceivedPacketManager : public QuicReceivedPacketManager {
@@ -1722,6 +1744,358 @@ MATCHER(IsQuicStreamNoError,
return arg == QUIC_STREAM_NO_ERROR;
}
+// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message.
+class TaggingEncrypter : public QuicEncrypter {
+ public:
+ explicit TaggingEncrypter(uint8_t tag) : tag_(tag) {}
+ TaggingEncrypter(const TaggingEncrypter&) = delete;
+ TaggingEncrypter& operator=(const TaggingEncrypter&) = delete;
+
+ ~TaggingEncrypter() override {}
+
+ // QuicEncrypter interface.
+ bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; }
+
+ bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override {
+ return true;
+ }
+
+ bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; }
+
+ bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override {
+ return true;
+ }
+
+ bool EncryptPacket(uint64_t packet_number,
+ quiche::QuicheStringPiece associated_data,
+ quiche::QuicheStringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override;
+
+ std::string GenerateHeaderProtectionMask(
+ quiche::QuicheStringPiece /*sample*/) override {
+ return std::string(5, 0);
+ }
+
+ size_t GetKeySize() const override { return 0; }
+ size_t GetNoncePrefixSize() const override { return 0; }
+ size_t GetIVSize() const override { return 0; }
+
+ size_t GetMaxPlaintextSize(size_t ciphertext_size) const override {
+ return ciphertext_size - kTagSize;
+ }
+
+ size_t GetCiphertextSize(size_t plaintext_size) const override {
+ return plaintext_size + kTagSize;
+ }
+
+ quiche::QuicheStringPiece GetKey() const override {
+ return quiche::QuicheStringPiece();
+ }
+
+ quiche::QuicheStringPiece GetNoncePrefix() const override {
+ return quiche::QuicheStringPiece();
+ }
+
+ private:
+ enum {
+ kTagSize = 12,
+ };
+
+ const uint8_t tag_;
+};
+
+// TaggingDecrypter ensures that the final kTagSize bytes of the message all
+// have the same value and then removes them.
+class TaggingDecrypter : public QuicDecrypter {
+ public:
+ ~TaggingDecrypter() override {}
+
+ // QuicDecrypter interface
+ bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; }
+
+ bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override {
+ return true;
+ }
+
+ bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; }
+
+ bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override {
+ return true;
+ }
+
+ bool SetPreliminaryKey(quiche::QuicheStringPiece /*key*/) override {
+ QUIC_BUG << "should not be called";
+ return false;
+ }
+
+ bool SetDiversificationNonce(const DiversificationNonce& /*key*/) override {
+ return true;
+ }
+
+ bool DecryptPacket(uint64_t packet_number,
+ quiche::QuicheStringPiece associated_data,
+ quiche::QuicheStringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override;
+
+ std::string GenerateHeaderProtectionMask(
+ QuicDataReader* /*sample_reader*/) override {
+ return std::string(5, 0);
+ }
+
+ size_t GetKeySize() const override { return 0; }
+ size_t GetNoncePrefixSize() const override { return 0; }
+ size_t GetIVSize() const override { return 0; }
+ quiche::QuicheStringPiece GetKey() const override {
+ return quiche::QuicheStringPiece();
+ }
+ quiche::QuicheStringPiece GetNoncePrefix() const override {
+ return quiche::QuicheStringPiece();
+ }
+ // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
+ uint32_t cipher_id() const override { return 0xFFFFFFF0; }
+
+ protected:
+ virtual uint8_t GetTag(quiche::QuicheStringPiece ciphertext) {
+ return ciphertext.data()[ciphertext.size() - 1];
+ }
+
+ private:
+ enum {
+ kTagSize = 12,
+ };
+
+ bool CheckTag(quiche::QuicheStringPiece ciphertext, uint8_t tag);
+};
+
+class TestPacketWriter : public QuicPacketWriter {
+ struct PacketBuffer {
+ QUIC_CACHELINE_ALIGNED char buffer[1500];
+ bool in_use = false;
+ };
+
+ public:
+ TestPacketWriter(ParsedQuicVersion version,
+ MockClock* clock,
+ Perspective perspective);
+
+ TestPacketWriter(const TestPacketWriter&) = delete;
+ TestPacketWriter& operator=(const TestPacketWriter&) = delete;
+
+ ~TestPacketWriter() override;
+
+ // QuicPacketWriter interface
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) override;
+
+ bool ShouldWriteFail() { return write_should_fail_; }
+
+ bool IsWriteBlocked() const override { return write_blocked_; }
+
+ void SetWriteBlocked() { write_blocked_ = true; }
+
+ void SetWritable() override { write_blocked_ = false; }
+
+ void SetShouldWriteFail() { write_should_fail_ = true; }
+
+ QuicByteCount GetMaxPacketSize(
+ const QuicSocketAddress& /*peer_address*/) const override {
+ return max_packet_size_;
+ }
+
+ bool SupportsReleaseTime() const override { return supports_release_time_; }
+
+ bool IsBatchMode() const override { return is_batch_mode_; }
+
+ QuicPacketBuffer GetNextWriteLocation(
+ const QuicIpAddress& /*self_address*/,
+ const QuicSocketAddress& /*peer_address*/) override;
+
+ WriteResult Flush() override;
+
+ void BlockOnNextFlush() { block_on_next_flush_ = true; }
+
+ void BlockOnNextWrite() { block_on_next_write_ = true; }
+
+ void SimulateNextPacketTooLarge() { next_packet_too_large_ = true; }
+
+ void AlwaysGetPacketTooLarge() { always_get_packet_too_large_ = true; }
+
+ // Sets the amount of time that the writer should before the actual write.
+ void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+ write_pause_time_delta_ = delta;
+ }
+
+ void SetBatchMode(bool new_value) { is_batch_mode_ = new_value; }
+
+ const QuicPacketHeader& header() { return framer_.header(); }
+
+ size_t frame_count() const { return framer_.num_frames(); }
+
+ const std::vector<QuicAckFrame>& ack_frames() const {
+ return framer_.ack_frames();
+ }
+
+ const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
+ return framer_.stop_waiting_frames();
+ }
+
+ const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const {
+ return framer_.connection_close_frames();
+ }
+
+ const std::vector<QuicRstStreamFrame>& rst_stream_frames() const {
+ return framer_.rst_stream_frames();
+ }
+
+ const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const {
+ return framer_.stream_frames();
+ }
+
+ const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const {
+ return framer_.crypto_frames();
+ }
+
+ const std::vector<QuicPingFrame>& ping_frames() const {
+ return framer_.ping_frames();
+ }
+
+ const std::vector<QuicMessageFrame>& message_frames() const {
+ return framer_.message_frames();
+ }
+
+ const std::vector<QuicWindowUpdateFrame>& window_update_frames() const {
+ return framer_.window_update_frames();
+ }
+
+ const std::vector<QuicPaddingFrame>& padding_frames() const {
+ return framer_.padding_frames();
+ }
+
+ const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const {
+ return framer_.path_challenge_frames();
+ }
+
+ const std::vector<QuicPathResponseFrame>& path_response_frames() const {
+ return framer_.path_response_frames();
+ }
+
+ const QuicEncryptedPacket* coalesced_packet() const {
+ return framer_.coalesced_packet();
+ }
+
+ size_t last_packet_size() { return last_packet_size_; }
+
+ const QuicPacketHeader& last_packet_header() const {
+ return last_packet_header_;
+ }
+
+ const QuicVersionNegotiationPacket* version_negotiation_packet() {
+ return framer_.version_negotiation_packet();
+ }
+
+ void set_is_write_blocked_data_buffered(bool buffered) {
+ is_write_blocked_data_buffered_ = buffered;
+ }
+
+ void set_perspective(Perspective perspective) {
+ // We invert perspective here, because the framer needs to parse packets
+ // we send.
+ QuicFramerPeer::SetPerspective(framer_.framer(),
+ QuicUtils::InvertPerspective(perspective));
+ framer_.framer()->SetInitialObfuscators(TestConnectionId());
+ }
+
+ // final_bytes_of_last_packet_ returns the last four bytes of the previous
+ // packet as a little-endian, uint32_t. This is intended to be used with a
+ // TaggingEncrypter so that tests can determine which encrypter was used for
+ // a given packet.
+ uint32_t final_bytes_of_last_packet() { return final_bytes_of_last_packet_; }
+
+ // Returns the final bytes of the second to last packet.
+ uint32_t final_bytes_of_previous_packet() {
+ return final_bytes_of_previous_packet_;
+ }
+
+ void use_tagging_decrypter() { use_tagging_decrypter_ = true; }
+
+ uint32_t packets_write_attempts() const { return packets_write_attempts_; }
+
+ uint32_t flush_attempts() const { return flush_attempts_; }
+
+ uint32_t connection_close_packets() const {
+ return connection_close_packets_;
+ }
+
+ void Reset() { framer_.Reset(); }
+
+ void SetSupportedVersions(const ParsedQuicVersionVector& versions) {
+ framer_.SetSupportedVersions(versions);
+ }
+
+ void set_max_packet_size(QuicByteCount max_packet_size) {
+ max_packet_size_ = max_packet_size;
+ }
+
+ void set_supports_release_time(bool supports_release_time) {
+ supports_release_time_ = supports_release_time;
+ }
+
+ SimpleQuicFramer* framer() { return &framer_; }
+
+ const QuicSocketAddress& last_write_peer_address() const {
+ return last_write_peer_address_;
+ }
+
+ private:
+ char* AllocPacketBuffer();
+
+ void FreePacketBuffer(const char* buffer);
+
+ ParsedQuicVersion version_;
+ SimpleQuicFramer framer_;
+ size_t last_packet_size_ = 0;
+ QuicPacketHeader last_packet_header_;
+ bool write_blocked_ = false;
+ bool write_should_fail_ = false;
+ bool block_on_next_flush_ = false;
+ bool block_on_next_write_ = false;
+ bool next_packet_too_large_ = false;
+ bool always_get_packet_too_large_ = false;
+ bool is_write_blocked_data_buffered_ = false;
+ bool is_batch_mode_ = false;
+ // Number of times Flush() was called.
+ uint32_t flush_attempts_ = 0;
+ // (Batch mode only) Number of bytes buffered in writer. It is used as the
+ // return value of a successful Flush().
+ uint32_t bytes_buffered_ = 0;
+ uint32_t final_bytes_of_last_packet_ = 0;
+ uint32_t final_bytes_of_previous_packet_ = 0;
+ bool use_tagging_decrypter_ = false;
+ uint32_t packets_write_attempts_ = 0;
+ uint32_t connection_close_packets_ = 0;
+ MockClock* clock_ = nullptr;
+ // If non-zero, the clock will pause during WritePacket for this amount of
+ // time.
+ QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero();
+ QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize;
+ bool supports_release_time_ = false;
+ // Used to verify writer-allocated packet buffers are properly released.
+ std::vector<PacketBuffer*> packet_buffer_pool_;
+ // Buffer address => Address of the owning PacketBuffer.
+ QuicHashMap<char*, PacketBuffer*> packet_buffer_pool_index_;
+ // Indices in packet_buffer_pool_ that are not allocated.
+ std::list<PacketBuffer*> packet_buffer_free_list_;
+ // The peer address passed into WritePacket().
+ QuicSocketAddress last_write_peer_address_;
+};
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc
index b72a9522036..bc65f448c2e 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc
@@ -265,9 +265,9 @@ TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) {
producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, crypto_data2);
notifier_.WriteCryptoData(ENCRYPTION_INITIAL, 1024, 0);
// Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<NullEncrypter>(
Perspective::IS_CLIENT));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0))
.WillOnce(Invoke(&connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
index cb3c38644f7..ff9b680f58f 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
@@ -59,6 +59,7 @@ class QuicEndpoint : public QuicEndpointBase,
bool WillingAndAbleToWrite() const override;
bool ShouldKeepConnectionAlive() const override;
+ std::string GetStreamsInfoForLogging() const override { return ""; }
void OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {}
void OnBlockedFrame(const QuicBlockedFrame& /*frame*/) override {}
void OnRstStream(const QuicRstStreamFrame& /*frame*/) override {}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h
index 6537987a381..af6cf84ee0c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h
@@ -40,9 +40,6 @@ class QuicBackendResponse {
INCOMPLETE_RESPONSE, // The server will act as if there is a non-empty
// trailer but it will not be sent, as a result, FIN
// will not be sent too.
- STOP_SENDING, // Acts like INCOMPLETE_RESPONSE in that the entire
- // response is not sent. After sending what is sent,
- // the server will send a STOP_SENDING.
GENERATE_BYTES // Sends a response with a length equal to the number
// of bytes in the URL path.
};
@@ -73,15 +70,12 @@ class QuicBackendResponse {
void set_body(quiche::QuicheStringPiece body) {
body_.assign(body.data(), body.size());
}
- uint16_t stop_sending_code() const { return stop_sending_code_; }
- void set_stop_sending_code(uint16_t code) { stop_sending_code_ = code; }
private:
SpecialResponseType response_type_;
spdy::SpdyHeaderBlock headers_;
spdy::SpdyHeaderBlock trailers_;
std::string body_;
- uint16_t stop_sending_code_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
index a9a932071f7..16499d2f8aa 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
@@ -32,9 +32,12 @@ namespace quic {
namespace tools {
-QuicSocketAddress LookupAddress(std::string host, std::string port) {
+QuicSocketAddress LookupAddress(int address_family_for_lookup,
+ std::string host,
+ std::string port) {
addrinfo hint;
memset(&hint, 0, sizeof(hint));
+ hint.ai_family = address_family_for_lookup;
hint.ai_protocol = IPPROTO_UDP;
addrinfo* info_list = nullptr;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h
index 7ce795d719c..ff01cec5831 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h
@@ -31,7 +31,13 @@ class QuicClientPeer;
namespace tools {
-QuicSocketAddress LookupAddress(std::string host, std::string port);
+QuicSocketAddress LookupAddress(int address_family_for_lookup,
+ std::string host,
+ std::string port);
+
+inline QuicSocketAddress LookupAddress(std::string host, std::string port) {
+ return LookupAddress(0, host, port);
+}
} // namespace tools
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
index f0def98fe4c..c1d2ea2103c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
@@ -114,14 +114,17 @@ void QuicClientBase::StartConnect() {
UpdateStats();
}
+ const quic::ParsedQuicVersionVector client_supported_versions =
+ can_reconnect_with_different_version
+ ? ParsedQuicVersionVector{mutual_version}
+ : supported_versions();
+
session_ = CreateQuicClientSession(
- supported_versions(),
+ client_supported_versions,
new QuicConnection(GetNextConnectionId(), server_address(), helper(),
alarm_factory(), writer,
/* owns_writer= */ false, Perspective::IS_CLIENT,
- can_reconnect_with_different_version
- ? ParsedQuicVersionVector{mutual_version}
- : supported_versions()));
+ client_supported_versions));
if (connection_debug_visitor_ != nullptr) {
session()->connection()->set_debug_visitor(connection_debug_visitor_);
}
@@ -283,7 +286,7 @@ bool QuicClientBase::connected() const {
}
bool QuicClientBase::goaway_received() const {
- return session_ != nullptr && session_->goaway_received();
+ return session_ != nullptr && session_->transport_goaway_received();
}
int QuicClientBase::GetNumSentClientHellos() {
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h
index ff600ae0de7..4df3a2bb927 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h
@@ -128,7 +128,7 @@ class QuicClientBase {
const QuicSession* session() const;
bool connected() const;
- bool goaway_received() const;
+ virtual bool goaway_received() const;
const QuicServerId& server_id() const { return server_id_; }
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
index 38dc582c1f3..b7dbb07fa7b 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
@@ -20,12 +20,13 @@ namespace quic {
std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient(
std::string host_for_handshake,
std::string host_for_lookup,
+ int address_family_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
const QuicConfig& config,
std::unique_ptr<ProofVerifier> verifier) {
- QuicSocketAddress addr =
- tools::LookupAddress(host_for_lookup, quiche::QuicheStrCat(port));
+ QuicSocketAddress addr = tools::LookupAddress(
+ address_family_for_lookup, host_for_lookup, quiche::QuicheStrCat(port));
if (!addr.IsInitialized()) {
QUIC_LOG(ERROR) << "Unable to resolve address: " << host_for_lookup;
return nullptr;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h
index 392bd6cc47c..84dbc98ef28 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h
@@ -16,6 +16,7 @@ class QuicEpollClientFactory : public QuicToyClient::ClientFactory {
std::unique_ptr<QuicSpdyClientBase> CreateClient(
std::string host_for_handshake,
std::string host_for_lookup,
+ int address_family_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
const QuicConfig& config,
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc
index c7ac9127790..370eb4aaedb 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc
@@ -199,8 +199,8 @@ void QuicMemoryCacheBackend::AddResponse(
SpdyHeaderBlock response_headers,
quiche::QuicheStringPiece response_body) {
AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
- std::move(response_headers), response_body, SpdyHeaderBlock(),
- 0);
+ std::move(response_headers), response_body,
+ SpdyHeaderBlock());
}
void QuicMemoryCacheBackend::AddResponse(
@@ -211,7 +211,7 @@ void QuicMemoryCacheBackend::AddResponse(
SpdyHeaderBlock response_trailers) {
AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
std::move(response_headers), response_body,
- std::move(response_trailers), 0);
+ std::move(response_trailers));
}
void QuicMemoryCacheBackend::AddSpecialResponse(
@@ -219,7 +219,7 @@ void QuicMemoryCacheBackend::AddSpecialResponse(
quiche::QuicheStringPiece path,
SpecialResponseType response_type) {
AddResponseImpl(host, path, response_type, SpdyHeaderBlock(), "",
- SpdyHeaderBlock(), 0);
+ SpdyHeaderBlock());
}
void QuicMemoryCacheBackend::AddSpecialResponse(
@@ -229,18 +229,7 @@ void QuicMemoryCacheBackend::AddSpecialResponse(
quiche::QuicheStringPiece response_body,
SpecialResponseType response_type) {
AddResponseImpl(host, path, response_type, std::move(response_headers),
- response_body, SpdyHeaderBlock(), 0);
-}
-
-void QuicMemoryCacheBackend::AddStopSendingResponse(
- quiche::QuicheStringPiece host,
- quiche::QuicheStringPiece path,
- spdy::SpdyHeaderBlock response_headers,
- quiche::QuicheStringPiece response_body,
- uint16_t stop_sending_code) {
- AddResponseImpl(host, path, SpecialResponseType::STOP_SENDING,
- std::move(response_headers), response_body, SpdyHeaderBlock(),
- stop_sending_code);
+ response_body, SpdyHeaderBlock());
}
QuicMemoryCacheBackend::QuicMemoryCacheBackend() : cache_initialized_(false) {}
@@ -369,8 +358,7 @@ void QuicMemoryCacheBackend::AddResponseImpl(
SpecialResponseType response_type,
SpdyHeaderBlock response_headers,
quiche::QuicheStringPiece response_body,
- SpdyHeaderBlock response_trailers,
- uint16_t stop_sending_code) {
+ SpdyHeaderBlock response_trailers) {
QuicWriterMutexLock lock(&response_mutex_);
DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
@@ -384,7 +372,6 @@ void QuicMemoryCacheBackend::AddResponseImpl(
new_response->set_headers(std::move(response_headers));
new_response->set_body(response_body);
new_response->set_trailers(std::move(response_trailers));
- new_response->set_stop_sending_code(stop_sending_code);
QUIC_DVLOG(1) << "Add response with key " << key;
responses_[key] = std::move(new_response);
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
index 56a2323b190..1c56ce6355e 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
@@ -124,12 +124,6 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend {
quiche::QuicheStringPiece response_body,
QuicBackendResponse::SpecialResponseType response_type);
- void AddStopSendingResponse(quiche::QuicheStringPiece host,
- quiche::QuicheStringPiece path,
- spdy::SpdyHeaderBlock response_headers,
- quiche::QuicheStringPiece response_body,
- uint16_t stop_sending_code);
-
// Sets a default response in case of cache misses. Takes ownership of
// 'response'.
void AddDefaultResponse(QuicBackendResponse* response);
@@ -159,8 +153,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend {
QuicBackendResponse::SpecialResponseType response_type,
spdy::SpdyHeaderBlock response_headers,
quiche::QuicheStringPiece response_body,
- spdy::SpdyHeaderBlock response_trailers,
- uint16_t stop_sending_code);
+ spdy::SpdyHeaderBlock response_trailers);
std::string GetKey(quiche::QuicheStringPiece host,
quiche::QuicheStringPiece path) const;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
index f5dad7d2d3f..780ff9df099 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
@@ -296,9 +296,8 @@ class QuicSimpleServerSessionTest
return;
}
EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
- QuicStopSendingFrame stop_sending(
- kInvalidControlFrameId, stream_id,
- static_cast<QuicApplicationErrorCode>(rst_stream_code));
+ QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_id,
+ rst_stream_code);
// Expect the RESET_STREAM that is generated in response to receiving a
// STOP_SENDING.
EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
index a6775ccd7a0..84ddb055aa7 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
@@ -254,15 +254,6 @@ void QuicSimpleServerStream::OnResponseBackendComplete(
return;
}
- if (response->response_type() == QuicBackendResponse::STOP_SENDING) {
- QUIC_DVLOG(1)
- << "Stream " << id()
- << " sending an incomplete response, i.e. no trailer, no fin.";
- SendIncompleteResponse(response->headers().Clone(), response->body());
- SendStopSending(response->stop_sending_code());
- return;
- }
-
if (response->response_type() == QuicBackendResponse::GENERATE_BYTES) {
QUIC_DVLOG(1) << "Stream " << id() << " sending a generate bytes response.";
std::string path = request_headers_[":path"].as_string().substr(1);
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
index 09de8138570..212e605f298 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
@@ -188,13 +188,15 @@ QuicSpdyClientStream* QuicSpdyClientBase::CreateClientStream() {
auto* stream = static_cast<QuicSpdyClientStream*>(
client_session()->CreateOutgoingBidirectionalStream());
if (stream) {
- stream->SetPriority(
- spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
stream->set_visitor(this);
}
return stream;
}
+bool QuicSpdyClientBase::goaway_received() const {
+ return client_session() && client_session()->goaway_received();
+}
+
bool QuicSpdyClientBase::EarlyDataAccepted() {
return client_session()->EarlyDataAccepted();
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h
index 874aa2da4d2..fdd67fbc3b5 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h
@@ -143,6 +143,8 @@ class QuicSpdyClientBase : public QuicClientBase,
// TODO(b/151641466): Rename this method.
void SetMaxAllowedPushId(PushId max) { max_allowed_push_id_ = max; }
+ // QuicClientBase methods.
+ bool goaway_received() const override;
bool EarlyDataAccepted() override;
bool ReceivedInchoateReject() override;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
index b42f967caf0..582f3c7cd4a 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
@@ -53,6 +53,7 @@
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
@@ -78,6 +79,12 @@ DEFINE_QUIC_COMMAND_LINE_FLAG(
DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");
DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
+ ip_version_for_host_lookup,
+ "",
+ "Only used if host address lookup is needed. "
+ "4=ipv4; 6=ipv6; otherwise=don't care.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
body,
"",
"If set, send a POST with this body.");
@@ -259,9 +266,17 @@ int QuicToyClient::SendRequestsAndPrintResponses(
ParseQuicTagVector(client_connection_options_string));
}
+ int address_family_for_lookup = AF_UNSPEC;
+ if (GetQuicFlag(FLAGS_ip_version_for_host_lookup) == "4") {
+ address_family_for_lookup = AF_INET;
+ } else if (GetQuicFlag(FLAGS_ip_version_for_host_lookup) == "6") {
+ address_family_for_lookup = AF_INET6;
+ }
+
// Build the client, and try to connect.
std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient(
- url.host(), host, port, versions, config, std::move(proof_verifier));
+ url.host(), host, address_family_for_lookup, port, versions, config,
+ std::move(proof_verifier));
if (client == nullptr) {
std::cerr << "Failed to create client." << std::endl;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h
index d9d8ecaf87a..bf56bf8946d 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h
@@ -24,6 +24,8 @@ class QuicToyClient {
virtual std::unique_ptr<QuicSpdyClientBase> CreateClient(
std::string host_for_handshake,
std::string host_for_lookup,
+ // AF_INET, AF_INET6, or AF_UNSPEC(=don't care).
+ int address_family_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
const QuicConfig& config,
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc
index 49c86e52000..d07da11672b 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc
@@ -176,6 +176,12 @@ void QuicTransportSimpleServerSession::OnIncomingDataStream(
break;
}
break;
+
+ case OUTGOING_BIDIRECTIONAL:
+ stream->set_visitor(std::make_unique<DiscardVisitor>(stream));
+ ++pending_outgoing_bidirectional_streams_;
+ MaybeCreateOutgoingBidirectionalStream();
+ break;
}
}
@@ -183,6 +189,8 @@ void QuicTransportSimpleServerSession::OnCanCreateNewOutgoingStream(
bool unidirectional) {
if (mode_ == ECHO && unidirectional) {
MaybeEchoStreamsBack();
+ } else if (mode_ == OUTGOING_BIDIRECTIONAL && !unidirectional) {
+ MaybeCreateOutgoingBidirectionalStream();
}
}
@@ -208,6 +216,10 @@ bool QuicTransportSimpleServerSession::ProcessPath(const GURL& url) {
mode_ = ECHO;
return true;
}
+ if (url.path() == "/receive-bidirectional") {
+ mode_ = OUTGOING_BIDIRECTIONAL;
+ return true;
+ }
QUIC_DLOG(WARNING) << "Unknown path requested: " << url.path();
return false;
@@ -246,4 +258,21 @@ void QuicTransportSimpleServerSession::MaybeEchoStreamsBack() {
}
}
+void QuicTransportSimpleServerSession::
+ MaybeCreateOutgoingBidirectionalStream() {
+ while (pending_outgoing_bidirectional_streams_ > 0 &&
+ CanOpenNextOutgoingBidirectionalStream()) {
+ auto stream_owned = std::make_unique<QuicTransportStream>(
+ GetNextOutgoingBidirectionalStreamId(), this, this);
+ QuicTransportStream* stream = stream_owned.get();
+ ActivateStream(std::move(stream_owned));
+ QUIC_DVLOG(1) << "Opened outgoing bidirectional stream " << stream->id();
+ stream->set_visitor(std::make_unique<BidirectionalEchoVisitor>(stream));
+ if (!stream->Write("hello")) {
+ QUIC_DVLOG(1) << "Write failed.";
+ }
+ --pending_outgoing_bidirectional_streams_;
+ }
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h
index 7a5fb097cd9..7cfd1975c4e 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h
@@ -34,6 +34,13 @@ class QuicTransportSimpleServerSession
// a server-initiated unidirectional stream that is sent as soon as a FIN is
// received on the incoming stream.
ECHO,
+ // In OUTGOING_BIDIRECTIONAL mode, a server-originated bidirectional stream
+ // is created on receipt of a unidirectional stream. The contents of the
+ // unidirectional stream are disregarded. The bidirectional stream initially
+ // sends "hello", then any received data is echoed back.
+ // TODO(ricea): Maybe this should be replaced by a more general mechanism
+ // where commands on the unidirectional stream trigger different behaviour?
+ OUTGOING_BIDIRECTIONAL,
};
QuicTransportSimpleServerSession(
@@ -60,8 +67,10 @@ class QuicTransportSimpleServerSession
private:
void MaybeEchoStreamsBack();
+ void MaybeCreateOutgoingBidirectionalStream();
const bool owns_connection_;
+ size_t pending_outgoing_bidirectional_streams_ = 0u;
Mode mode_;
std::vector<url::Origin> accepted_origins_;
QuicCircularDeque<std::string> streams_to_echo_back_;
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc
new file mode 100644
index 00000000000..aeea7268965
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc
@@ -0,0 +1,64 @@
+// Copyright 2020 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.
+
+//
+// $ blaze run -c opt --dynamic_mode=off \
+// -- //net/third_party/quiche/src/spdy/core/hpack:hpack_huffman_table_benchmark \
+// --benchmarks=all --benchmark_memory_usage --benchmark_repetitions=1
+//
+// Benchmark Time(ns) CPU(ns) Allocs Iterations
+// -----------------------------------------------------------------------------
+// BM_EncodeSmallStrings 463 441 0 100000 0.000B peak-mem
+// BM_EncodeLargeString/1k 9003 9069 5 4861 1.125kB peak-mem
+// BM_EncodeLargeString/4k 34808 35157 7 1597 4.500kB peak-mem
+// BM_EncodeLargeString/32k 275973 270741 10 207 36.000kB peak-mem
+// BM_EncodeLargeString/256k 2234748 2236850 13 29 288.000kB peak-mem
+// BM_EncodeLargeString/2M 18248449 18717995 16 3 2.250MB peak-mem
+// BM_EncodeLargeString/16M 144944895 144415061 19 1 18.000MB peak-mem
+// BM_EncodeLargeString/128M 1200907841 1207238809 86 1 144.009MB peak-mem
+//
+
+#include <string>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+// This header has multiple DCHECK_* macros with signed-unsigned comparison.
+#include "testing/base/public/benchmark.h"
+#pragma clang diagnostic pop
+
+#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
+#include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
+#include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h"
+
+namespace spdy {
+namespace {
+
+void BM_EncodeSmallStrings(benchmark::State& state) {
+ const HpackHuffmanTable& table = ObtainHpackHuffmanTable();
+ const std::vector<const std::string> inputs{
+ ":method", ":path", "cookie", "set-cookie", "vary", "accept-encoding"};
+ for (auto s : state) {
+ for (const auto& input : inputs) {
+ HpackOutputStream output_stream;
+ table.EncodedSize(input);
+ table.EncodeString(input, &output_stream);
+ }
+ }
+}
+
+void BM_EncodeLargeString(benchmark::State& state) {
+ const HpackHuffmanTable& table = ObtainHpackHuffmanTable();
+ const std::string input(state.range(0), 'a');
+ for (auto s : state) {
+ HpackOutputStream output_stream;
+ table.EncodedSize(input);
+ table.EncodeString(input, &output_stream);
+ }
+}
+
+BENCHMARK(BM_EncodeSmallStrings);
+BENCHMARK(BM_EncodeLargeString)->Range(1024, 128 * 1024 * 1024);
+
+} // namespace
+} // namespace spdy
diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h
index a50745f1897..a58e2240eff 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h
@@ -17,7 +17,6 @@
#include <utility>
#include <vector>
-#include "net/third_party/quiche/src/common/platform/api/quiche_map_util.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/spdy/core/spdy_intrusive_list.h"
#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
@@ -211,7 +210,7 @@ Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler() {
template <typename StreamIdType>
bool Http2PriorityWriteScheduler<StreamIdType>::StreamRegistered(
StreamIdType stream_id) const {
- return quiche::QuicheContainsKey(all_stream_infos_, stream_id);
+ return all_stream_infos_.find(stream_id) != all_stream_infos_.end();
}
template <typename StreamIdType>