From 31ccca0778db85c159634478b4ec7997f6704860 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 11 Mar 2020 11:32:04 +0100 Subject: BASELINE: Update Chromium to 80.0.3987.136 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I98e1649aafae85ba3a83e67af00bb27ef301db7b Reviewed-by: Jüri Valdmann --- .../quiche/src/quic/core/chlo_extractor.h | 4 +- .../core/congestion_control/bandwidth_sampler.cc | 8 +- .../core/congestion_control/bandwidth_sampler.h | 13 +- .../congestion_control/bandwidth_sampler_test.cc | 5 + .../src/quic/core/congestion_control/bbr2_drain.h | 3 +- .../src/quic/core/congestion_control/bbr2_misc.h | 13 +- .../quic/core/congestion_control/bbr2_probe_bw.cc | 35 +- .../quic/core/congestion_control/bbr2_probe_bw.h | 10 +- .../quic/core/congestion_control/bbr2_probe_rtt.cc | 6 + .../quic/core/congestion_control/bbr2_probe_rtt.h | 3 +- .../quic/core/congestion_control/bbr2_sender.cc | 21 +- .../src/quic/core/congestion_control/bbr2_sender.h | 14 +- .../core/congestion_control/bbr2_simulator_test.cc | 86 +- .../quic/core/congestion_control/bbr2_startup.cc | 17 +- .../quic/core/congestion_control/bbr2_startup.h | 7 +- .../src/quic/core/congestion_control/bbr_sender.cc | 63 +- .../src/quic/core/congestion_control/bbr_sender.h | 7 +- .../core/congestion_control/bbr_sender_test.cc | 106 +- .../congestion_control/general_loss_algorithm.cc | 35 +- .../congestion_control/general_loss_algorithm.h | 18 +- .../general_loss_algorithm_test.cc | 64 +- .../congestion_control/loss_detection_interface.h | 10 - .../src/quic/core/congestion_control/rtt_stats.h | 5 - .../quic/core/congestion_control/rtt_stats_test.cc | 34 - .../congestion_control/send_algorithm_interface.cc | 3 +- .../congestion_control/send_algorithm_interface.h | 43 +- .../congestion_control/tcp_cubic_sender_bytes.cc | 10 +- .../congestion_control/tcp_cubic_sender_bytes.h | 5 +- .../tcp_cubic_sender_bytes_test.cc | 27 +- .../core/congestion_control/uber_loss_algorithm.cc | 17 +- .../core/congestion_control/uber_loss_algorithm.h | 10 +- .../congestion_control/uber_loss_algorithm_test.cc | 4 +- .../quic/core/congestion_control/windowed_filter.h | 8 +- .../src/quic/core/crypto/aead_base_encrypter.cc | 2 +- .../core/crypto/aes_128_gcm_12_decrypter_test.cc | 2 +- .../core/crypto/aes_128_gcm_12_encrypter_test.cc | 1 + .../quic/core/crypto/aes_128_gcm_decrypter_test.cc | 2 +- .../quic/core/crypto/aes_256_gcm_decrypter_test.cc | 2 +- .../crypto/chacha20_poly1305_decrypter_test.cc | 2 +- .../crypto/chacha20_poly1305_tls_decrypter_test.cc | 2 +- .../src/quic/core/crypto/chacha_base_decrypter.cc | 3 +- .../src/quic/core/crypto/chacha_base_encrypter.cc | 3 +- .../quiche/src/quic/core/crypto/crypto_framer.cc | 9 +- .../quic/core/crypto/crypto_handshake_message.cc | 13 +- .../core/crypto/crypto_handshake_message_test.cc | 2 +- .../quic/core/crypto/crypto_message_printer_bin.cc | 1 - .../quiche/src/quic/core/crypto/crypto_protocol.h | 21 + .../src/quic/core/crypto/crypto_server_test.cc | 4 +- .../quiche/src/quic/core/crypto/crypto_utils.cc | 9 +- .../quiche/src/quic/core/crypto/crypto_utils.h | 2 +- .../quiche/src/quic/core/crypto/key_exchange.h | 2 +- .../quiche/src/quic/core/crypto/null_decrypter.cc | 3 +- .../quiche/src/quic/core/crypto/null_encrypter.cc | 2 +- .../src/quic/core/crypto/null_encrypter_test.cc | 1 + .../quiche/src/quic/core/crypto/proof_source.h | 6 +- .../quic/core/crypto/quic_compressed_certs_cache.h | 4 +- .../quic/core/crypto/quic_crypto_client_config.cc | 13 +- .../quic/core/crypto/quic_crypto_client_config.h | 57 +- .../core/crypto/quic_crypto_client_config_test.cc | 17 +- .../quic/core/crypto/quic_crypto_server_config.cc | 8 +- .../quic/core/crypto/quic_crypto_server_config.h | 12 +- .../core/crypto/quic_crypto_server_config_test.cc | 3 +- .../quiche/src/quic/core/crypto/quic_hkdf.h | 2 +- .../src/quic/core/crypto/tls_client_connection.cc | 18 +- .../src/quic/core/crypto/tls_client_connection.h | 9 +- .../quiche/src/quic/core/crypto/tls_connection.h | 2 +- .../src/quic/core/crypto/tls_server_connection.cc | 1 + .../src/quic/core/crypto/tls_server_connection.h | 2 +- .../src/quic/core/crypto/transport_parameters.cc | 32 +- .../src/quic/core/crypto/transport_parameters.h | 4 + .../quic/core/crypto/transport_parameters_test.cc | 60 +- .../quiche/src/quic/core/frames/quic_ack_frame.cc | 173 +- .../quiche/src/quic/core/frames/quic_ack_frame.h | 13 +- .../quiche/src/quic/core/frames/quic_frame.cc | 95 + .../quiche/src/quic/core/frames/quic_frame.h | 8 + .../src/quic/core/frames/quic_frames_test.cc | 145 +- .../src/quic/core/frames/quic_stream_frame.cc | 10 + .../src/quic/core/frames/quic_stream_frame.h | 4 + .../quic/core/frames/quic_window_update_frame.cc | 6 +- .../quic/core/frames/quic_window_update_frame.h | 18 +- .../src/quic/core/handshaker_delegate_interface.h | 53 + .../quiche/src/quic/core/http/end_to_end_test.cc | 122 +- .../quiche/src/quic/core/http/http_decoder_test.cc | 129 +- .../quiche/src/quic/core/http/http_encoder.cc | 84 +- .../quiche/src/quic/core/http/http_encoder.h | 51 +- .../quiche/src/quic/core/http/http_encoder_test.cc | 50 +- .../quiche/src/quic/core/http/http_frames.h | 18 +- .../src/quic/core/http/quic_client_promised_info.h | 2 +- .../core/http/quic_client_promised_info_test.cc | 1 - .../http/quic_client_push_promise_index_test.cc | 1 - .../quiche/src/quic/core/http/quic_header_list.cc | 3 +- .../src/quic/core/http/quic_header_list_test.cc | 7 +- .../src/quic/core/http/quic_headers_stream_test.cc | 15 +- .../quic/core/http/quic_receive_control_stream.cc | 13 +- .../core/http/quic_receive_control_stream_test.cc | 43 +- .../src/quic/core/http/quic_send_control_stream.cc | 30 +- .../src/quic/core/http/quic_send_control_stream.h | 5 +- .../core/http/quic_send_control_stream_test.cc | 1 - .../core/http/quic_server_session_base_test.cc | 29 +- .../src/quic/core/http/quic_spdy_client_session.cc | 12 +- .../src/quic/core/http/quic_spdy_client_session.h | 2 +- .../core/http/quic_spdy_client_session_base.cc | 9 - .../quic/core/http/quic_spdy_client_session_base.h | 3 - .../core/http/quic_spdy_client_session_test.cc | 32 +- .../src/quic/core/http/quic_spdy_client_stream.h | 2 +- .../quic/core/http/quic_spdy_client_stream_test.cc | 14 +- .../quic/core/http/quic_spdy_server_stream_base.h | 2 +- .../core/http/quic_spdy_server_stream_base_test.cc | 1 + .../quiche/src/quic/core/http/quic_spdy_session.cc | 91 +- .../quiche/src/quic/core/http/quic_spdy_session.h | 29 +- .../src/quic/core/http/quic_spdy_session_test.cc | 232 ++- .../quiche/src/quic/core/http/quic_spdy_stream.cc | 137 +- .../quiche/src/quic/core/http/quic_spdy_stream.h | 14 +- .../quic/core/http/quic_spdy_stream_body_manager.h | 2 +- .../http/quic_spdy_stream_body_manager_test.cc | 195 +- .../src/quic/core/http/quic_spdy_stream_test.cc | 298 ++- .../quic/core/http/spdy_server_push_utils_test.cc | 2 - .../src/quic/core/packet_number_indexed_queue.h | 4 +- .../quiche/src/quic/core/qpack/offline/README.md | 28 - .../core/qpack/offline/qpack_offline_decoder.cc | 312 --- .../core/qpack/offline/qpack_offline_decoder.h | 86 - .../qpack/offline/qpack_offline_decoder_bin.cc | 46 - .../src/quic/core/qpack/qpack_blocking_manager.cc | 34 +- .../src/quic/core/qpack/qpack_blocking_manager.h | 19 +- .../quic/core/qpack/qpack_blocking_manager_test.cc | 82 - .../quiche/src/quic/core/qpack/qpack_constants.cc | 202 -- .../quiche/src/quic/core/qpack/qpack_constants.h | 142 -- .../qpack/qpack_decoded_headers_accumulator.cc | 79 +- .../core/qpack/qpack_decoded_headers_accumulator.h | 82 +- .../qpack_decoded_headers_accumulator_test.cc | 158 +- .../quiche/src/quic/core/qpack/qpack_decoder.cc | 8 +- .../quiche/src/quic/core/qpack/qpack_decoder.h | 5 + .../core/qpack/qpack_decoder_stream_receiver.cc | 2 +- .../core/qpack/qpack_decoder_stream_receiver.h | 2 +- .../quic/core/qpack/qpack_decoder_stream_sender.cc | 20 +- .../quic/core/qpack/qpack_decoder_stream_sender.h | 1 - .../core/qpack/qpack_decoder_stream_sender_test.cc | 2 +- .../src/quic/core/qpack/qpack_decoder_test.cc | 67 +- .../quic/core/qpack/qpack_decoder_test_utils.cc | 88 - .../src/quic/core/qpack/qpack_decoder_test_utils.h | 103 - .../quiche/src/quic/core/qpack/qpack_encoder.cc | 60 +- .../quiche/src/quic/core/qpack/qpack_encoder.h | 27 +- .../core/qpack/qpack_encoder_stream_receiver.cc | 2 +- .../core/qpack/qpack_encoder_stream_receiver.h | 2 +- .../quic/core/qpack/qpack_encoder_stream_sender.cc | 31 +- .../quic/core/qpack/qpack_encoder_stream_sender.h | 1 - .../core/qpack/qpack_encoder_stream_sender_test.cc | 2 +- .../src/quic/core/qpack/qpack_encoder_test.cc | 9 +- .../quic/core/qpack/qpack_encoder_test_utils.cc | 16 - .../src/quic/core/qpack/qpack_encoder_test_utils.h | 40 - .../src/quic/core/qpack/qpack_header_table.cc | 3 +- .../src/quic/core/qpack/qpack_header_table.h | 18 +- .../quic/core/qpack/qpack_instruction_decoder.cc | 110 +- .../quic/core/qpack/qpack_instruction_decoder.h | 42 +- .../core/qpack/qpack_instruction_decoder_test.cc | 97 +- .../quic/core/qpack/qpack_instruction_encoder.cc | 18 +- .../quic/core/qpack/qpack_instruction_encoder.h | 15 +- .../core/qpack/qpack_instruction_encoder_test.cc | 148 +- .../src/quic/core/qpack/qpack_instructions.cc | 331 +++ .../src/quic/core/qpack/qpack_instructions.h | 207 ++ .../quic/core/qpack/qpack_offline_decoder_bin.cc | 45 + .../quic/core/qpack/qpack_progressive_decoder.cc | 28 +- .../quic/core/qpack/qpack_progressive_decoder.h | 3 +- .../src/quic/core/qpack/qpack_round_trip_test.cc | 8 +- .../quiche/src/quic/core/qpack/qpack_test_utils.cc | 23 - .../quiche/src/quic/core/qpack/qpack_test_utils.h | 40 - .../quiche/src/quic/core/qpack/qpack_utils.h | 23 - .../core/qpack/value_splitting_header_list_test.cc | 70 +- .../quiche/src/quic/core/quic_arena_scoped_ptr.h | 3 +- .../quiche/src/quic/core/quic_circular_deque.h | 744 +++++++ .../src/quic/core/quic_circular_deque_test.cc | 790 +++++++ .../quiche/src/quic/core/quic_coalesced_packet.cc | 119 ++ .../quiche/src/quic/core/quic_coalesced_packet.h | 72 + .../src/quic/core/quic_coalesced_packet_test.cc | 114 ++ .../quiche/src/quic/core/quic_config.cc | 62 +- .../third_party/quiche/src/quic/core/quic_config.h | 18 + .../quiche/src/quic/core/quic_config_test.cc | 68 +- .../quiche/src/quic/core/quic_connection.cc | 925 +++++---- .../quiche/src/quic/core/quic_connection.h | 155 +- .../quiche/src/quic/core/quic_connection_id.cc | 2 +- .../quiche/src/quic/core/quic_connection_id.h | 2 +- .../quiche/src/quic/core/quic_connection_stats.cc | 53 +- .../quiche/src/quic/core/quic_connection_stats.h | 99 +- .../quiche/src/quic/core/quic_connection_test.cc | 1170 +++++------ .../quiche/src/quic/core/quic_constants.h | 12 + .../src/quic/core/quic_control_frame_manager.cc | 17 +- .../src/quic/core/quic_control_frame_manager.h | 3 - .../quic/core/quic_control_frame_manager_test.cc | 1 - .../src/quic/core/quic_crypto_client_handshaker.cc | 37 +- .../src/quic/core/quic_crypto_client_handshaker.h | 5 +- .../src/quic/core/quic_crypto_client_stream.cc | 9 +- .../src/quic/core/quic_crypto_client_stream.h | 16 + .../quic/core/quic_crypto_client_stream_test.cc | 86 +- .../src/quic/core/quic_crypto_server_handshaker.cc | 56 +- .../src/quic/core/quic_crypto_server_handshaker.h | 5 +- .../src/quic/core/quic_crypto_server_stream.cc | 4 + .../src/quic/core/quic_crypto_server_stream.h | 4 +- .../quic/core/quic_crypto_server_stream_test.cc | 6 +- .../quiche/src/quic/core/quic_crypto_stream.cc | 9 +- .../quiche/src/quic/core/quic_crypto_stream.h | 5 +- .../src/quic/core/quic_crypto_stream_test.cc | 1 + .../quiche/src/quic/core/quic_data_reader.cc | 27 +- .../quiche/src/quic/core/quic_data_reader.h | 10 +- .../quiche/src/quic/core/quic_data_writer.cc | 31 +- .../quiche/src/quic/core/quic_data_writer.h | 6 +- .../quiche/src/quic/core/quic_data_writer_test.cc | 138 +- .../quiche/src/quic/core/quic_dispatcher.cc | 24 +- .../quiche/src/quic/core/quic_dispatcher.h | 12 +- .../quiche/src/quic/core/quic_dispatcher_test.cc | 226 +- .../src/quic/core/quic_epoll_alarm_factory.h | 2 +- .../src/quic/core/quic_epoll_connection_helper.h | 3 +- .../quiche/src/quic/core/quic_error_codes.cc | 5 + .../quiche/src/quic/core/quic_error_codes.h | 23 +- .../quiche/src/quic/core/quic_framer.cc | 155 +- .../third_party/quiche/src/quic/core/quic_framer.h | 12 +- .../quiche/src/quic/core/quic_framer_test.cc | 457 +++-- .../quiche/src/quic/core/quic_ietf_framer_test.cc | 103 +- .../quiche/src/quic/core/quic_interval.h | 6 +- .../quiche/src/quic/core/quic_interval_set.h | 50 +- .../quiche/src/quic/core/quic_interval_set_test.cc | 41 + .../quiche/src/quic/core/quic_lru_cache.h | 3 +- .../quiche/src/quic/core/quic_mtu_discovery.cc | 3 - .../quiche/src/quic/core/quic_one_block_arena.h | 2 +- .../quiche/src/quic/core/quic_packet_creator.cc | 417 ++-- .../quiche/src/quic/core/quic_packet_creator.h | 91 +- .../src/quic/core/quic_packet_creator_test.cc | 2160 ++++++++++++++++---- .../quiche/src/quic/core/quic_packet_generator.cc | 556 ----- .../quiche/src/quic/core/quic_packet_generator.h | 269 --- .../src/quic/core/quic_packet_generator_test.cc | 1512 -------------- .../quiche/src/quic/core/quic_packet_number.cc | 14 - .../quiche/src/quic/core/quic_packet_number.h | 19 +- .../quiche/src/quic/core/quic_packet_reader.h | 4 +- .../src/quic/core/quic_packet_writer_wrapper.h | 2 +- .../quiche/src/quic/core/quic_packets.cc | 43 +- .../quiche/src/quic/core/quic_packets.h | 17 +- .../quiche/src/quic/core/quic_packets_test.cc | 41 + .../src/quic/core/quic_pending_retransmission.h | 54 - .../src/quic/core/quic_process_packet_interface.h | 2 +- .../src/quic/core/quic_received_packet_manager.cc | 8 - .../src/quic/core/quic_sent_packet_manager.cc | 593 ++---- .../src/quic/core/quic_sent_packet_manager.h | 118 +- .../src/quic/core/quic_sent_packet_manager_test.cc | 1561 +++++++------- .../quiche/src/quic/core/quic_session.cc | 308 ++- .../quiche/src/quic/core/quic_session.h | 59 +- .../quiche/src/quic/core/quic_session_test.cc | 137 +- .../quiche/src/quic/core/quic_stream.cc | 144 +- .../third_party/quiche/src/quic/core/quic_stream.h | 31 +- .../quiche/src/quic/core/quic_stream_id_manager.h | 6 +- .../src/quic/core/quic_stream_id_manager_test.cc | 1 - .../src/quic/core/quic_stream_send_buffer.cc | 27 +- .../quiche/src/quic/core/quic_stream_send_buffer.h | 12 +- .../src/quic/core/quic_stream_send_buffer_test.cc | 45 +- .../quiche/src/quic/core/quic_stream_sequencer.cc | 42 +- .../quiche/src/quic/core/quic_stream_sequencer.h | 11 +- .../src/quic/core/quic_stream_sequencer_buffer.h | 2 +- .../quic/core/quic_stream_sequencer_buffer_test.cc | 147 +- .../src/quic/core/quic_stream_sequencer_test.cc | 40 +- .../quiche/src/quic/core/quic_stream_test.cc | 325 +-- .../third_party/quiche/src/quic/core/quic_time.h | 3 + .../quiche/src/quic/core/quic_time_accumulator.h | 69 + .../src/quic/core/quic_time_accumulator_test.cc | 82 + .../src/quic/core/quic_time_wait_list_manager.h | 9 +- .../quiche/src/quic/core/quic_trace_visitor.cc | 8 +- .../quiche/src/quic/core/quic_trace_visitor.h | 3 +- .../quiche/src/quic/core/quic_transmission_info.cc | 3 - .../quiche/src/quic/core/quic_transmission_info.h | 3 - .../third_party/quiche/src/quic/core/quic_types.cc | 69 +- .../third_party/quiche/src/quic/core/quic_types.h | 66 +- .../quiche/src/quic/core/quic_types_test.cc | 8 +- .../src/quic/core/quic_unacked_packet_map.cc | 167 +- .../quiche/src/quic/core/quic_unacked_packet_map.h | 35 +- .../src/quic/core/quic_unacked_packet_map_test.cc | 195 +- .../third_party/quiche/src/quic/core/quic_utils.cc | 8 +- .../quiche/src/quic/core/quic_utils_test.cc | 10 +- .../quiche/src/quic/core/quic_version_manager.cc | 16 +- .../quiche/src/quic/core/quic_version_manager.h | 8 - .../src/quic/core/quic_version_manager_test.cc | 56 +- .../quiche/src/quic/core/quic_versions.cc | 62 +- .../quiche/src/quic/core/quic_versions.h | 31 +- .../quiche/src/quic/core/quic_versions_test.cc | 281 +-- .../quiche/src/quic/core/quic_write_blocked_list.h | 4 +- .../quiche/src/quic/core/tls_client_handshaker.cc | 72 +- .../quiche/src/quic/core/tls_client_handshaker.h | 28 +- .../quiche/src/quic/core/tls_handshaker.cc | 32 +- .../quiche/src/quic/core/tls_handshaker.h | 7 +- .../quiche/src/quic/core/tls_handshaker_test.cc | 64 +- .../quiche/src/quic/core/tls_server_handshaker.cc | 23 +- .../quiche/src/quic/core/tls_server_handshaker.h | 9 +- .../src/quic/core/uber_quic_stream_id_manager.cc | 8 + .../src/quic/core/uber_quic_stream_id_manager.h | 2 + .../quiche/src/quic/platform/api/quic_cert_utils.h | 3 +- .../quiche/src/quic/platform/api/quic_endian.h | 54 - .../src/quic/platform/api/quic_endian_test.cc | 51 - .../quiche/src/quic/platform/api/quic_export.h | 7 + .../quiche/src/quic/platform/api/quic_ptr_util.h | 5 - .../src/quic/platform/api/quic_reference_counted.h | 2 +- .../quiche/src/quic/platform/api/quic_test.h | 5 + .../quic/platform/api/quic_test_mem_slice_vector.h | 2 +- .../quiche/src/quic/platform/api/quic_text_utils.h | 3 +- .../quiche/src/quic/platform/api/quic_thread.h | 3 +- .../quiche/src/quic/qbone/bonnet/icmp_reachable.cc | 2 +- .../src/quic/qbone/bonnet/icmp_reachable_test.cc | 10 +- .../bonnet/mock_packet_exchanger_stats_interface.h | 27 + .../quiche/src/quic/qbone/bonnet/tun_device.cc | 4 +- .../qbone/bonnet/tun_device_packet_exchanger.cc | 5 + .../qbone/bonnet/tun_device_packet_exchanger.h | 7 +- .../bonnet/tun_device_packet_exchanger_test.cc | 12 +- .../quiche/src/quic/qbone/platform/icmp_packet.cc | 8 +- .../src/quic/qbone/platform/internet_checksum.cc | 1 - .../quiche/src/quic/qbone/platform/ip_range.cc | 14 +- .../quiche/src/quic/qbone/platform/netlink_test.cc | 6 +- .../quiche/src/quic/qbone/platform/tcp_packet.cc | 15 +- .../quiche/src/quic/qbone/qbone_client.cc | 3 +- .../src/quic/qbone/qbone_packet_processor.cc | 4 +- .../quiche/src/quic/qbone/qbone_session_base.cc | 43 +- .../quiche/src/quic/qbone/qbone_session_test.cc | 48 +- .../quiche/src/quic/quartc/quartc_endpoint_test.cc | 4 +- .../quiche/src/quic/quartc/quartc_factory.cc | 9 +- .../src/quic/quartc/quartc_multiplexer_test.cc | 7 +- .../quiche/src/quic/quartc/quartc_packet_writer.cc | 2 +- .../quiche/src/quic/quartc/quartc_session.cc | 30 + .../quiche/src/quic/quartc/quartc_session.h | 1 + .../quiche/src/quic/quartc/quartc_session_test.cc | 9 +- .../quiche/src/quic/quartc/quartc_stream_test.cc | 23 +- .../quic_transport_client_session.cc | 130 +- .../quic_transport/quic_transport_client_session.h | 62 +- .../quic_transport_client_session_test.cc | 103 +- .../quic_transport_integration_test.cc | 331 +++ .../quic/quic_transport/quic_transport_protocol.h | 7 +- .../quic_transport_server_session.cc | 10 +- .../quic_transport/quic_transport_server_session.h | 15 +- .../quic_transport_server_session_test.cc | 12 +- .../quic_transport_session_interface.h | 4 +- .../quic/quic_transport/quic_transport_stream.cc | 112 + .../quic/quic_transport/quic_transport_stream.h | 72 + .../quic_transport/quic_transport_stream_test.cc | 123 ++ .../src/quic/test_tools/crypto_test_utils.cc | 26 +- .../quiche/src/quic/test_tools/crypto_test_utils.h | 5 + .../src/quic/test_tools/crypto_test_utils_test.cc | 2 +- .../test_tools/qpack/qpack_decoder_test_utils.cc | 88 + .../test_tools/qpack/qpack_decoder_test_utils.h | 103 + .../quic/test_tools/qpack/qpack_encoder_peer.cc | 30 + .../src/quic/test_tools/qpack/qpack_encoder_peer.h | 30 + .../test_tools/qpack/qpack_encoder_test_utils.cc | 16 + .../test_tools/qpack/qpack_encoder_test_utils.h | 40 + .../test_tools/qpack/qpack_header_table_peer.cc | 25 + .../test_tools/qpack/qpack_header_table_peer.h | 29 + .../quic/test_tools/qpack/qpack_offline_decoder.cc | 334 +++ .../quic/test_tools/qpack/qpack_offline_decoder.h | 86 + .../src/quic/test_tools/qpack/qpack_test_utils.cc | 23 + .../src/quic/test_tools/qpack/qpack_test_utils.h | 47 + .../src/quic/test_tools/qpack_encoder_peer.cc | 30 - .../src/quic/test_tools/qpack_encoder_peer.h | 30 - .../src/quic/test_tools/qpack_header_table_peer.cc | 25 - .../src/quic/test_tools/qpack_header_table_peer.h | 29 - .../src/quic/test_tools/quic_connection_peer.cc | 58 +- .../src/quic/test_tools/quic_connection_peer.h | 12 +- .../src/quic/test_tools/quic_dispatcher_peer.cc | 9 +- .../src/quic/test_tools/quic_dispatcher_peer.h | 3 + .../quiche/src/quic/test_tools/quic_framer_peer.h | 4 + .../quic/test_tools/quic_packet_creator_peer.cc | 11 +- .../src/quic/test_tools/quic_packet_creator_peer.h | 1 + .../quic/test_tools/quic_packet_generator_peer.cc | 20 - .../quic/test_tools/quic_packet_generator_peer.h | 28 - .../test_tools/quic_sent_packet_manager_peer.cc | 22 +- .../test_tools/quic_sent_packet_manager_peer.h | 3 + .../src/quic/test_tools/quic_session_peer.cc | 9 - .../quiche/src/quic/test_tools/quic_session_peer.h | 5 - .../quiche/src/quic/test_tools/quic_stream_peer.cc | 2 +- .../quic/test_tools/quic_stream_send_buffer_peer.h | 4 + .../quic_stream_sequencer_buffer_peer.cc | 5 +- .../quiche/src/quic/test_tools/quic_test_client.cc | 4 +- .../quiche/src/quic/test_tools/quic_test_server.cc | 12 +- .../quiche/src/quic/test_tools/quic_test_utils.cc | 23 +- .../quiche/src/quic/test_tools/quic_test_utils.h | 72 +- .../quic/test_tools/quic_transport_test_tools.h | 36 + .../src/quic/test_tools/simple_quic_framer.cc | 12 +- .../src/quic/test_tools/simple_quic_framer.h | 1 + .../src/quic/test_tools/simple_session_cache.cc | 28 + .../src/quic/test_tools/simple_session_cache.h | 35 + .../src/quic/test_tools/simple_session_notifier.cc | 8 +- .../test_tools/simple_session_notifier_test.cc | 6 +- .../src/quic/test_tools/simulator/quic_endpoint.cc | 246 +-- .../src/quic/test_tools/simulator/quic_endpoint.h | 113 +- .../test_tools/simulator/quic_endpoint_base.cc | 222 ++ .../quic/test_tools/simulator/quic_endpoint_base.h | 158 ++ .../test_tools/simulator/quic_endpoint_test.cc | 4 +- .../quiche/src/quic/tools/quic_client.cc | 43 +- .../quiche/src/quic/tools/quic_client.h | 16 +- .../quiche/src/quic/tools/quic_client_base.cc | 5 +- .../quiche/src/quic/tools/quic_client_base.h | 4 +- .../src/quic/tools/quic_client_interop_test_bin.cc | 127 +- .../src/quic/tools/quic_memory_cache_backend.cc | 1 - .../src/quic/tools/quic_memory_cache_backend.h | 3 - .../quic/tools/quic_memory_cache_backend_test.cc | 4 - .../quiche/src/quic/tools/quic_server.cc | 2 - .../src/quic/tools/quic_simple_client_stream.cc | 4 - .../src/quic/tools/quic_simple_client_stream.h | 8 +- .../quic/tools/quic_simple_server_session_test.cc | 63 +- .../quic/tools/quic_simple_server_stream_test.cc | 42 +- .../quiche/src/quic/tools/quic_spdy_client_base.cc | 6 +- .../quiche/src/quic/tools/quic_spdy_client_base.h | 4 +- .../quiche/src/quic/tools/quic_toy_client.cc | 5 - .../quiche/src/quic/tools/quic_toy_server.cc | 7 +- .../quic_transport_simple_server_dispatcher.cc | 55 + .../quic_transport_simple_server_dispatcher.h | 41 + .../tools/quic_transport_simple_server_session.cc | 226 ++ .../tools/quic_transport_simple_server_session.h | 72 + 408 files changed, 15145 insertions(+), 11696 deletions(-) create mode 100644 chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc create mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h delete mode 100644 chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet_test.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h delete mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_pending_retransmission.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator.h create mode 100644 chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator_test.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/platform/api/quic_endian.h delete mode 100644 chromium/net/third_party/quiche/src/quic/platform/api/quic_endian_test.cc create mode 100644 chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h create mode 100644 chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc create mode 100644 chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc create mode 100644 chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h create mode 100644 chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h delete mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h delete mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h delete mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.cc delete mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc create mode 100644 chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h create mode 100644 chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc create mode 100644 chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h create mode 100644 chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc create mode 100644 chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h (limited to 'chromium/net/third_party/quiche/src/quic') diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.h b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.h index 3cf0d24b3b5..89dffe16a24 100644 --- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.h +++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.h @@ -12,9 +12,9 @@ namespace quic { // A utility for extracting QUIC Client Hello messages from packets, // without needs to spin up a full QuicSession. -class ChloExtractor { +class QUIC_NO_EXPORT ChloExtractor { public: - class Delegate { + class QUIC_NO_EXPORT Delegate { public: virtual ~Delegate() {} diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc index 19158435ac6..cc90cb00539 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc @@ -21,6 +21,7 @@ QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate, if (aggregation_epoch_start_time_ == QuicTime::Zero()) { aggregation_epoch_bytes_ = bytes_acked; aggregation_epoch_start_time_ = ack_time; + ++num_ack_aggregation_epochs_; return 0; } @@ -30,10 +31,13 @@ QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate, bandwidth_estimate * (ack_time - aggregation_epoch_start_time_); // Reset the current aggregation epoch as soon as the ack arrival rate is less // than or equal to the max bandwidth. - if (aggregation_epoch_bytes_ <= expected_bytes_acked) { + if (aggregation_epoch_bytes_ <= + GetQuicFlag(FLAGS_quic_ack_aggregation_bandwidth_threshold) * + expected_bytes_acked) { // Reset to start measuring a new aggregation epoch. aggregation_epoch_bytes_ = bytes_acked; aggregation_epoch_start_time_ = ack_time; + ++num_ack_aggregation_epochs_; return 0; } @@ -195,7 +199,7 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner( } else { QUIC_CODE_COUNT_N(quic_prev_ack_time_larger_than_current_ack_time, 2, 2); } - QUIC_LOG_EVERY_N_SEC(ERROR, 5) + QUIC_LOG_EVERY_N_SEC(ERROR, 60) << "Time of the previously acked packet:" << sent_packet.last_acked_packet_ack_time.ToDebuggingValue() << " is larger than the ack time of the current packet:" diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h index 5bbb6ba7487..51f5e870819 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h @@ -100,6 +100,10 @@ class QUIC_EXPORT_PRIVATE MaxAckHeightTracker { max_ack_height_filter_.Reset(new_height, new_time); } + uint64_t num_ack_aggregation_epochs() const { + return num_ack_aggregation_epochs_; + } + private: // Tracks the maximum number of bytes acked faster than the estimated // bandwidth. @@ -113,6 +117,9 @@ class QUIC_EXPORT_PRIVATE MaxAckHeightTracker { // The time this aggregation started and the number of bytes acked during it. QuicTime aggregation_epoch_start_time_ = QuicTime::Zero(); QuicByteCount aggregation_epoch_bytes_ = 0; + // The number of ack aggregation epochs ever started, including the ongoing + // one. Stats only. + uint64_t num_ack_aggregation_epochs_ = 0; }; // An interface common to any class that can provide bandwidth samples from the @@ -273,6 +280,10 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { QuicByteCount max_ack_height() const { return max_ack_height_tracker_.Get(); } + uint64_t num_ack_aggregation_epochs() const { + return max_ack_height_tracker_.num_ack_aggregation_epochs(); + } + void SetMaxAckHeightTrackerWindowLength(QuicRoundTripCount length) { max_ack_height_tracker_.SetFilterWindowLength(length); } @@ -289,7 +300,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { // and the state of the connection at the moment the packet was sent, // specifically the information about the most recently acknowledged packet at // that moment. - struct ConnectionStateOnSentPacket { + struct QUIC_EXPORT_PRIVATE ConnectionStateOnSentPacket { // Time at which the packet is sent. QuicTime sent_time; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc index 558971aab69..59318a98590 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc @@ -551,6 +551,7 @@ TEST_F(MaxAckHeightTrackerTest, VeryAggregatedLargeAck) { AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), 1200, false); + EXPECT_EQ(2u, tracker_.num_ack_aggregation_epochs()); } TEST_F(MaxAckHeightTrackerTest, VeryAggregatedSmallAcks) { @@ -562,6 +563,7 @@ TEST_F(MaxAckHeightTrackerTest, VeryAggregatedSmallAcks) { AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), 300, false); + EXPECT_EQ(2u, tracker_.num_ack_aggregation_epochs()); } TEST_F(MaxAckHeightTrackerTest, SomewhatAggregatedLargeAck) { @@ -573,6 +575,7 @@ TEST_F(MaxAckHeightTrackerTest, SomewhatAggregatedLargeAck) { AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), 1000, false); + EXPECT_EQ(2u, tracker_.num_ack_aggregation_epochs()); } TEST_F(MaxAckHeightTrackerTest, SomewhatAggregatedSmallAcks) { @@ -584,11 +587,13 @@ TEST_F(MaxAckHeightTrackerTest, SomewhatAggregatedSmallAcks) { AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), 100, false); + EXPECT_EQ(2u, tracker_.num_ack_aggregation_epochs()); } TEST_F(MaxAckHeightTrackerTest, NotAggregated) { AggregationEpisode(bandwidth_, QuicTime::Delta::FromMilliseconds(100), 100, true); + EXPECT_LT(2u, tracker_.num_ack_aggregation_epochs()); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_drain.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_drain.h index 546962bfc1f..e083aeb655b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_drain.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_drain.h @@ -18,6 +18,7 @@ class QUIC_EXPORT_PRIVATE Bbr2DrainMode final : public Bbr2ModeBase { using Bbr2ModeBase::Bbr2ModeBase; void Enter(const Bbr2CongestionEvent& congestion_event) override; + void Leave(const Bbr2CongestionEvent& /*congestion_event*/) override {} Bbr2Mode OnCongestionEvent( QuicByteCount prior_in_flight, @@ -32,7 +33,7 @@ class QUIC_EXPORT_PRIVATE Bbr2DrainMode final : public Bbr2ModeBase { bool IsProbingForBandwidth() const override { return false; } - struct DebugState { + struct QUIC_EXPORT_PRIVATE DebugState { QuicByteCount drain_target; }; 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 d5b2742ec0d..8f08a58c6fc 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 @@ -331,6 +331,10 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { return bandwidth_sampler_.max_ack_height(); } + uint64_t num_ack_aggregation_epochs() const { + return bandwidth_sampler_.num_ack_aggregation_epochs(); + } + bool MaybeExpireMinRtt(const Bbr2CongestionEvent& congestion_event); QuicBandwidth BandwidthEstimate() const { @@ -372,7 +376,10 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { QuicBandwidth bandwidth_latest() const { return bandwidth_latest_; } QuicBandwidth bandwidth_lo() const { return bandwidth_lo_; } - void clear_bandwidth_lo() { bandwidth_lo_ = QuicBandwidth::Infinite(); } + static QuicBandwidth bandwidth_lo_default() { + return QuicBandwidth::Infinite(); + } + void clear_bandwidth_lo() { bandwidth_lo_ = bandwidth_lo_default(); } QuicByteCount inflight_latest() const { return inflight_latest_; } QuicByteCount inflight_lo() const { return inflight_lo_; } @@ -420,7 +427,7 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { // Max bandwidth in the current round. Updated once per congestion event. QuicBandwidth bandwidth_latest_ = QuicBandwidth::Zero(); // Max bandwidth of recent rounds. Updated once per round. - QuicBandwidth bandwidth_lo_ = QuicBandwidth::Infinite(); + QuicBandwidth bandwidth_lo_ = bandwidth_lo_default(); // Max inflight in the current round. Updated once per congestion event. QuicByteCount inflight_latest_ = 0; @@ -470,7 +477,9 @@ class QUIC_EXPORT_PRIVATE Bbr2ModeBase { virtual ~Bbr2ModeBase() = default; + // Called when entering/leaving this mode. virtual void Enter(const Bbr2CongestionEvent& congestion_event) = 0; + virtual void Leave(const Bbr2CongestionEvent& congestion_event) = 0; virtual Bbr2Mode OnCongestionEvent( QuicByteCount prior_in_flight, 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 887d553371f..4487cbf879b 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 @@ -48,6 +48,8 @@ Bbr2Mode Bbr2ProbeBwMode::OnCongestionEvent( } } + bool switch_to_probe_rtt = false; + if (cycle_.phase == CyclePhase::PROBE_UP) { UpdateProbeUp(prior_in_flight, congestion_event); } else if (cycle_.phase == CyclePhase::PROBE_DOWN) { @@ -55,7 +57,7 @@ Bbr2Mode Bbr2ProbeBwMode::OnCongestionEvent( // Maybe transition to PROBE_RTT at the end of this cycle. if (cycle_.phase != CyclePhase::PROBE_DOWN && model_->MaybeExpireMinRtt(congestion_event)) { - return Bbr2Mode::PROBE_RTT; + switch_to_probe_rtt = true; } } else if (cycle_.phase == CyclePhase::PROBE_CRUISE) { UpdateProbeCruise(congestion_event); @@ -63,10 +65,14 @@ Bbr2Mode Bbr2ProbeBwMode::OnCongestionEvent( UpdateProbeRefill(congestion_event); } - model_->set_pacing_gain(PacingGainForPhase(cycle_.phase)); - model_->set_cwnd_gain(Params().probe_bw_cwnd_gain); + // Do not need to set the gains if switching to PROBE_RTT, they will be set + // when Bbr2ProbeRttMode::Enter is called. + if (!switch_to_probe_rtt) { + model_->set_pacing_gain(PacingGainForPhase(cycle_.phase)); + model_->set_cwnd_gain(Params().probe_bw_cwnd_gain); + } - return Bbr2Mode::PROBE_BW; + return switch_to_probe_rtt ? Bbr2Mode::PROBE_RTT : Bbr2Mode::PROBE_BW; } Limits Bbr2ProbeBwMode::GetCwndLimits() const { @@ -194,6 +200,15 @@ bool Bbr2ProbeBwMode::IsTimeToProbeBandwidth( // long, as seen in some multi-sender simulator tests. bool Bbr2ProbeBwMode::HasStayedLongEnoughInProbeDown( const Bbr2CongestionEvent& congestion_event) const { + if (exit_probe_down_after_one_rtt_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_exit_probe_bw_down_after_one_rtt); + // Stay in PROBE_DOWN for at most the time of a min rtt, as it is done in + // BBRv1. The intention here is to figure out whether the performance + // regression in BBRv2 is because it stays in PROBE_DOWN for too long. + // TODO(wub): Consider exit after a full round instead, which typically + // indicates most(if not all) packets sent during PROBE_UP have been acked. + return HasPhaseLasted(model_->MinRtt(), congestion_event); + } // The amount of time to stay in PROBE_DOWN, as a fraction of probe wait time. const double kProbeWaitFraction = 0.2; return HasCycleLasted(cycle_.probe_wait_time * kProbeWaitFraction, @@ -271,9 +286,7 @@ void Bbr2ProbeBwMode::ProbeInflightHighUpward( return; } - if (GetQuicReloadableFlag(quic_bbr2_fix_inflight_bounds) && - congestion_event.prior_cwnd < model_->inflight_hi()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_inflight_bounds, 1, 2); + if (congestion_event.prior_cwnd < model_->inflight_hi()) { QUIC_DVLOG(3) << sender_ << " Raising inflight_hi early return: inflight_hi not fully used."; @@ -296,7 +309,7 @@ void Bbr2ProbeBwMode::ProbeInflightHighUpward( << ", (new)probe_up_acked:" << cycle_.probe_up_acked; model_->set_inflight_hi(new_inflight_hi); - } else if (GetQuicReloadableFlag(quic_bbr2_fix_inflight_bounds)) { + } else { QUIC_BUG << "Not growing inflight_hi due to wrap around. Old value:" << model_->inflight_hi() << ", new value:" << new_inflight_hi; } @@ -417,10 +430,8 @@ void Bbr2ProbeBwMode::EnterProbeCruise( << congestion_event.event_time - cycle_.phase_start_time << ", or " << cycle_.rounds_in_phase << " rounds. @ " << congestion_event.event_time; - if (GetQuicReloadableFlag(quic_bbr2_fix_inflight_bounds)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_inflight_bounds, 2, 2); - model_->cap_inflight_lo(model_->inflight_hi()); - } + + model_->cap_inflight_lo(model_->inflight_hi()); cycle_.phase = CyclePhase::PROBE_CRUISE; cycle_.rounds_in_phase = 0; cycle_.phase_start_time = congestion_event.event_time; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h index 407056b5f49..45b5a73835e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h @@ -11,6 +11,7 @@ #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_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" namespace quic { @@ -20,6 +21,7 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeBwMode final : public Bbr2ModeBase { using Bbr2ModeBase::Bbr2ModeBase; void Enter(const Bbr2CongestionEvent& congestion_event) override; + void Leave(const Bbr2CongestionEvent& /*congestion_event*/) override {} Bbr2Mode OnCongestionEvent( QuicByteCount prior_in_flight, @@ -42,7 +44,7 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeBwMode final : public Bbr2ModeBase { static const char* CyclePhaseToString(CyclePhase phase); - struct DebugState { + struct QUIC_EXPORT_PRIVATE DebugState { CyclePhase phase; QuicTime cycle_start_time = QuicTime::Zero(); QuicTime phase_start_time = QuicTime::Zero(); @@ -102,7 +104,7 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeBwMode final : public Bbr2ModeBase { void RaiseInflightHighSlope(); void ProbeInflightHighUpward(const Bbr2CongestionEvent& congestion_event); - struct Cycle { + struct QUIC_EXPORT_PRIVATE Cycle { QuicTime cycle_start_time = QuicTime::Zero(); CyclePhase phase = CyclePhase::PROBE_NOT_STARTED; uint64_t rounds_in_phase = 0; @@ -120,6 +122,10 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeBwMode final : public Bbr2ModeBase { bool last_cycle_probed_too_high_; bool last_cycle_stopped_risky_probe_; + + // Latched value of --quic_bbr2_exit_probe_bw_down_after_one_rtt. + const bool exit_probe_down_after_one_rtt_ = + GetQuicReloadableFlag(quic_bbr2_exit_probe_bw_down_after_one_rtt); }; QUIC_EXPORT_PRIVATE std::ostream& operator<<( diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.cc index fe4506b5bc0..f9c77097324 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.cc @@ -26,6 +26,12 @@ Bbr2Mode Bbr2ProbeRttMode::OnCongestionEvent( congestion_event.bytes_in_flight <= sender_->GetMinimumCongestionWindow()) { exit_time_ = congestion_event.event_time + Params().probe_rtt_duration; + QUIC_DVLOG(2) << sender_ << " PROBE_RTT exit time set to " << exit_time_ + << ". bytes_inflight:" << congestion_event.bytes_in_flight + << ", inflight_target:" << InflightTarget() + << ", min_congestion_window:" + << sender_->GetMinimumCongestionWindow() << " @ " + << congestion_event.event_time; } return Bbr2Mode::PROBE_RTT; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.h index 811c6467fa0..80a9d93d423 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.h @@ -18,6 +18,7 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeRttMode final : public Bbr2ModeBase { using Bbr2ModeBase::Bbr2ModeBase; void Enter(const Bbr2CongestionEvent& congestion_event) override; + void Leave(const Bbr2CongestionEvent& /*congestion_event*/) override {} Bbr2Mode OnCongestionEvent( QuicByteCount prior_in_flight, @@ -30,7 +31,7 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeRttMode final : public Bbr2ModeBase { bool IsProbingForBandwidth() const override { return false; } - struct DebugState { + struct QUIC_EXPORT_PRIVATE DebugState { QuicByteCount inflight_target; QuicTime exit_time = QuicTime::Zero(); }; 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 9cd40b93621..31bf29946e5 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 @@ -57,11 +57,12 @@ Bbr2Sender::Bbr2Sender(QuicTime now, QuicPacketCount initial_cwnd_in_packets, QuicPacketCount max_cwnd_in_packets, QuicRandom* random, - QuicConnectionStats* /*stats*/) + QuicConnectionStats* stats) : mode_(Bbr2Mode::STARTUP), rtt_stats_(rtt_stats), unacked_packets_(unacked_packets), random_(random), + connection_stats_(stats), params_(kDefaultMinimumCongestionWindow, max_cwnd_in_packets * kDefaultTCPMSS), model_(¶ms_, @@ -75,7 +76,7 @@ Bbr2Sender::Bbr2Sender(QuicTime now, pacing_rate_(kInitialPacingGain * QuicBandwidth::FromBytesAndTimeDelta( cwnd_, rtt_stats->SmoothedOrInitialRtt())), - startup_(this, &model_), + startup_(this, &model_, now), drain_(this, &model_), probe_bw_(this, &model_), probe_rtt_(this, &model_), @@ -114,10 +115,8 @@ const Limits& Bbr2Sender::cwnd_limits() const { return params_.cwnd_limits; } -void Bbr2Sender::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) { - model_.UpdateNetworkParameters(bandwidth, rtt); +void Bbr2Sender::AdjustNetworkParameters(const NetworkParams& params) { + model_.UpdateNetworkParameters(params.bandwidth, params.rtt); if (mode_ == Bbr2Mode::STARTUP) { const QuicByteCount prior_cwnd = cwnd_; @@ -127,7 +126,7 @@ void Bbr2Sender::AdjustNetworkParameters(QuicBandwidth bandwidth, // we are reducing the number of updates needed to arrive at the target. cwnd_ = model_.BDP(model_.BandwidthEstimate()); UpdateCongestionWindow(0); - if (!allow_cwnd_to_decrease) { + if (!params.allow_cwnd_to_decrease) { cwnd_ = std::max(cwnd_, prior_cwnd); } } @@ -170,6 +169,7 @@ void Bbr2Sender::OnCongestionEvent(bool /*rtt_updated*/, QUIC_DVLOG(2) << this << " Mode change: " << mode_ << " ==> " << next_mode << " @ " << event_time; + BBR2_MODE_DISPATCH(Leave(congestion_event)); mode_ = next_mode; BBR2_MODE_DISPATCH(Enter(congestion_event)); --mode_changes_allowed; @@ -311,6 +311,10 @@ void Bbr2Sender::OnApplicationLimited(QuicByteCount bytes_in_flight) { << ", CWND: " << GetCongestionWindow(); } +void Bbr2Sender::PopulateConnectionStats(QuicConnectionStats* stats) const { + stats->num_ack_aggregation_epochs = model_.num_ack_aggregation_epochs(); +} + bool Bbr2Sender::ShouldSendProbingPacket() const { // TODO(wub): Implement ShouldSendProbingPacket properly. if (!BBR2_MODE_DISPATCH(IsProbingForBandwidth())) { @@ -363,6 +367,9 @@ Bbr2Sender::DebugState Bbr2Sender::ExportDebugState() const { s.bandwidth_hi = model_.MaxBandwidth(); s.bandwidth_lo = model_.bandwidth_lo(); s.bandwidth_est = BandwidthEstimate(); + s.inflight_hi = model_.inflight_hi(); + s.inflight_lo = model_.inflight_lo(); + s.max_ack_height = model_.MaxAckHeight(); s.min_rtt = model_.MinRtt(); s.min_rtt_timestamp = model_.MinRttTimestamp(); s.congestion_window = cwnd_; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h index b58dd93e271..4cfd34c74c7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h @@ -30,7 +30,7 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { QuicPacketCount initial_cwnd_in_packets, QuicPacketCount max_cwnd_in_packets, QuicRandom* random, - QuicConnectionStats* /*stats*/); + QuicConnectionStats* stats); ~Bbr2Sender() override = default; @@ -47,9 +47,7 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { void SetFromConfig(const QuicConfig& config, Perspective perspective) override; - void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) override; + void AdjustNetworkParameters(const NetworkParams& params) override; void SetInitialCongestionWindowInPackets( QuicPacketCount congestion_window) override; @@ -89,6 +87,8 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { std::string GetDebugState() const override; void OnApplicationLimited(QuicByteCount bytes_in_flight) override; + + void PopulateConnectionStats(QuicConnectionStats* stats) const override; // End implementation of SendAlgorithmInterface. const Bbr2Params& Params() const { return params_; } @@ -97,7 +97,7 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { return cwnd_limits().Min(); } - struct DebugState { + struct QUIC_EXPORT_PRIVATE DebugState { Bbr2Mode mode; // Shared states. @@ -105,6 +105,9 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { QuicBandwidth bandwidth_hi = QuicBandwidth::Zero(); QuicBandwidth bandwidth_lo = QuicBandwidth::Zero(); QuicBandwidth bandwidth_est = QuicBandwidth::Zero(); + QuicByteCount inflight_hi; + QuicByteCount inflight_lo; + QuicByteCount max_ack_height; QuicTime::Delta min_rtt = QuicTime::Delta::Zero(); QuicTime min_rtt_timestamp = QuicTime::Zero(); QuicByteCount congestion_window; @@ -156,6 +159,7 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { const RttStats* const rtt_stats_; const QuicUnackedPacketMap* const unacked_packets_; QuicRandom* random_; + QuicConnectionStats* connection_stats_; const Bbr2Params params_; 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 71f3048198a..005e11deae7 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 @@ -24,6 +24,10 @@ #include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/traffic_policer.h" +using testing::AllOf; +using testing::Ge; +using testing::Le; + namespace quic { using CyclePhase = Bbr2ProbeBwMode::CyclePhase; @@ -135,9 +139,13 @@ class Bbr2DefaultTopologyTest : public Bbr2SimulatorTest { ~Bbr2DefaultTopologyTest() { const auto* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + const Bbr2Sender::DebugState& debug_state = sender_->ExportDebugState(); QUIC_LOG(INFO) << "Bbr2DefaultTopologyTest." << test_info->name() << " completed at simulated time: " - << SimulatedNow().ToDebuggingValue() / 1e6 << " sec."; + << SimulatedNow().ToDebuggingValue() / 1e6 + << " sec. packet loss:" + << sender_loss_rate_in_packets() * 100 + << "%, bw_hi:" << debug_state.bandwidth_hi; } Bbr2Sender* SetupBbr2Sender(simulator::QuicEndpoint* endpoint) { @@ -147,8 +155,9 @@ class Bbr2DefaultTopologyTest : public Bbr2SimulatorTest { endpoint->connection()->sent_packet_manager().GetRttStats(), QuicSentPacketManagerPeer::GetUnackedPacketMap( QuicConnectionPeer::GetSentPacketManager(endpoint->connection())), - kDefaultInitialCwndPackets, kDefaultMaxCongestionWindowPackets, - &random_, QuicConnectionPeer::GetStats(endpoint->connection())); + kDefaultInitialCwndPackets, + GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, + QuicConnectionPeer::GetStats(endpoint->connection())); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); return sender; @@ -413,7 +422,7 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) { } // Test Bbr2's reaction to a 100x bandwidth decrease during a transfer. -TEST_F(Bbr2DefaultTopologyTest, BandwidthDecrease) { +TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthDecrease)) { DefaultTopologyParams params; params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000); params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000); @@ -442,7 +451,7 @@ TEST_F(Bbr2DefaultTopologyTest, BandwidthDecrease) { } // Test Bbr2's reaction to a 100x bandwidth increase during a transfer. -TEST_F(Bbr2DefaultTopologyTest, BandwidthIncrease) { +TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncrease)) { DefaultTopologyParams params; params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000); params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100); @@ -668,7 +677,26 @@ TEST_F(Bbr2DefaultTopologyTest, SenderPoliced) { EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); // TODO(wub): Fix (long-term) bandwidth overestimation in policer mode, then // reduce the loss rate upper bound. - EXPECT_LE(sender_loss_rate_in_packets(), 0.15); + EXPECT_LE(sender_loss_rate_in_packets(), 0.30); +} + +// TODO(wub): Add other slowstart stats to BBRv2. +TEST_F(Bbr2DefaultTopologyTest, StartupStats) { + DefaultTopologyParams params; + CreateNetwork(params); + + DriveOutOfStartup(params); + ASSERT_FALSE(sender_->InSlowStart()); + + const QuicConnectionStats& stats = sender_connection_stats(); + EXPECT_EQ(1u, stats.slowstart_count); + EXPECT_FALSE(stats.slowstart_duration.IsRunning()); + EXPECT_THAT(stats.slowstart_duration.GetTotalElapsedTime(), + AllOf(Ge(QuicTime::Delta::FromMilliseconds(500)), + Le(QuicTime::Delta::FromMilliseconds(1500)))); + EXPECT_EQ(stats.slowstart_duration.GetTotalElapsedTime(), + QuicConnectionPeer::GetSentPacketManager(sender_connection()) + ->GetSlowStartDuration()); } // All Bbr2MultiSenderTests uses the following network topology: @@ -741,7 +769,7 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest { protected: Bbr2MultiSenderTest() { uint64_t first_connection_id = 42; - std::vector receiver_endpoint_pointers; + std::vector receiver_endpoint_pointers; for (size_t i = 0; i < MultiSenderTopologyParams::kNumLocalLinks; ++i) { std::string sender_name = QuicStrCat("Sender", i + 1); std::string receiver_name = QuicStrCat("Receiver", i + 1); @@ -770,7 +798,17 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest { ::testing::UnitTest::GetInstance()->current_test_info(); QUIC_LOG(INFO) << "Bbr2MultiSenderTest." << test_info->name() << " completed at simulated time: " - << SimulatedNow().ToDebuggingValue() / 1e6 << " sec."; + << SimulatedNow().ToDebuggingValue() / 1e6 + << " sec. Per sender stats:"; + for (size_t i = 0; i < sender_endpoints_.size(); ++i) { + QUIC_LOG(INFO) << "sender[" << i << "]: " + << sender_connection(i) + ->sent_packet_manager() + .GetSendAlgorithm() + ->GetCongestionControlType() + << ", packet_loss:" + << 100.0 * sender_loss_rate_in_packets(i) << "%"; + } } Bbr2Sender* SetupBbr2Sender(simulator::QuicEndpoint* endpoint) { @@ -780,8 +818,9 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest { endpoint->connection()->sent_packet_manager().GetRttStats(), QuicSentPacketManagerPeer::GetUnackedPacketMap( QuicConnectionPeer::GetSentPacketManager(endpoint->connection())), - kDefaultInitialCwndPackets, kDefaultMaxCongestionWindowPackets, - &random_, QuicConnectionPeer::GetStats(endpoint->connection())); + kDefaultInitialCwndPackets, + GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, + QuicConnectionPeer::GetStats(endpoint->connection())); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); return sender; @@ -794,8 +833,9 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest { endpoint->connection()->sent_packet_manager().GetRttStats(), QuicSentPacketManagerPeer::GetUnackedPacketMap( QuicConnectionPeer::GetSentPacketManager(endpoint->connection())), - kDefaultInitialCwndPackets, kDefaultMaxCongestionWindowPackets, - &random_, QuicConnectionPeer::GetStats(endpoint->connection())); + kDefaultInitialCwndPackets, + GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, + QuicConnectionPeer::GetStats(endpoint->connection())); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); return sender; @@ -808,7 +848,8 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest { TcpCubicSenderBytes* sender = new TcpCubicSenderBytes( endpoint->connection()->clock(), endpoint->connection()->sent_packet_manager().GetRttStats(), reno, - kDefaultInitialCwndPackets, kDefaultMaxCongestionWindowPackets, + kDefaultInitialCwndPackets, + GetQuicFlag(FLAGS_quic_max_congestion_window), QuicConnectionPeer::GetStats(endpoint->connection())); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); @@ -834,6 +875,19 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest { QuicTime SimulatedNow() const { return simulator_.GetClock()->Now(); } + QuicConnection* sender_connection(size_t which) { + return sender_endpoints_[which]->connection(); + } + + const QuicConnectionStats& sender_connection_stats(size_t which) { + return sender_connection(which)->GetStats(); + } + + float sender_loss_rate_in_packets(size_t which) { + return static_cast(sender_connection_stats(which).packets_lost) / + sender_connection_stats(which).packets_sent; + } + simulator::Simulator simulator_; std::vector> sender_endpoints_; std::vector> receiver_endpoints_; @@ -876,7 +930,7 @@ TEST_F(Bbr2MultiSenderTest, Bbr2VsBbr2) { ASSERT_TRUE(simulator_result); } -TEST_F(Bbr2MultiSenderTest, MultipleBbr2s) { +TEST_F(Bbr2MultiSenderTest, QUIC_SLOW_TEST(MultipleBbr2s)) { const int kTotalNumSenders = 6; for (int i = 1; i < kTotalNumSenders; ++i) { SetupBbr2Sender(sender_endpoints_[i].get()); @@ -992,7 +1046,7 @@ TEST_F(Bbr2MultiSenderTest, Bbr2VsBbr1) { ASSERT_TRUE(simulator_result); } -TEST_F(Bbr2MultiSenderTest, Bbr2VsReno) { +TEST_F(Bbr2MultiSenderTest, QUIC_SLOW_TEST(Bbr2VsReno)) { SetupTcpSender(sender_endpoints_[1].get(), /*reno=*/true); MultiSenderTopologyParams params; @@ -1023,7 +1077,7 @@ TEST_F(Bbr2MultiSenderTest, Bbr2VsReno) { ASSERT_TRUE(simulator_result); } -TEST_F(Bbr2MultiSenderTest, Bbr2VsCubic) { +TEST_F(Bbr2MultiSenderTest, QUIC_SLOW_TEST(Bbr2VsCubic)) { SetupTcpSender(sender_endpoints_[1].get(), /*reno=*/false); MultiSenderTopologyParams params; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc index 5ff10503025..187b349b327 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc @@ -12,17 +12,30 @@ namespace quic { Bbr2StartupMode::Bbr2StartupMode(const Bbr2Sender* sender, - Bbr2NetworkModel* model) + Bbr2NetworkModel* model, + QuicTime now) : Bbr2ModeBase(sender, model), full_bandwidth_reached_(false), full_bandwidth_baseline_(QuicBandwidth::Zero()), rounds_without_bandwidth_growth_(0), - loss_events_in_round_(0) {} + loss_events_in_round_(0) { + // Clear some startup stats if |sender_->connection_stats_| has been used by + // another sender, which happens e.g. when QuicConnection switch send + // algorithms. + sender_->connection_stats_->slowstart_count = 1; + sender_->connection_stats_->slowstart_duration = QuicTimeAccumulator(); + sender_->connection_stats_->slowstart_duration.Start(now); +} void Bbr2StartupMode::Enter(const Bbr2CongestionEvent& /*congestion_event*/) { QUIC_BUG << "Bbr2StartupMode::Enter should not be called"; } +void Bbr2StartupMode::Leave(const Bbr2CongestionEvent& congestion_event) { + sender_->connection_stats_->slowstart_duration.Stop( + congestion_event.event_time); +} + Bbr2Mode Bbr2StartupMode::OnCongestionEvent( QuicByteCount /*prior_in_flight*/, QuicTime /*event_time*/, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h index df3f9a747c7..80539d9a108 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h @@ -16,9 +16,12 @@ namespace quic { class Bbr2Sender; class QUIC_EXPORT_PRIVATE Bbr2StartupMode final : public Bbr2ModeBase { public: - Bbr2StartupMode(const Bbr2Sender* sender, Bbr2NetworkModel* model); + Bbr2StartupMode(const Bbr2Sender* sender, + Bbr2NetworkModel* model, + QuicTime now); void Enter(const Bbr2CongestionEvent& congestion_event) override; + void Leave(const Bbr2CongestionEvent& congestion_event) override; Bbr2Mode OnCongestionEvent( QuicByteCount prior_in_flight, @@ -35,7 +38,7 @@ class QUIC_EXPORT_PRIVATE Bbr2StartupMode final : public Bbr2ModeBase { bool FullBandwidthReached() const { return full_bandwidth_reached_; } - struct DebugState { + struct QUIC_EXPORT_PRIVATE DebugState { bool full_bandwidth_reached; QuicBandwidth full_bandwidth_baseline = QuicBandwidth::Zero(); QuicRoundTripCount round_trips_without_bandwidth_growth; 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 b0fd50d4c8b..0096ca5b095 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 @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_time_accumulator.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" @@ -136,8 +137,10 @@ BbrSender::BbrSender(QuicTime now, app_limited_since_last_probe_rtt_(false), min_rtt_since_last_probe_rtt_(QuicTime::Delta::Infinite()) { if (stats_) { + // Clear some startup stats if |stats_| has been used by another sender, + // which happens e.g. when QuicConnection switch send algorithms. stats_->slowstart_count = 0; - stats_->slowstart_start_time = QuicTime::Zero(); + stats_->slowstart_duration = QuicTimeAccumulator(); } EnterStartupMode(now); } @@ -324,27 +327,31 @@ void BbrSender::SetFromConfig(const QuicConfig& config, } } -void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) { - if (!bandwidth.IsZero()) { +void BbrSender::AdjustNetworkParameters(const NetworkParams& params) { + const QuicBandwidth& bandwidth = params.bandwidth; + const QuicTime::Delta& rtt = params.rtt; + + if (GetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_donot_inject_bandwidth); + } else if (!bandwidth.IsZero()) { max_bandwidth_.Update(bandwidth, round_trip_count_); } if (!rtt.IsZero() && (min_rtt_ > rtt || min_rtt_.IsZero())) { min_rtt_ = rtt; } - if (GetQuicReloadableFlag(quic_fix_bbr_cwnd_in_bandwidth_resumption) && - mode_ == STARTUP) { + + if (params.quic_fix_bbr_cwnd_in_bandwidth_resumption && mode_ == STARTUP) { if (bandwidth.IsZero()) { // Ignore bad bandwidth samples. - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_bbr_cwnd_in_bandwidth_resumption, 3, - 3); return; } - const QuicByteCount new_cwnd = - std::max(kMinInitialCongestionWindow * kDefaultTCPMSS, - std::min(kMaxInitialCongestionWindow * kDefaultTCPMSS, - bandwidth * rtt_stats_->SmoothedOrInitialRtt())); + const QuicByteCount new_cwnd = std::max( + kMinInitialCongestionWindow * kDefaultTCPMSS, + std::min( + kMaxInitialCongestionWindow * kDefaultTCPMSS, + bandwidth * (GetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth) + ? GetMinRtt() + : rtt_stats_->SmoothedOrInitialRtt()))); if (!rtt_stats_->smoothed_rtt().IsZero()) { QUIC_CODE_COUNT(quic_smoothed_rtt_available); } else if (rtt_stats_->initial_rtt() != @@ -353,14 +360,7 @@ void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth, } else { QUIC_CODE_COUNT(quic_default_initial_rtt); } - if (new_cwnd > congestion_window_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_bbr_cwnd_in_bandwidth_resumption, 1, - 3); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_bbr_cwnd_in_bandwidth_resumption, 2, - 3); - } - if (new_cwnd < congestion_window_ && !allow_cwnd_to_decrease) { + if (new_cwnd < congestion_window_ && !params.allow_cwnd_to_decrease) { // Only decrease cwnd if allow_cwnd_to_decrease is true. return; } @@ -372,6 +372,12 @@ void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth, set_high_cwnd_gain(kDerivedHighCWNDGain); } congestion_window_ = new_cwnd; + if (params.quic_bbr_fix_pacing_rate) { + // Pace at the rate of new_cwnd / RTT. + QuicBandwidth new_pacing_rate = + QuicBandwidth::FromBytesAndTimeDelta(congestion_window_, GetMinRtt()); + pacing_rate_ = std::max(pacing_rate_, new_pacing_rate); + } } } @@ -462,8 +468,7 @@ QuicByteCount BbrSender::ProbeRttCongestionWindow() const { void BbrSender::EnterStartupMode(QuicTime now) { if (stats_) { ++stats_->slowstart_count; - DCHECK_EQ(stats_->slowstart_start_time, QuicTime::Zero()) << mode_; - stats_->slowstart_start_time = now; + stats_->slowstart_duration.Start(now); } mode_ = STARTUP; pacing_gain_ = high_gain_; @@ -668,12 +673,7 @@ void BbrSender::MaybeExitStartupOrDrain(QuicTime now) { void BbrSender::OnExitStartup(QuicTime now) { DCHECK_EQ(mode_, STARTUP); if (stats_) { - DCHECK_NE(stats_->slowstart_start_time, QuicTime::Zero()); - if (now > stats_->slowstart_start_time) { - stats_->slowstart_duration = - now - stats_->slowstart_start_time + stats_->slowstart_duration; - } - stats_->slowstart_start_time = QuicTime::Zero(); + stats_->slowstart_duration.Stop(now); } } @@ -877,6 +877,7 @@ void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, recovery_window_ = std::max( recovery_window_, unacked_packets_->bytes_in_flight() + bytes_acked); if (GetQuicReloadableFlag(quic_bbr_one_mss_conservation)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_one_mss_conservation); recovery_window_ = std::max(recovery_window_, unacked_packets_->bytes_in_flight() + kMaxSegmentSize); @@ -904,6 +905,10 @@ void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) { << last_sent_packet_ << ", CWND: " << GetCongestionWindow(); } +void BbrSender::PopulateConnectionStats(QuicConnectionStats* stats) const { + stats->num_ack_aggregation_epochs = sampler_.num_ack_aggregation_epochs(); +} + BbrSender::DebugState BbrSender::ExportDebugState() const { return DebugState(*this); } 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 8321b8c9e27..dc512cf59be 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 @@ -62,7 +62,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { // Debug state can be exported in order to troubleshoot potential congestion // control issues. - struct DebugState { + struct QUIC_EXPORT_PRIVATE DebugState { explicit DebugState(const BbrSender& sender); DebugState(const DebugState& state); @@ -105,9 +105,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { void SetFromConfig(const QuicConfig& config, Perspective perspective) override; - void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) override; + void AdjustNetworkParameters(const NetworkParams& params) override; void SetInitialCongestionWindowInPackets( QuicPacketCount congestion_window) override; void OnCongestionEvent(bool rtt_updated, @@ -130,6 +128,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { CongestionControlType GetCongestionControlType() const override; std::string GetDebugState() const override; void OnApplicationLimited(QuicByteCount bytes_in_flight) override; + void PopulateConnectionStats(QuicConnectionStats* stats) const override; // End implementation of SendAlgorithmInterface. // Gets the number of RTTs BBR remains in STARTUP phase. 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 8ecab8736ae..6acfe80519a 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 @@ -135,8 +135,9 @@ class BbrSenderTest : public QuicTest { endpoint->connection()->clock()->Now(), rtt_stats, QuicSentPacketManagerPeer::GetUnackedPacketMap( QuicConnectionPeer::GetSentPacketManager(endpoint->connection())), - kInitialCongestionWindowPackets, kDefaultMaxCongestionWindowPackets, - &random_, QuicConnectionPeer::GetStats(endpoint->connection())); + kInitialCongestionWindowPackets, + GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, + QuicConnectionPeer::GetStats(endpoint->connection())); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); return sender; @@ -379,8 +380,9 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { bbr_sender_.connection()->clock()->Now(), rtt_stats_, QuicSentPacketManagerPeer::GetUnackedPacketMap( QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection())), - kInitialCongestionWindowPackets, kDefaultMaxCongestionWindowPackets, - &random_, QuicConnectionPeer::GetStats(bbr_sender_.connection())); + kInitialCongestionWindowPackets, + 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(), @@ -1247,10 +1249,18 @@ TEST_F(BbrSenderTest, SimpleCompetition) { TEST_F(BbrSenderTest, ResumeConnectionState) { CreateDefaultSetup(); - bbr_sender_.connection()->AdjustNetworkParameters(kTestLinkBandwidth, - kTestRtt, false); - EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth); - EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate()); + bbr_sender_.connection()->AdjustNetworkParameters( + SendAlgorithmInterface::NetworkParams(kTestLinkBandwidth, kTestRtt, + false)); + if (!GetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth)) { + EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth); + EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate()); + } + EXPECT_EQ(kTestLinkBandwidth * kTestRtt, + sender_->ExportDebugState().congestion_window); + if (GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) { + EXPECT_EQ(kTestLinkBandwidth, sender_->PacingRate(/*bytes_in_flight=*/0)); + } EXPECT_APPROX_EQ(kTestRtt, sender_->ExportDebugState().min_rtt, 0.01f); DriveOutOfStartup(); @@ -1299,14 +1309,88 @@ TEST_F(BbrSenderTest, StartupStats) { EXPECT_THAT(stats.slowstart_bytes_sent, AllOf(Ge(100000u), Le(1000000u))); EXPECT_LE(stats.slowstart_packets_lost, 10u); EXPECT_LE(stats.slowstart_bytes_lost, 10000u); - EXPECT_THAT(stats.slowstart_duration, + EXPECT_FALSE(stats.slowstart_duration.IsRunning()); + EXPECT_THAT(stats.slowstart_duration.GetTotalElapsedTime(), AllOf(Ge(QuicTime::Delta::FromMilliseconds(500)), Le(QuicTime::Delta::FromMilliseconds(1500)))); - EXPECT_EQ(QuicTime::Zero(), stats.slowstart_start_time); - EXPECT_EQ(stats.slowstart_duration, + EXPECT_EQ(stats.slowstart_duration.GetTotalElapsedTime(), QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection()) ->GetSlowStartDuration()); } +// Regression test for b/143540157. +TEST_F(BbrSenderTest, RecalculatePacingRateOnCwndChange1RTT) { + CreateDefaultSetup(); + + bbr_sender_.AddBytesToTransfer(1 * 1024 * 1024); + // Wait until an ACK comes back. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return !sender_->ExportDebugState().min_rtt.IsZero(); }, + timeout); + ASSERT_TRUE(simulator_result); + const QuicByteCount previous_cwnd = + sender_->ExportDebugState().congestion_window; + + // Bootstrap cwnd. + bbr_sender_.connection()->AdjustNetworkParameters( + SendAlgorithmInterface::NetworkParams(kTestLinkBandwidth, + QuicTime::Delta::Zero(), false)); + if (!GetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth)) { + EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth); + EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate()); + } + EXPECT_LT(previous_cwnd, sender_->ExportDebugState().congestion_window); + + if (GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) { + // Verify pacing rate is re-calculated based on the new cwnd and min_rtt. + EXPECT_APPROX_EQ(QuicBandwidth::FromBytesAndTimeDelta( + sender_->ExportDebugState().congestion_window, + sender_->ExportDebugState().min_rtt), + sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f); + } else { + // Pacing rate is still based on initial cwnd. + EXPECT_APPROX_EQ(QuicBandwidth::FromBytesAndTimeDelta( + kInitialCongestionWindowPackets * kDefaultTCPMSS, + sender_->ExportDebugState().min_rtt), + sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f); + } +} + +TEST_F(BbrSenderTest, RecalculatePacingRateOnCwndChange0RTT) { + CreateDefaultSetup(); + // Initial RTT is available. + const_cast(rtt_stats_)->set_initial_rtt(kTestRtt); + + // Bootstrap cwnd. + bbr_sender_.connection()->AdjustNetworkParameters( + SendAlgorithmInterface::NetworkParams(kTestLinkBandwidth, + QuicTime::Delta::Zero(), false)); + if (!GetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth)) { + EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth); + EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate()); + } + EXPECT_LT(kInitialCongestionWindowPackets * kDefaultTCPMSS, + sender_->ExportDebugState().congestion_window); + // No Rtt sample is available. + EXPECT_TRUE(sender_->ExportDebugState().min_rtt.IsZero()); + + if (GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) { + // Verify pacing rate is re-calculated based on the new cwnd and initial + // RTT. + EXPECT_APPROX_EQ(QuicBandwidth::FromBytesAndTimeDelta( + sender_->ExportDebugState().congestion_window, + rtt_stats_->initial_rtt()), + sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f); + } else { + // Pacing rate is still based on initial cwnd. + EXPECT_APPROX_EQ( + 2.885f * QuicBandwidth::FromBytesAndTimeDelta( + kInitialCongestionWindowPackets * kDefaultTCPMSS, + rtt_stats_->initial_rtt()), + sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f); + } +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc index 3502031a7c7..8798322eb76 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc @@ -32,6 +32,7 @@ GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type) : loss_detection_timeout_(QuicTime::Zero()), reordering_threshold_(kNumberOfNacksBeforeRetransmission), use_adaptive_reordering_threshold_(false), + use_adaptive_time_threshold_(false), least_in_flight_(1), packet_number_space_(NUM_PACKET_NUMBER_SPACES) { SetLossDetectionType(loss_type); @@ -39,7 +40,6 @@ GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type) void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) { loss_detection_timeout_ = QuicTime::Zero(); - largest_sent_on_spurious_retransmit_.Clear(); loss_type_ = loss_type; if (loss_type == kAdaptiveTime) { reordering_shift_ = kDefaultAdaptiveLossDelayShift; @@ -185,43 +185,14 @@ QuicTime GeneralLossAlgorithm::GetLossTimeout() const { return loss_detection_timeout_; } -void GeneralLossAlgorithm::SpuriousRetransmitDetected( - const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber spurious_retransmission) { - if (loss_type_ != kAdaptiveTime || reordering_shift_ == 0) { - return; - } - // Calculate the extra time needed so this wouldn't have been declared lost. - // Extra time needed is based on how long it's been since the spurious - // retransmission was sent, because the SRTT and latest RTT may have changed. - QuicTime::Delta extra_time_needed = - time - - unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time; - // Increase the reordering fraction until enough time would be allowed. - QuicTime::Delta max_rtt = - std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); - - if (largest_sent_on_spurious_retransmit_.IsInitialized() && - spurious_retransmission <= largest_sent_on_spurious_retransmit_) { - return; - } - largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet(); - QuicTime::Delta proposed_extra_time(QuicTime::Delta::Zero()); - do { - proposed_extra_time = max_rtt >> reordering_shift_; - --reordering_shift_; - } while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0); -} - void GeneralLossAlgorithm::SpuriousLossDetected( const QuicUnackedPacketMap& unacked_packets, const RttStats& rtt_stats, QuicTime ack_receive_time, QuicPacketNumber packet_number, QuicPacketNumber previous_largest_acked) { - if (loss_type_ == kAdaptiveTime && reordering_shift_ > 0) { + if ((loss_type_ == kAdaptiveTime || use_adaptive_time_threshold_) && + reordering_shift_ > 0) { // Increase reordering fraction such that the packet would not have been // declared lost. QuicTime::Delta time_needed = diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h index c9da8370e20..fb85523c63e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h @@ -47,13 +47,6 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { // Returns a non-zero value when the early retransmit timer is active. QuicTime GetLossTimeout() const override; - // Increases the loss detection threshold for time loss detection. - void SpuriousRetransmitDetected( - const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber spurious_retransmission) override; - // Called to increases time and/or packet threshold. void SpuriousLossDetected(const QuicUnackedPacketMap& unacked_packets, const RttStats& rtt_stats, @@ -77,11 +70,14 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { use_adaptive_reordering_threshold_ = true; } + bool use_adaptive_time_threshold() const { + return use_adaptive_time_threshold_; + } + + void enable_adaptive_time_threshold() { use_adaptive_time_threshold_ = true; } + private: QuicTime loss_detection_timeout_; - // Largest sent packet when a spurious retransmit is detected. - // Prevents increasing the reordering threshold multiple times per epoch. - QuicPacketNumber largest_sent_on_spurious_retransmit_; LossDetectionType loss_type_; // Fraction of a max(SRTT, latest_rtt) to permit reordering before declaring // loss. Fraction calculated by shifting max(SRTT, latest_rtt) to the right @@ -91,6 +87,8 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { QuicPacketCount reordering_threshold_; // If true, uses adaptive reordering threshold for loss detection. bool use_adaptive_reordering_threshold_; + // If true, uses adaptive time threshold for time based loss detection. + bool use_adaptive_time_threshold_; // The largest newly acked from the previous call to DetectLosses. QuicPacketNumber largest_previously_acked_; // The least in flight packet. Loss detection should start from this. Please 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 dba6d5b5484..aaf9c7c32bc 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 @@ -41,16 +41,16 @@ class GeneralLossAlgorithmTest : public QuicTest { PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, false, false); packet.retransmittable_frames.push_back(QuicFrame(frame)); - unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(), - NOT_RETRANSMISSION, clock_.Now(), true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(), + true); } void SendAckPacket(uint64_t packet_number) { SerializedPacket packet(QuicPacketNumber(packet_number), PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, true, false); - unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(), - NOT_RETRANSMISSION, clock_.Now(), false); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(), + false); } void VerifyLosses(uint64_t largest_newly_acked, @@ -514,21 +514,51 @@ TEST_F(GeneralLossAlgorithmTest, IncreaseThresholdUponSpuriousLoss) { // Advance the time 1/4 RTT and indicate the loss was spurious. // The new threshold should be 1/2 RTT. clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); - if (GetQuicReloadableFlag(quic_detect_spurious_loss)) { - loss_algorithm_.SpuriousLossDetected(unacked_packets_, rtt_stats_, - clock_.Now(), QuicPacketNumber(1), - QuicPacketNumber(2)); - EXPECT_EQ(1, loss_algorithm_.reordering_shift()); - return; - } - loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(), - rtt_stats_, QuicPacketNumber(11)); + loss_algorithm_.SpuriousLossDetected(unacked_packets_, rtt_stats_, + clock_.Now(), QuicPacketNumber(1), + QuicPacketNumber(2)); EXPECT_EQ(1, loss_algorithm_.reordering_shift()); +} + +TEST_F(GeneralLossAlgorithmTest, IncreaseTimeThresholdUponSpuriousLoss) { + loss_algorithm_.SetLossDetectionType(kIetfLossDetection); + loss_algorithm_.enable_adaptive_time_threshold(); + loss_algorithm_.set_reordering_shift(kDefaultLossDelayShift); + EXPECT_EQ(kDefaultLossDelayShift, loss_algorithm_.reordering_shift()); + EXPECT_TRUE(loss_algorithm_.use_adaptive_time_threshold()); + const size_t kNumSentPackets = 10; + // Transmit 2 packets at 1/10th an RTT interval. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); + } + EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now()); + AckedPacketVector packets_acked; + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Packet 1 should not be lost until 1/4 RTTs pass. + unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); + packets_acked.push_back(AckedPacket( + QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector{}); + packets_acked.clear(); + // Expect the timer to be set to 1/4 RTT's in the future. + EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 4), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + VerifyLosses(2, packets_acked, std::vector{}); + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); + VerifyLosses(2, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Retransmit packet 1 as 11 and 2 as 12. + SendDataPacket(11); + SendDataPacket(12); - // Detect another spurious retransmit and ensure the threshold doesn't - // increase again. - loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(), - rtt_stats_, QuicPacketNumber(12)); + // Advance the time 1/4 RTT and indicate the loss was spurious. + // The new threshold should be 1/2 RTT. + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); + loss_algorithm_.SpuriousLossDetected(unacked_packets_, rtt_stats_, + clock_.Now(), QuicPacketNumber(1), + QuicPacketNumber(2)); EXPECT_EQ(1, loss_algorithm_.reordering_shift()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h index f6867853dab..af9c1962656 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h @@ -35,16 +35,6 @@ class QUIC_EXPORT_PRIVATE LossDetectionInterface { // Returns QuicTime::Zero if no alarm needs to be set. virtual QuicTime GetLossTimeout() const = 0; - // Called when a |spurious_retransmission| is detected. The original - // transmission must have been caused by DetectLosses. - // TODO(fayang): Remove this method when deprecating - // quic_detect_spurious_loss. - virtual void SpuriousRetransmitDetected( - const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber spurious_retransmission) = 0; - // Called when |packet_number| was detected lost but gets acked later. virtual void SpuriousLossDetected( const QuicUnackedPacketMap& unacked_packets, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h index 997faa402e8..1c0466a424f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h @@ -73,11 +73,6 @@ class QUIC_EXPORT_PRIVATE RttStats { QuicTime::Delta mean_deviation() const { return mean_deviation_; } - QuicTime::Delta max_ack_delay() const { - DCHECK(!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)); - return max_ack_delay_; - } - QuicTime last_update_time() const { return last_update_time_; } bool ignore_max_ack_delay() const { return ignore_max_ack_delay_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc index 4d259d3b248..be5f4d679f0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc @@ -35,28 +35,17 @@ TEST_F(RttStatsTest, SmoothedRtt) { QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); - } // Verify that a plausible ack delay increases the max ack delay. rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(400), QuicTime::Delta::FromMilliseconds(100), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), - rtt_stats_.max_ack_delay()); - } // Verify that Smoothed RTT includes max ack delay if it's reasonable. rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(350), QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), - rtt_stats_.max_ack_delay()); - } // Verify that large erroneous ack_delay does not change Smoothed RTT. rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), QuicTime::Delta::FromMilliseconds(300), @@ -64,10 +53,6 @@ TEST_F(RttStatsTest, SmoothedRtt) { EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(287500), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), - rtt_stats_.max_ack_delay()); - } } TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) { @@ -78,18 +63,12 @@ TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) { QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); - } // Verify that a plausible ack delay increases the max ack delay. rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), QuicTime::Delta::FromMilliseconds(100), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); - } // Verify that Smoothed RTT includes max ack delay if it's reasonable. rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); @@ -102,9 +81,6 @@ TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) { EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(287500), rtt_stats_.smoothed_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); - } } // Ensure that the potential rounding artifacts in EWMA calculation do not cause @@ -225,9 +201,6 @@ TEST_F(RttStatsTest, ResetAfterConnectionMigrations) { EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(0), rtt_stats_.max_ack_delay()); - } rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), QuicTime::Delta::FromMilliseconds(100), @@ -235,19 +208,12 @@ TEST_F(RttStatsTest, ResetAfterConnectionMigrations) { EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), - rtt_stats_.max_ack_delay()); - } // Reset rtt stats on connection migrations. rtt_stats_.OnConnectionMigration(); EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt()); EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt()); - if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); - } } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc index b641eb4bb3d..83529c6e76c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc @@ -27,7 +27,8 @@ SendAlgorithmInterface* SendAlgorithmInterface::Create( QuicRandom* random, QuicConnectionStats* stats, QuicPacketCount initial_congestion_window) { - QuicPacketCount max_congestion_window = kDefaultMaxCongestionWindowPackets; + QuicPacketCount max_congestion_window = + GetQuicFlag(FLAGS_quic_max_congestion_window); switch (congestion_control_type) { case kGoogCC: // GoogCC is not supported by quic/core, fall back to BBR. case kBBR: diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h index dab8fc294a7..628e0d62e0c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h @@ -29,10 +29,42 @@ typedef uint64_t QuicRoundTripCount; class CachedNetworkParameters; class RttStats; -const QuicPacketCount kDefaultMaxCongestionWindowPackets = 2000; - class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { public: + // Network Params for AdjustNetworkParameters. + struct QUIC_NO_EXPORT NetworkParams { + NetworkParams() + : NetworkParams(QuicBandwidth::Zero(), QuicTime::Delta::Zero(), false) { + } + NetworkParams(const QuicBandwidth& bandwidth, + const QuicTime::Delta& rtt, + bool allow_cwnd_to_decrease) + : bandwidth(bandwidth), + rtt(rtt), + allow_cwnd_to_decrease(allow_cwnd_to_decrease), + quic_fix_bbr_cwnd_in_bandwidth_resumption( + GetQuicReloadableFlag(quic_fix_bbr_cwnd_in_bandwidth_resumption)), + quic_bbr_fix_pacing_rate( + GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) {} + + bool operator==(const NetworkParams& other) const { + return bandwidth == other.bandwidth && rtt == other.rtt && + allow_cwnd_to_decrease == other.allow_cwnd_to_decrease && + quic_fix_bbr_cwnd_in_bandwidth_resumption == + other.quic_fix_bbr_cwnd_in_bandwidth_resumption && + quic_bbr_fix_pacing_rate == other.quic_bbr_fix_pacing_rate; + } + + QuicBandwidth bandwidth; + QuicTime::Delta rtt; + bool allow_cwnd_to_decrease; + // Code changes that are controlled by flags. + // TODO(b/131899599): Remove when impact of fix is measured. + bool quic_fix_bbr_cwnd_in_bandwidth_resumption; + // TODO(b/143540157): Remove when impact of fix is measured. + bool quic_bbr_fix_pacing_rate; + }; + static SendAlgorithmInterface* Create( const QuicClock* clock, const RttStats* rtt_stats, @@ -117,9 +149,7 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { // Notifies the congestion control algorithm of an external network // measurement or prediction. Either |bandwidth| or |rtt| may be zero if no // sample is available. - virtual void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) = 0; + virtual void AdjustNetworkParameters(const NetworkParams& params) = 0; // Retrieves debugging information about the current state of the // send algorithm. @@ -138,6 +168,9 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { // such cases, it should use the internal state it uses for congestion control // for that. virtual void OnApplicationLimited(QuicByteCount bytes_in_flight) = 0; + + // Called before connection close to collect stats. + virtual void PopulateConnectionStats(QuicConnectionStats* stats) const = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc index 28f284e4ce0..cf400e5a1cc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc @@ -105,15 +105,11 @@ void TcpCubicSenderBytes::SetFromConfig(const QuicConfig& config, } } -void TcpCubicSenderBytes::AdjustNetworkParameters( - QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool /*allow_cwnd_to_decrease*/) { - if (bandwidth.IsZero() || rtt.IsZero()) { +void TcpCubicSenderBytes::AdjustNetworkParameters(const NetworkParams& params) { + if (params.bandwidth.IsZero() || params.rtt.IsZero()) { return; } - - SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt); + SetCongestionWindowFromBandwidthAndRtt(params.bandwidth, params.rtt); } float TcpCubicSenderBytes::RenoBeta() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h index 50f7981b81e..9144b8a5913 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h @@ -46,9 +46,7 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { // Start implementation of SendAlgorithmInterface. void SetFromConfig(const QuicConfig& config, Perspective perspective) override; - void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) override; + void AdjustNetworkParameters(const NetworkParams& params) override; void SetNumEmulatedConnections(int num_connections); void SetInitialCongestionWindowInPackets( QuicPacketCount congestion_window) override; @@ -75,6 +73,7 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { bool ShouldSendProbingPacket() const override; std::string GetDebugState() const override; void OnApplicationLimited(QuicByteCount bytes_in_flight) override; + void PopulateConnectionStats(QuicConnectionStats* /*stats*/) const override {} // End implementation of SendAlgorithmInterface. QuicByteCount min_congestion_window() const { return min_congestion_window_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc index 4c51742cd3e..04c0e8a41ec 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc @@ -677,20 +677,29 @@ TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) { const QuicBandwidth kBandwidthEstimate = QuicBandwidth::FromBytesPerSecond(kNumberOfPackets * kDefaultTCPMSS); const QuicTime::Delta kRttEstimate = QuicTime::Delta::FromSeconds(1); - sender_->AdjustNetworkParameters(kBandwidthEstimate, kRttEstimate, false); + + SendAlgorithmInterface::NetworkParams network_param; + network_param.bandwidth = kBandwidthEstimate; + network_param.rtt = kRttEstimate; + sender_->AdjustNetworkParameters(network_param); EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); // Resume with an illegal value of 0 and verify the server ignores it. - sender_->AdjustNetworkParameters(QuicBandwidth::Zero(), kRttEstimate, false); + SendAlgorithmInterface::NetworkParams network_param_no_bandwidth; + network_param_no_bandwidth.bandwidth = QuicBandwidth::Zero(); + network_param_no_bandwidth.rtt = kRttEstimate; + sender_->AdjustNetworkParameters(network_param_no_bandwidth); EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); // Resumed CWND is limited to be in a sensible range. const QuicBandwidth kUnreasonableBandwidth = - QuicBandwidth::FromBytesPerSecond((kMaxCongestionWindowPackets + 1) * + QuicBandwidth::FromBytesPerSecond((kMaxResumptionCongestionWindow + 1) * kDefaultTCPMSS); - sender_->AdjustNetworkParameters(kUnreasonableBandwidth, - QuicTime::Delta::FromSeconds(1), false); - EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS, + SendAlgorithmInterface::NetworkParams network_param_large_bandwidth; + network_param_large_bandwidth.bandwidth = kUnreasonableBandwidth; + network_param_large_bandwidth.rtt = QuicTime::Delta::FromSeconds(1); + sender_->AdjustNetworkParameters(network_param_large_bandwidth); + EXPECT_EQ(kMaxResumptionCongestionWindow * kDefaultTCPMSS, sender_->GetCongestionWindow()); } @@ -781,14 +790,16 @@ TEST_F(TcpCubicSenderBytesTest, DefaultMaxCwnd) { AckedPacketVector acked_packets; LostPacketVector missing_packets; - for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) { + QuicPacketCount max_congestion_window = + GetQuicFlag(FLAGS_quic_max_congestion_window); + for (uint64_t i = 1; i < max_congestion_window; ++i) { acked_packets.clear(); acked_packets.push_back( AckedPacket(QuicPacketNumber(i), 1350, QuicTime::Zero())); sender->OnCongestionEvent(true, sender->GetCongestionWindow(), clock_.Now(), acked_packets, missing_packets); } - EXPECT_EQ(kDefaultMaxCongestionWindowPackets, + EXPECT_EQ(max_congestion_window, sender->GetCongestionWindow() / kDefaultTCPMSS); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc index 3b669e23e25..4e7f07b3b10 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc @@ -70,17 +70,6 @@ QuicTime UberLossAlgorithm::GetLossTimeout() const { return loss_timeout; } -void UberLossAlgorithm::SpuriousRetransmitDetected( - const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber spurious_retransmission) { - general_loss_algorithms_[unacked_packets.GetPacketNumberSpace( - spurious_retransmission)] - .SpuriousRetransmitDetected(unacked_packets, time, rtt_stats, - spurious_retransmission); -} - void UberLossAlgorithm::SpuriousLossDetected( const QuicUnackedPacketMap& unacked_packets, const RttStats& rtt_stats, @@ -104,4 +93,10 @@ void UberLossAlgorithm::EnableAdaptiveReorderingThreshold() { } } +void UberLossAlgorithm::EnableAdaptiveTimeThreshold() { + for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { + general_loss_algorithms_[i].enable_adaptive_time_threshold(); + } +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h index 0d2b788ea96..f922bba1abf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h @@ -41,13 +41,6 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { // Returns the earliest time the early retransmit timer should be active. QuicTime GetLossTimeout() const override; - // Increases the loss detection threshold for time loss detection. - void SpuriousRetransmitDetected( - const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber spurious_retransmission) override; - // Called to increases time or packet threshold. void SpuriousLossDetected(const QuicUnackedPacketMap& unacked_packets, const RttStats& rtt_stats, @@ -61,6 +54,9 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { // Enable adaptive reordering threshold of all packet number spaces. void EnableAdaptiveReorderingThreshold(); + // Enable adaptive time threshold of all packet number spaces. + void EnableAdaptiveTimeThreshold(); + private: friend class test::QuicSentPacketManagerPeer; 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 8d69c136c0a..79d0ff76867 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 @@ -48,8 +48,8 @@ class UberLossAlgorithmTest : public QuicTest { false, false); packet.encryption_level = encryption_level; packet.retransmittable_frames.push_back(QuicFrame(frame)); - unacked_packets_->AddSentPacket(&packet, QuicPacketNumber(), - NOT_RETRANSMISSION, clock_.Now(), true); + unacked_packets_->AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(), + true); } void AckPackets(const std::vector& packets_acked) { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h index 8729895d9e0..4176d730536 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h @@ -38,14 +38,14 @@ namespace quic { // Compares two values and returns true if the first is less than or equal // to the second. template -struct MinFilter { +struct QUIC_EXPORT_PRIVATE MinFilter { bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; } }; // Compares two values and returns true if the first is greater than or equal // to the second. template -struct MaxFilter { +struct QUIC_EXPORT_PRIVATE MaxFilter { bool operator()(const T& lhs, const T& rhs) const { return lhs >= rhs; } }; @@ -63,7 +63,7 @@ struct MaxFilter { // two timestamps. Has to be the type of (a - b) if both |a| and |b| are // of type TimeT. template -class WindowedFilter { +class QUIC_EXPORT_PRIVATE WindowedFilter { public: // |window_length| is the period after which a best estimate expires. // |zero_value| is used as the uninitialized value for objects of T. @@ -143,7 +143,7 @@ class WindowedFilter { T GetThirdBest() const { return estimates_[2].sample; } private: - struct Sample { + struct QUIC_EXPORT_PRIVATE Sample { T sample; TimeT time; Sample(T init_sample, TimeT init_time) diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.cc index 405292ea083..a3173f54456 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.cc @@ -168,7 +168,7 @@ size_t AeadBaseEncrypter::GetIVSize() const { } size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { - return ciphertext_size - auth_tag_size_; + return ciphertext_size - std::min(ciphertext_size, auth_tag_size_); } size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc index dd8a680ec32..9ce4bda19ba 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc @@ -269,7 +269,7 @@ TEST_F(Aes128Gcm12DecrypterTest, Decrypt) { // handle an AAD that is set to nullptr, as opposed // to a zero-length, non-nullptr pointer. aad.length() ? aad : QuicStringPiece(), ciphertext)); - if (!decrypted.get()) { + if (!decrypted) { EXPECT_FALSE(has_pt); continue; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc index 5ccc44da3c6..d529d5d60d4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc @@ -228,6 +228,7 @@ TEST_F(Aes128Gcm12EncrypterTest, GetMaxPlaintextSize) { EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012)); EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112)); EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22)); + EXPECT_EQ(0u, encrypter.GetMaxPlaintextSize(11)); } TEST_F(Aes128Gcm12EncrypterTest, GetCiphertextSize) { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc index 54793f8c6e2..579f76d498d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc @@ -258,7 +258,7 @@ TEST_F(Aes128GcmDecrypterTest, Decrypt) { // handle an AAD that is set to nullptr, as opposed // to a zero-length, non-nullptr pointer. aad.length() ? aad : QuicStringPiece(), ciphertext)); - if (!decrypted.get()) { + if (!decrypted) { EXPECT_FALSE(has_pt); continue; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc index 73a3b3deec4..b3d61c7798f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc @@ -262,7 +262,7 @@ TEST_F(Aes256GcmDecrypterTest, Decrypt) { // handle an AAD that is set to nullptr, as opposed // to a zero-length, non-nullptr pointer. aad.length() ? aad : QuicStringPiece(), ciphertext)); - if (!decrypted.get()) { + if (!decrypted) { EXPECT_FALSE(has_pt); continue; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc index a9c4999683b..930af24a3b3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc @@ -159,7 +159,7 @@ TEST_F(ChaCha20Poly1305DecrypterTest, Decrypt) { // is set to nullptr, as opposed to a zero-length, non-nullptr pointer. QuicStringPiece(aad.length() ? aad.data() : nullptr, aad.length()), ct)); - if (!decrypted.get()) { + if (!decrypted) { EXPECT_FALSE(has_pt); continue; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc index ce4dea9f385..90052d60520 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc @@ -154,7 +154,7 @@ TEST_F(ChaCha20Poly1305TlsDecrypterTest, Decrypt) { // is set to nullptr, as opposed to a zero-length, non-nullptr pointer. QuicStringPiece(aad.length() ? aad.data() : nullptr, aad.length()), ct)); - if (!decrypted.get()) { + if (!decrypted) { EXPECT_FALSE(has_pt); continue; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_decrypter.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_decrypter.cc index eb1e95fb98c..c67fd89d4ef 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_decrypter.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_decrypter.cc @@ -10,6 +10,7 @@ #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -30,7 +31,7 @@ std::string ChaChaBaseDecrypter::GenerateHeaderProtectionMask( } const uint8_t* nonce = reinterpret_cast(sample.data()) + 4; uint32_t counter; - QuicDataReader(sample.data(), 4, Endianness::HOST_BYTE_ORDER) + QuicDataReader(sample.data(), 4, quiche::HOST_BYTE_ORDER) .ReadUInt32(&counter); const uint8_t zeroes[] = {0, 0, 0, 0, 0}; std::string out(QUIC_ARRAYSIZE(zeroes), 0); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_encrypter.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_encrypter.cc index 04d902f4b4c..9c465a944c9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_encrypter.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha_base_encrypter.cc @@ -8,6 +8,7 @@ #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -27,7 +28,7 @@ std::string ChaChaBaseEncrypter::GenerateHeaderProtectionMask( } const uint8_t* nonce = reinterpret_cast(sample.data()) + 4; uint32_t counter; - QuicDataReader(sample.data(), 4, Endianness::HOST_BYTE_ORDER) + QuicDataReader(sample.data(), 4, quiche::HOST_BYTE_ORDER) .ReadUInt32(&counter); const uint8_t zeroes[] = {0, 0, 0, 0, 0}; std::string out(QUIC_ARRAYSIZE(zeroes), 0); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.cc index 6feaa8a0e9d..c3dd2aa142b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -117,7 +118,8 @@ bool CryptoFramer::HasTag(QuicTag tag) const { } void CryptoFramer::ForceHandshake() { - QuicDataReader reader(buffer_.data(), buffer_.length(), HOST_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), buffer_.length(), + quiche::HOST_BYTE_ORDER); for (const std::pair& item : tags_and_lengths_) { QuicStringPiece value; if (reader.BytesRemaining() < item.second) { @@ -156,7 +158,7 @@ std::unique_ptr CryptoFramer::ConstructHandshakeMessage( } std::unique_ptr buffer(new char[len]); - QuicDataWriter writer(len, buffer.get(), HOST_BYTE_ORDER); + QuicDataWriter writer(len, buffer.get(), quiche::HOST_BYTE_ORDER); if (!writer.WriteTag(message.tag())) { DCHECK(false) << "Failed to write message tag."; return nullptr; @@ -244,7 +246,8 @@ void CryptoFramer::Clear() { QuicErrorCode CryptoFramer::Process(QuicStringPiece input) { // Add this data to the buffer. buffer_.append(input.data(), input.length()); - QuicDataReader reader(buffer_.data(), buffer_.length(), HOST_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), buffer_.length(), + quiche::HOST_BYTE_ORDER); switch (state_) { case STATE_READING_TAG: diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc index 022a86b9227..56f0bd62a1f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc @@ -12,10 +12,10 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -57,7 +57,7 @@ void CryptoHandshakeMessage::Clear() { } const QuicData& CryptoHandshakeMessage::GetSerialized() const { - if (!serialized_.get()) { + if (!serialized_) { serialized_ = CryptoFramer::ConstructHandshakeMessage(*this); } return *serialized_; @@ -73,14 +73,15 @@ void CryptoHandshakeMessage::SetVersionVector( QuicVersionLabelVector version_labels; for (ParsedQuicVersion version : versions) { version_labels.push_back( - QuicEndian::HostToNet32(CreateQuicVersionLabel(version))); + quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version))); } SetVector(tag, version_labels); } void CryptoHandshakeMessage::SetVersion(QuicTag tag, ParsedQuicVersion version) { - SetValue(tag, QuicEndian::HostToNet32(CreateQuicVersionLabel(version))); + SetValue(tag, + quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version))); } void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, @@ -128,7 +129,7 @@ QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList( } for (size_t i = 0; i < out->size(); ++i) { - (*out)[i] = QuicEndian::HostToNet32((*out)[i]); + (*out)[i] = quiche::QuicheEndian::HostToNet32((*out)[i]); } return QUIC_NO_ERROR; @@ -142,7 +143,7 @@ QuicErrorCode CryptoHandshakeMessage::GetVersionLabel( return error; } - *out = QuicEndian::HostToNet32(*out); + *out = quiche::QuicheEndian::HostToNet32(*out); return QUIC_NO_ERROR; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc index f595581601f..b6dfdd4cdaa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc @@ -6,8 +6,8 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc index ecbcab82e53..67cd531dd72 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc @@ -14,7 +14,6 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" -using quic::Perspective; using std::cerr; using std::cout; using std::endl; 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 4d5a890bba2..9707fb5b0ca 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 @@ -176,6 +176,11 @@ const QuicTag kILD3 = TAG('I', 'L', 'D', '3'); // IETF style loss detection // with 1/4 RTT time threshold // and adaptive packet // threshold +const QuicTag kILD4 = TAG('I', 'L', 'D', '4'); // IETF style loss detection + // with both adaptive time + // threshold (default 1/4 RTT) + // and adaptive packet + // threshold // TODO(fayang): Remove this connection option when QUIC_VERSION_35, is removed // Since MAX_HEADER_LIST_SIZE settings frame is supported instead. const QuicTag kSMHL = TAG('S', 'M', 'H', 'L'); // Support MAX_HEADER_LIST_SIZE @@ -194,6 +199,16 @@ const QuicTag k8PTO = TAG('8', 'P', 'T', 'O'); // Closes connection on 8 // consecutive PTOs. const QuicTag kPTOS = TAG('P', 'T', 'O', 'S'); // Skip packet number before // sending the last PTO. +const QuicTag kPTOA = TAG('P', 'T', 'O', 'A'); // Do not add max ack delay + // when computing PTO timeout + // if an immediate ACK is + // expected. +const QuicTag kPEB1 = TAG('P', 'E', 'B', '1'); // Start exponential backoff + // since 1st PTO. +const QuicTag kPEB2 = TAG('P', 'E', 'B', '2'); // Start exponential backoff + // since 2nd PTO. +const QuicTag kPVS1 = TAG('P', 'V', 'S', '1'); // Use 2 * rttvar when + // calculating PTO timeout. // Optional support of truncated Connection IDs. If sent by a peer, the value // is the minimum number of bytes allowed for the connection ID sent to the @@ -217,6 +232,12 @@ const QuicTag kBWS2 = TAG('B', 'W', 'S', '2'); // Server bw resumption v2. const QuicTag kBWS3 = TAG('B', 'W', 'S', '3'); // QUIC Initial CWND - Control. const QuicTag kBWS4 = TAG('B', 'W', 'S', '4'); // QUIC Initial CWND - Enabled. const QuicTag kBWS5 = TAG('B', 'W', 'S', '5'); // QUIC Initial CWND up and down +const QuicTag kBWS6 = TAG('B', 'W', 'S', '6'); // QUIC Initial CWND - Enabled + // with 0.5 * default + // multiplier. +const QuicTag kBWS7 = TAG('B', 'W', 'S', '7'); // QUIC Initial CWND - Enabled + // with 0.75 * default + // multiplier. // Enable path MTU discovery experiment. const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc index b869f8bdeea..2db49d22a42 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc @@ -22,7 +22,6 @@ #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -33,6 +32,7 @@ #include "net/third_party/quiche/src/quic/test_tools/mock_random.h" #include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace test { @@ -125,7 +125,7 @@ class CryptoServerTest : public QuicTestWithParam { config_.GenerateConfig(rand_, &clock_, config_options_); primary_config.set_primary_time(clock_.WallNow().ToUNIXSeconds()); std::unique_ptr msg( - config_.AddConfig(std::move(primary_config), clock_.WallNow())); + config_.AddConfig(primary_config, clock_.WallNow())); QuicStringPiece orbit; CHECK(msg->GetStringPiece(kORBT, &orbit)); 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 59cc9673653..037990ae797 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 @@ -30,6 +30,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -109,8 +110,8 @@ void CryptoUtils::SetKeyAndIV(const EVP_MD* prf, namespace { -static_assert(kQuicIetfDraftVersion == 23, "Salts do not match draft version"); -// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-23#section-5.2 +static_assert(kQuicIetfDraftVersion == 24, "Salts do not match draft version"); +// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-24#section-5.2 const uint8_t kDraft23InitialSalt[] = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02}; @@ -141,7 +142,7 @@ const uint8_t kQ099Salt[] = {0xc0, 0xa2, 0xee, 0x20, 0xc7, 0xe1, 0x83, const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version, size_t* out_len) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync with initial encryption salts"); switch (version.handshake_protocol) { case PROTOCOL_QUIC_CRYPTO: @@ -299,7 +300,7 @@ bool CryptoUtils::DeriveKeys(const ParsedQuicVersion& version, psk_premaster_secret = std::make_unique(psk_premaster_secret_size); QuicDataWriter writer(psk_premaster_secret_size, psk_premaster_secret.get(), - HOST_BYTE_ORDER); + quiche::HOST_BYTE_ORDER); if (!writer.WriteStringPiece(label) || !writer.WriteUInt8(0) || !writer.WriteStringPiece(pre_shared_key) || 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 cb02dd79542..da746e3d63c 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 @@ -32,7 +32,7 @@ class QUIC_EXPORT_PRIVATE CryptoUtils { // Diversification is a utility class that's used to act like a union type. // Values can be created by calling the functions like |NoDiversification|, // below. - class Diversification { + class QUIC_EXPORT_PRIVATE Diversification { public: enum Mode { NEVER, // Key diversification will never be used. Forward secure diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/key_exchange.h b/chromium/net/third_party/quiche/src/quic/core/crypto/key_exchange.h index c695523ef32..127dc62ea14 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/key_exchange.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/key_exchange.h @@ -25,7 +25,7 @@ class QUIC_EXPORT_PRIVATE AsynchronousKeyExchange { // Callback base class for receiving the results of an async call to // CalculateSharedKeys. - class Callback { + class QUIC_EXPORT_PRIVATE Callback { public: Callback() = default; virtual ~Callback() = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/null_decrypter.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/null_decrypter.cc index af0a8868cb5..51d8b11695b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/null_decrypter.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/null_decrypter.cc @@ -10,6 +10,7 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -50,7 +51,7 @@ bool NullDecrypter::DecryptPacket(uint64_t /*packet_number*/, size_t* output_length, size_t max_output_length) { QuicDataReader reader(ciphertext.data(), ciphertext.length(), - HOST_BYTE_ORDER); + quiche::HOST_BYTE_ORDER); QuicUint128 hash; if (!ReadHash(&reader, &hash)) { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter.cc index 4ad9b2ad382..1fe0fdfc8bf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter.cc @@ -75,7 +75,7 @@ size_t NullEncrypter::GetIVSize() const { } size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { - return ciphertext_size - GetHashLength(); + return ciphertext_size - std::min(ciphertext_size, GetHashLength()); } size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter_test.cc index fd95cc6fb76..c6a89efbf29 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/null_encrypter_test.cc @@ -87,6 +87,7 @@ TEST_F(NullEncrypterTest, GetMaxPlaintextSize) { EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012)); EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112)); EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22)); + EXPECT_EQ(0u, encrypter.GetMaxPlaintextSize(11)); } TEST_F(NullEncrypterTest, GetCiphertextSize) { 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 fd890987d5d..f774efc3f22 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 @@ -37,13 +37,13 @@ class QUIC_EXPORT_PRIVATE ProofSource { // Details is an abstract class which acts as a container for any // implementation-specific details that a ProofSource wants to return. - class Details { + class QUIC_EXPORT_PRIVATE Details { public: virtual ~Details() {} }; // Callback base class for receiving the results of an async call to GetProof. - class Callback { + class QUIC_EXPORT_PRIVATE Callback { public: Callback() {} virtual ~Callback() {} @@ -74,7 +74,7 @@ class QUIC_EXPORT_PRIVATE ProofSource { }; // Base class for signalling the completion of a call to ComputeTlsSignature. - class SignatureCallback { + class QUIC_EXPORT_PRIVATE SignatureCallback { public: SignatureCallback() {} virtual ~SignatureCallback() = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h index 20031874c83..586ea88f676 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h @@ -52,7 +52,7 @@ class QUIC_EXPORT_PRIVATE QuicCompressedCertsCache { // A wrapper of the tuple: // |chain, client_common_set_hashes, client_cached_cert_hashes| // to identify uncompressed representation of certs. - struct UncompressedCerts { + struct QUIC_EXPORT_PRIVATE UncompressedCerts { UncompressedCerts(); UncompressedCerts( const QuicReferenceCountedPointer& chain, @@ -68,7 +68,7 @@ class QUIC_EXPORT_PRIVATE QuicCompressedCertsCache { // Certs stored by QuicCompressedCertsCache where uncompressed certs data is // used to identify the uncompressed representation of certs and // |compressed_cert| is the cached compressed representation. - class CachedCerts { + class QUIC_EXPORT_PRIVATE CachedCerts { public: CachedCerts(); CachedCerts(const UncompressedCerts& uncompressed_certs, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc index 75b2e6a2884..d674126b6df 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc @@ -28,7 +28,6 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_client_stats.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #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" @@ -61,7 +60,13 @@ void RecordDiskCacheServerConfigState( QuicCryptoClientConfig::QuicCryptoClientConfig( std::unique_ptr proof_verifier) + : QuicCryptoClientConfig(std::move(proof_verifier), nullptr) {} + +QuicCryptoClientConfig::QuicCryptoClientConfig( + std::unique_ptr proof_verifier, + std::unique_ptr session_cache) : proof_verifier_(std::move(proof_verifier)), + session_cache_(std::move(session_cache)), ssl_ctx_(TlsClientConnection::CreateSslCtx()) { DCHECK(proof_verifier_.get()); SetDefaults(); @@ -120,7 +125,7 @@ QuicCryptoClientConfig::CachedState::GetServerConfig() const { return nullptr; } - if (!scfg_.get()) { + if (!scfg_) { scfg_ = CryptoFramer::ParseMessage(server_config_); DCHECK(scfg_.get()); } @@ -850,6 +855,10 @@ ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { return proof_verifier_.get(); } +SessionCache* QuicCryptoClientConfig::session_cache() const { + return session_cache_.get(); +} + SSL_CTX* QuicCryptoClientConfig::ssl_ctx() const { return ssl_ctx_.get(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h index 838b2eef010..a3e1bcd18b2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h @@ -12,8 +12,10 @@ #include #include "third_party/boringssl/src/include/openssl/base.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_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -27,6 +29,53 @@ class ProofVerifier; class ProofVerifyDetails; class QuicRandom; +// QuicResumptionState stores the state a client needs for performing connection +// resumption. +struct QUIC_EXPORT_PRIVATE QuicResumptionState { + // |tls_session| holds the cryptographic state necessary for a resumption. It + // includes the ALPN negotiated on the connection where the ticket was + // received. + bssl::UniquePtr tls_session; + + // If the application using QUIC doesn't support 0-RTT handshakes or the + // client didn't receive a 0-RTT capable session ticket from the server, + // |transport_params| will be null. Otherwise, it will contain the transport + // parameters received from the server on the original connection. + std::unique_ptr transport_params; + + // If |transport_params| is null, then |application_state| is ignored and + // should be empty. |application_state| contains serialized state that the + // client received from the server at the application layer that the client + // needs to remember when performing a 0-RTT handshake. + std::vector application_state; +}; + +// SessionCache is an interface for managing storing and retrieving +// QuicResumptionState structs. +class QUIC_EXPORT_PRIVATE SessionCache { + public: + virtual ~SessionCache() {} + + // Inserts |state| into the cache, keyed by |server_id|. Insert is called + // after a session ticket is received. If the session ticket is valid for + // 0-RTT, there may be a delay between its receipt and the call to Insert + // while waiting for application state for |state|. + // + // Insert may be called multiple times per connection. SessionCache + // implementations should support storing multiple entries per server ID. + virtual void Insert(const QuicServerId& server_id, + std::unique_ptr state) = 0; + + // Lookup is called once at the beginning of each TLS handshake to potentially + // provide the saved state both for the TLS handshake and for sending 0-RTT + // data (if supported). Lookup may return a nullptr. Implementations should + // delete cache entries after returning them in Lookup so that session tickets + // are used only once. + virtual std::unique_ptr Lookup( + const QuicServerId& server_id, + const SSL_CTX* ctx) = 0; +}; + // QuicCryptoClientConfig contains crypto-related configuration settings for a // client. Note that this object isn't thread-safe. It's designed to be used on // a single thread at a time. @@ -195,7 +244,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { }; // Used to filter server ids for partial config deletion. - class ServerIdFilter { + class QUIC_EXPORT_PRIVATE ServerIdFilter { public: virtual ~ServerIdFilter() {} @@ -203,8 +252,11 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { virtual bool Matches(const QuicServerId& server_id) const = 0; }; + // DEPRECATED: Use the constructor below instead. explicit QuicCryptoClientConfig( std::unique_ptr proof_verifier); + QuicCryptoClientConfig(std::unique_ptr proof_verifier, + std::unique_ptr session_cache); QuicCryptoClientConfig(const QuicCryptoClientConfig&) = delete; QuicCryptoClientConfig& operator=(const QuicCryptoClientConfig&) = delete; ~QuicCryptoClientConfig(); @@ -309,7 +361,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { std::string* error_details); ProofVerifier* proof_verifier() const; - + SessionCache* session_cache() const; SSL_CTX* ssl_ctx() const; // Initialize the CachedState from |canonical_crypto_config| for the @@ -388,6 +440,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { std::vector canonical_suffixes_; std::unique_ptr proof_verifier_; + std::unique_ptr session_cache_; bssl::UniquePtr ssl_ctx_; // The |user_agent_id_| passed in QUIC's CHLO message. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc index 683180bf030..8b5f116d107 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc @@ -10,7 +10,6 @@ #include "net/third_party/quiche/src/quic/core/quic_server_id.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_endian.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/mock_random.h" @@ -115,11 +114,9 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_ServerDesignatedConnectionId) { TEST_F(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) { QuicCryptoClientConfig::CachedState state; EXPECT_FALSE(state.has_server_designated_connection_id()); -#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - EXPECT_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(), - "Attempting to consume a connection id " - "that was never designated."); -#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) + EXPECT_QUIC_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(), + "Attempting to consume a connection id " + "that was never designated."); } TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) { @@ -156,11 +153,9 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) { TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) { QuicCryptoClientConfig::CachedState state; EXPECT_FALSE(state.has_server_nonce()); -#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - EXPECT_DEBUG_DEATH(state.GetNextServerNonce(), - "Attempting to consume a server nonce " - "that was never designated."); -#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) + EXPECT_QUIC_DEBUG_DEATH(state.GetNextServerNonce(), + "Attempting to consume a server nonce " + "that was never designated."); } TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) { 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 c211cdb3345..d5689862fcf 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 @@ -38,7 +38,6 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.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" @@ -385,14 +384,14 @@ std::unique_ptr QuicCryptoServerConfig::AddConfig( std::unique_ptr msg = CryptoFramer::ParseMessage(protobuf.config()); - if (!msg.get()) { + if (!msg) { QUIC_LOG(WARNING) << "Failed to parse server config message"; return nullptr; } QuicReferenceCountedPointer config = ParseConfigProtobuf(protobuf, /* is_fallback = */ false); - if (!config.get()) { + if (!config) { QUIC_LOG(WARNING) << "Failed to parse server config message"; return nullptr; } @@ -896,7 +895,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys( } std::unique_ptr cetv(CryptoFramer::ParseMessage( QuicStringPiece(plaintext, plaintext_length))); - if (!cetv.get()) { + if (!cetv) { context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error"); return; } @@ -1281,7 +1280,6 @@ void QuicCryptoServerConfig::EvaluateClientHello( // Server nonce is optional, and used for key derivation if present. client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce); - QUIC_DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher."; // If the server nonce is empty and we're requiring handshake confirmation // for DoS reasons then we must reject the CHLO. if (GetQuicReloadableFlag(quic_require_handshake_confirmation) && diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h index 3fb424d4022..809ebaec575 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h @@ -41,7 +41,7 @@ struct QuicSignedServerConfig; // ClientHelloInfo contains information about a client hello message that is // only kept for as long as it's being processed. -struct ClientHelloInfo { +struct QUIC_EXPORT_PRIVATE ClientHelloInfo { ClientHelloInfo(const QuicIpAddress& in_client_ip, QuicWallTime in_now); ClientHelloInfo(const ClientHelloInfo& other); ~ClientHelloInfo(); @@ -68,7 +68,7 @@ class QuicCryptoServerConfigPeer; } // namespace test // Hook that allows application code to subscribe to primary config changes. -class PrimaryConfigChangedCallback { +class QUIC_EXPORT_PRIVATE PrimaryConfigChangedCallback { public: PrimaryConfigChangedCallback(); PrimaryConfigChangedCallback(const PrimaryConfigChangedCallback&) = delete; @@ -128,7 +128,7 @@ class QUIC_EXPORT_PRIVATE ProcessClientHelloResultCallback { // Callback used to receive the results of a call to // BuildServerConfigUpdateMessage. -class BuildServerConfigUpdateMessageResultCallback { +class QUIC_EXPORT_PRIVATE BuildServerConfigUpdateMessageResultCallback { public: BuildServerConfigUpdateMessageResultCallback() = default; virtual ~BuildServerConfigUpdateMessageResultCallback() {} @@ -141,7 +141,7 @@ class BuildServerConfigUpdateMessageResultCallback { // Object that is interested in built rejections (which include REJ, SREJ and // cheap SREJ). -class RejectionObserver { +class QUIC_EXPORT_PRIVATE RejectionObserver { public: RejectionObserver() = default; virtual ~RejectionObserver() {} @@ -511,7 +511,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { QUIC_SHARED_LOCKS_REQUIRED(configs_lock_); // A snapshot of the configs associated with an in-progress handshake. - struct Configs { + struct QUIC_EXPORT_PRIVATE Configs { QuicReferenceCountedPointer requested; QuicReferenceCountedPointer primary; QuicReferenceCountedPointer fallback; @@ -552,7 +552,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { // Convenience class which carries the arguments passed to // |ProcessClientHellp| along. - class ProcessClientHelloContext { + class QUIC_EXPORT_PRIVATE ProcessClientHelloContext { public: ProcessClientHelloContext( QuicReferenceCountedPointer diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc index bc9b2efe200..8f9e4ba776a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc @@ -18,6 +18,7 @@ #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" @@ -351,7 +352,7 @@ class CryptoServerConfigsTest : public QuicTest { QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options); protobuf.set_primary_time(primary_time); protobuf.set_priority(priority); - if (std::string(server_config_id).find("INVALID") == 0) { + if (QuicTextUtils::StartsWith(std::string(server_config_id), "INVALID")) { protobuf.clear_key(); has_invalid = true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h index 09006eef4db..94d45bc91a6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h @@ -15,7 +15,7 @@ namespace quic { // QuicHKDF implements the key derivation function specified in RFC 5869 // (using SHA-256) and outputs key material, as needed by QUIC. // See https://tools.ietf.org/html/rfc5869 for details. -class QUIC_EXPORT QuicHKDF { +class QUIC_EXPORT_PRIVATE QuicHKDF { public: // |secret|: the input shared secret (or, from RFC 5869, the IKM). // |salt|: an (optional) public salt / non-secret random value. While diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc index f28af660e90..7d112245b3c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc @@ -14,11 +14,14 @@ TlsClientConnection::TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate) bssl::UniquePtr TlsClientConnection::CreateSslCtx() { bssl::UniquePtr ssl_ctx = TlsConnection::CreateSslCtx(); // Configure certificate verification. - // TODO(nharper): This only verifies certs on initial connection, not on - // resumption. Chromium has this callback be a no-op and verifies the - // certificate after the connection is complete. We need to re-verify on - // resumption in case of expiration or revocation/distrust. SSL_CTX_set_custom_verify(ssl_ctx.get(), SSL_VERIFY_PEER, &VerifyCallback); + int reverify_on_resume_enabled = 1; + SSL_CTX_set_reverify_on_resume(ssl_ctx.get(), reverify_on_resume_enabled); + + // Configure session caching. + SSL_CTX_set_session_cache_mode( + ssl_ctx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback); return ssl_ctx; } @@ -30,4 +33,11 @@ enum ssl_verify_result_t TlsClientConnection::VerifyCallback( ->delegate_->VerifyCert(out_alert); } +// static +int TlsClientConnection::NewSessionCallback(SSL* ssl, SSL_SESSION* session) { + static_cast(ConnectionFromSsl(ssl)) + ->delegate_->InsertSession(bssl::UniquePtr(session)); + return 1; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h index a9212ff2a72..035f420a835 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h @@ -15,7 +15,7 @@ class QUIC_EXPORT_PRIVATE TlsClientConnection : public TlsConnection { public: // A TlsClientConnection::Delegate implements the client-specific methods that // are set as callbacks for an SSL object. - class Delegate { + class QUIC_EXPORT_PRIVATE Delegate { public: virtual ~Delegate() {} @@ -26,6 +26,9 @@ class QUIC_EXPORT_PRIVATE TlsClientConnection : public TlsConnection { // or ssl_verify_retry if verification is happening asynchronously. virtual enum ssl_verify_result_t VerifyCert(uint8_t* out_alert) = 0; + // Called when a NewSessionTicket is received from the server. + virtual void InsertSession(bssl::UniquePtr session) = 0; + // Provides the delegate for callbacks that are shared between client and // server. virtual TlsConnection::Delegate* ConnectionDelegate() = 0; @@ -43,6 +46,10 @@ class QUIC_EXPORT_PRIVATE TlsClientConnection : public TlsConnection { // implementation is delegated to Delegate::VerifyCert. static enum ssl_verify_result_t VerifyCallback(SSL* ssl, uint8_t* out_alert); + // Registered as the callback for SSL_CTX_sess_set_new_cb, which calls + // Delegate::InsertSession. + static int NewSessionCallback(SSL* ssl, SSL_SESSION* session); + Delegate* delegate_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h index 4774ba6924d..fd4f64b1978 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h @@ -26,7 +26,7 @@ class QUIC_EXPORT_PRIVATE TlsConnection { public: // A TlsConnection::Delegate implements the methods that are set as callbacks // of TlsConnection. - class Delegate { + class QUIC_EXPORT_PRIVATE Delegate { public: virtual ~Delegate() {} 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 927c75af318..f539a089d2c 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 @@ -16,6 +16,7 @@ bssl::UniquePtr TlsServerConnection::CreateSslCtx() { SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), &SelectCertificateCallback); SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr); + 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/crypto/tls_server_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h index 0e78d1bf015..96d71e2bef1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h @@ -15,7 +15,7 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection { public: // A TlsServerConnection::Delegate implement the server-specific methods that // are set as callbacks for an SSL object. - class Delegate { + class QUIC_EXPORT_PRIVATE Delegate { public: virtual ~Delegate() {} diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc index ce6cc2005c3..a870017b0b3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc @@ -44,6 +44,8 @@ enum TransportParameters::TransportParameterId : uint16_t { kPreferredAddress = 0xd, kActiveConnectionIdLimit = 0xe, + kMaxDatagramFrameSize = 0x20, + kGoogleQuicParam = 18257, // Used for non-standard Google-specific params. kGoogleQuicVersion = 18258, // Used to transmit version and supported_versions. @@ -95,6 +97,8 @@ std::string TransportParameterIdToString( return "preferred_address"; case TransportParameters::kActiveConnectionIdLimit: return "active_connection_id_limit"; + case TransportParameters::kMaxDatagramFrameSize: + return "max_datagram_frame_size"; case TransportParameters::kGoogleQuicParam: return "google"; case TransportParameters::kGoogleQuicVersion: @@ -279,6 +283,7 @@ std::string TransportParameters::ToString() const { preferred_address->ToString(); } rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true); + rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true); if (google_quic_params) { rv += " " + TransportParameterIdToString(kGoogleQuicParam); } @@ -313,7 +318,8 @@ TransportParameters::TransportParameters() 0, kMaxMaxAckDelayTransportParam), disable_migration(false), - active_connection_id_limit(kActiveConnectionIdLimit) + active_connection_id_limit(kActiveConnectionIdLimit), + max_datagram_frame_size(kMaxDatagramFrameSize) // Important note: any new transport parameters must be added // to TransportParameters::AreValid, SerializeTransportParameters and // ParseTransportParameters. @@ -354,15 +360,15 @@ bool TransportParameters::AreValid() const { QUIC_BUG << "Preferred address family failure"; return false; } - const bool ok = idle_timeout_milliseconds.IsValid() && - max_packet_size.IsValid() && initial_max_data.IsValid() && - initial_max_stream_data_bidi_local.IsValid() && - initial_max_stream_data_bidi_remote.IsValid() && - initial_max_stream_data_uni.IsValid() && - initial_max_streams_bidi.IsValid() && - initial_max_streams_uni.IsValid() && - ack_delay_exponent.IsValid() && max_ack_delay.IsValid() && - active_connection_id_limit.IsValid(); + const bool ok = + idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() && + initial_max_data.IsValid() && + initial_max_stream_data_bidi_local.IsValid() && + initial_max_stream_data_bidi_remote.IsValid() && + initial_max_stream_data_uni.IsValid() && + initial_max_streams_bidi.IsValid() && initial_max_streams_uni.IsValid() && + ack_delay_exponent.IsValid() && max_ack_delay.IsValid() && + active_connection_id_limit.IsValid() && max_datagram_frame_size.IsValid(); if (!ok) { QUIC_DLOG(ERROR) << "Invalid transport parameters " << *this; } @@ -445,7 +451,8 @@ bool SerializeTransportParameters(ParsedQuicVersion /*version*/, !in.initial_max_streams_uni.WriteToCbb(¶ms) || !in.ack_delay_exponent.WriteToCbb(¶ms) || !in.max_ack_delay.WriteToCbb(¶ms) || - !in.active_connection_id_limit.WriteToCbb(¶ms)) { + !in.active_connection_id_limit.WriteToCbb(¶ms) || + !in.max_datagram_frame_size.WriteToCbb(¶ms)) { QUIC_BUG << "Failed to write integers for " << in; return false; } @@ -734,6 +741,9 @@ bool ParseTransportParameters(ParsedQuicVersion version, case TransportParameters::kActiveConnectionIdLimit: parse_success = out->active_connection_id_limit.ReadFromCbs(&value); break; + case TransportParameters::kMaxDatagramFrameSize: + parse_success = out->max_datagram_frame_size.ReadFromCbs(&value); + break; case TransportParameters::kGoogleQuicParam: { if (out->google_quic_params) { QUIC_DLOG(ERROR) << "Received a second Google parameter"; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h index 22dc252405c..c5ec1a4f71b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h @@ -168,6 +168,10 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // to store. IntegerParameter active_connection_id_limit; + // Indicates support for the DATAGRAM frame and the maximum frame size that + // the sender accepts. See draft-pauly-quic-datagram. + IntegerParameter max_datagram_frame_size; + // Transport parameters used by Google QUIC but not IETF QUIC. This is // serialized into a TransportParameter struct with a TransportParameterId of // kGoogleQuicParamId. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc index 90afe221bd7..61a6e0d4d6b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc @@ -24,14 +24,10 @@ using testing::UnorderedElementsAre; const ParsedQuicVersion kVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); const QuicVersionLabel kFakeVersionLabel = 0x01234567; const QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF; -const QuicConnectionId kFakeOriginalConnectionId = TestConnectionId(0x1337); const uint64_t kFakeIdleTimeoutMilliseconds = 12012; const uint8_t kFakeStatelessResetTokenData[16] = { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}; -const std::vector kFakeStatelessResetToken( - kFakeStatelessResetTokenData, - kFakeStatelessResetTokenData + sizeof(kFakeStatelessResetTokenData)); const uint64_t kFakeMaxPacketSize = 9001; const uint64_t kFakeInitialMaxData = 101; const uint64_t kFakeInitialMaxStreamDataBidiLocal = 2001; @@ -43,14 +39,10 @@ const uint64_t kFakeAckDelayExponent = 10; const uint64_t kFakeMaxAckDelay = 51; const bool kFakeDisableMigration = true; const uint64_t kFakeActiveConnectionIdLimit = 52; -const QuicConnectionId kFakePreferredConnectionId = TestConnectionId(0xBEEF); const uint8_t kFakePreferredStatelessResetTokenData[16] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F}; -const std::vector kFakePreferredStatelessResetToken( - kFakePreferredStatelessResetTokenData, - kFakePreferredStatelessResetTokenData + - sizeof(kFakeStatelessResetTokenData)); + const auto kCustomParameter1 = static_cast(0xffcd); const char* kCustomParameter1Value = "foo"; @@ -58,6 +50,27 @@ const auto kCustomParameter2 = static_cast(0xff34); const char* kCustomParameter2Value = "bar"; +QuicConnectionId CreateFakeOriginalConnectionId() { + return TestConnectionId(0x1337); +} + +QuicConnectionId CreateFakePreferredConnectionId() { + return TestConnectionId(0xBEEF); +} + +std::vector CreateFakeStatelessResetToken() { + return std::vector( + kFakeStatelessResetTokenData, + kFakeStatelessResetTokenData + sizeof(kFakeStatelessResetTokenData)); +} + +std::vector CreateFakePreferredStatelessResetToken() { + return std::vector( + kFakePreferredStatelessResetTokenData, + kFakePreferredStatelessResetTokenData + + sizeof(kFakePreferredStatelessResetTokenData)); +} + QuicSocketAddress CreateFakeV4SocketAddress() { QuicIpAddress ipv4_address; if (!ipv4_address.FromString("65.66.67.68")) { // 0x41, 0x42, 0x43, 0x44 @@ -81,8 +94,9 @@ CreateFakePreferredAddress() { TransportParameters::PreferredAddress preferred_address; preferred_address.ipv4_socket_address = CreateFakeV4SocketAddress(); preferred_address.ipv6_socket_address = CreateFakeV6SocketAddress(); - preferred_address.connection_id = kFakePreferredConnectionId; - preferred_address.stateless_reset_token = kFakePreferredStatelessResetToken; + preferred_address.connection_id = CreateFakePreferredConnectionId(); + preferred_address.stateless_reset_token = + CreateFakePreferredStatelessResetToken(); return std::make_unique( preferred_address); } @@ -158,9 +172,9 @@ TEST_F(TransportParametersTest, RoundTripServer) { orig_params.version = kFakeVersionLabel; orig_params.supported_versions.push_back(kFakeVersionLabel); orig_params.supported_versions.push_back(kFakeVersionLabel2); - orig_params.original_connection_id = kFakeOriginalConnectionId; + orig_params.original_connection_id = CreateFakeOriginalConnectionId(); orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); - orig_params.stateless_reset_token = kFakeStatelessResetToken; + orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); orig_params.max_packet_size.set_value(kFakeMaxPacketSize); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( @@ -191,10 +205,11 @@ TEST_F(TransportParametersTest, RoundTripServer) { EXPECT_EQ(2u, new_params.supported_versions.size()); EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); - EXPECT_EQ(kFakeOriginalConnectionId, new_params.original_connection_id); + EXPECT_EQ(CreateFakeOriginalConnectionId(), + new_params.original_connection_id); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, new_params.idle_timeout_milliseconds.value()); - EXPECT_EQ(kFakeStatelessResetToken, new_params.stateless_reset_token); + EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token); EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, @@ -215,9 +230,9 @@ TEST_F(TransportParametersTest, RoundTripServer) { new_params.preferred_address->ipv4_socket_address); EXPECT_EQ(CreateFakeV6SocketAddress(), new_params.preferred_address->ipv6_socket_address); - EXPECT_EQ(kFakePreferredConnectionId, + EXPECT_EQ(CreateFakePreferredConnectionId(), new_params.preferred_address->connection_id); - EXPECT_EQ(kFakePreferredStatelessResetToken, + EXPECT_EQ(CreateFakePreferredStatelessResetToken(), new_params.preferred_address->stateless_reset_token); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); @@ -272,7 +287,7 @@ TEST_F(TransportParametersTest, NoClientParamsWithStatelessResetToken) { orig_params.perspective = Perspective::IS_CLIENT; orig_params.version = kFakeVersionLabel; orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); - orig_params.stateless_reset_token = kFakeStatelessResetToken; + orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); orig_params.max_packet_size.set_value(kFakeMaxPacketSize); std::vector out; @@ -543,10 +558,11 @@ TEST_F(TransportParametersTest, ParseServerParams) { EXPECT_EQ(2u, new_params.supported_versions.size()); EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); - EXPECT_EQ(kFakeOriginalConnectionId, new_params.original_connection_id); + EXPECT_EQ(CreateFakeOriginalConnectionId(), + new_params.original_connection_id); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, new_params.idle_timeout_milliseconds.value()); - EXPECT_EQ(kFakeStatelessResetToken, new_params.stateless_reset_token); + EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token); EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, @@ -567,9 +583,9 @@ TEST_F(TransportParametersTest, ParseServerParams) { new_params.preferred_address->ipv4_socket_address); EXPECT_EQ(CreateFakeV6SocketAddress(), new_params.preferred_address->ipv6_socket_address); - EXPECT_EQ(kFakePreferredConnectionId, + EXPECT_EQ(CreateFakePreferredConnectionId(), new_params.preferred_address->connection_id); - EXPECT_EQ(kFakePreferredStatelessResetToken, + EXPECT_EQ(CreateFakePreferredStatelessResetToken(), new_params.preferred_address->stateless_reset_token); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc index 389f1c04a0a..2946c01af8b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc @@ -15,13 +15,6 @@ namespace { const QuicPacketCount kMaxPrintRange = 128; -uint64_t PacketNumberIntervalLength( - const QuicInterval& interval) { - if (interval.Empty()) { - return 0u; - } - return interval.max() - interval.min(); -} } // namespace bool IsAwaitingPacket(const QuicAckFrame& ack_frame, @@ -86,77 +79,8 @@ void PacketNumberQueue::Add(QuicPacketNumber packet_number) { if (!packet_number.IsInitialized()) { return; } - // Check if the deque is empty - if (packet_number_deque_.empty()) { - packet_number_deque_.push_front( - QuicInterval(packet_number, packet_number + 1)); - return; - } - QuicInterval back = packet_number_deque_.back(); - - // Check for the typical case, - // when the next packet in order is acked - if (back.max() == packet_number) { - packet_number_deque_.back().SetMax(packet_number + 1); - return; - } - // Check if the next packet in order is skipped - if (back.max() < packet_number) { - packet_number_deque_.push_back( - QuicInterval(packet_number, packet_number + 1)); - return; - } - - QuicInterval front = packet_number_deque_.front(); - // Check if the packet can be popped on the front - if (front.min() > packet_number + 1) { - packet_number_deque_.push_front( - QuicInterval(packet_number, packet_number + 1)); - return; - } - if (front.min() == packet_number + 1) { - packet_number_deque_.front().SetMin(packet_number); - return; - } - - int i = packet_number_deque_.size() - 1; - // Iterating through the queue backwards - // to find a proper place for the packet - while (i >= 0) { - QuicInterval packet_interval = packet_number_deque_[i]; - DCHECK(packet_interval.min() < packet_interval.max()); - // Check if the packet is contained in an interval already - if (packet_interval.Contains(packet_number)) { - return; - } - - // Check if the packet can extend an interval. - if (packet_interval.max() == packet_number) { - packet_number_deque_[i].SetMax(packet_number + 1); - return; - } - // Check if the packet can extend an interval - // and merge two intervals if needed. - // There is no need to merge an interval in the previous - // if statement, as all merges will happen here. - if (packet_interval.min() == packet_number + 1) { - packet_number_deque_[i].SetMin(packet_number); - if (i > 0 && packet_number == packet_number_deque_[i - 1].max()) { - packet_number_deque_[i - 1].SetMax(packet_interval.max()); - packet_number_deque_.erase(packet_number_deque_.begin() + i); - } - return; - } - - // Check if we need to make a new interval for the packet - if (packet_interval.max() < packet_number + 1) { - packet_number_deque_.insert( - packet_number_deque_.begin() + i + 1, - QuicInterval(packet_number, packet_number + 1)); - return; - } - i--; - } + packet_number_intervals_.AddOptimizedForAppend(packet_number, + packet_number + 1); } void PacketNumberQueue::AddRange(QuicPacketNumber lower, @@ -164,136 +88,81 @@ void PacketNumberQueue::AddRange(QuicPacketNumber lower, if (!lower.IsInitialized() || !higher.IsInitialized() || lower >= higher) { return; } - if (packet_number_deque_.empty()) { - packet_number_deque_.push_front( - QuicInterval(lower, higher)); - return; - } - QuicInterval back = packet_number_deque_.back(); - if (back.max() == lower) { - // Check for the typical case, - // when the next packet in order is acked - packet_number_deque_.back().SetMax(higher); - return; - } - if (back.max() < lower) { - // Check if the next packet in order is skipped - packet_number_deque_.push_back( - QuicInterval(lower, higher)); - return; - } - QuicInterval front = packet_number_deque_.front(); - // Check if the packets are being added in reverse order - if (front.min() == higher) { - packet_number_deque_.front().SetMin(lower); - } else if (front.min() > higher) { - packet_number_deque_.push_front( - QuicInterval(lower, higher)); - - } else { - // Ranges must be above or below all existing ranges. - QUIC_BUG << "AddRange only supports adding packets above or below the " - << "current min:" << Min() << " and max:" << Max() - << ", but adding [" << lower << "," << higher << ")"; - } + packet_number_intervals_.AddOptimizedForAppend(lower, higher); } bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) { if (!higher.IsInitialized() || Empty()) { return false; } - const QuicPacketNumber old_min = Min(); - while (!packet_number_deque_.empty()) { - QuicInterval front = packet_number_deque_.front(); - if (front.max() < higher) { - packet_number_deque_.pop_front(); - } else if (front.min() < higher && front.max() >= higher) { - packet_number_deque_.front().SetMin(higher); - if (front.max() == higher) { - packet_number_deque_.pop_front(); - } - break; - } else { - break; - } - } - - return Empty() || old_min != Min(); + return packet_number_intervals_.TrimLessThan(higher); } void PacketNumberQueue::RemoveSmallestInterval() { - QUIC_BUG_IF(packet_number_deque_.size() < 2) + // TODO(wub): Move this QUIC_BUG to upper level. + QUIC_BUG_IF(packet_number_intervals_.Size() < 2) << (Empty() ? "No intervals to remove." : "Can't remove the last interval."); - packet_number_deque_.pop_front(); + packet_number_intervals_.PopFront(); } void PacketNumberQueue::Clear() { - packet_number_deque_.clear(); + packet_number_intervals_.Clear(); } bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const { - if (!packet_number.IsInitialized() || packet_number_deque_.empty()) { - return false; - } - if (packet_number_deque_.front().min() > packet_number || - packet_number_deque_.back().max() <= packet_number) { + if (!packet_number.IsInitialized()) { return false; } - for (QuicInterval interval : packet_number_deque_) { - if (interval.Contains(packet_number)) { - return true; - } - } - return false; + return packet_number_intervals_.Contains(packet_number); } bool PacketNumberQueue::Empty() const { - return packet_number_deque_.empty(); + return packet_number_intervals_.Empty(); } QuicPacketNumber PacketNumberQueue::Min() const { DCHECK(!Empty()); - return packet_number_deque_.front().min(); + return packet_number_intervals_.begin()->min(); } QuicPacketNumber PacketNumberQueue::Max() const { DCHECK(!Empty()); - return packet_number_deque_.back().max() - 1; + return packet_number_intervals_.rbegin()->max() - 1; } QuicPacketCount PacketNumberQueue::NumPacketsSlow() const { QuicPacketCount n_packets = 0; - for (QuicInterval interval : packet_number_deque_) { - n_packets += PacketNumberIntervalLength(interval); + for (const auto& interval : packet_number_intervals_) { + n_packets += interval.Length(); } return n_packets; } size_t PacketNumberQueue::NumIntervals() const { - return packet_number_deque_.size(); + return packet_number_intervals_.Size(); } PacketNumberQueue::const_iterator PacketNumberQueue::begin() const { - return packet_number_deque_.begin(); + return packet_number_intervals_.begin(); } PacketNumberQueue::const_iterator PacketNumberQueue::end() const { - return packet_number_deque_.end(); + return packet_number_intervals_.end(); } PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const { - return packet_number_deque_.rbegin(); + return packet_number_intervals_.rbegin(); } PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const { - return packet_number_deque_.rend(); + return packet_number_intervals_.rend(); } QuicPacketCount PacketNumberQueue::LastIntervalLength() const { DCHECK(!Empty()); - return PacketNumberIntervalLength(packet_number_deque_.back()); + return packet_number_intervals_.rbegin()->Length(); } // Largest min...max range for packet numbers where we print the numbers diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h index 771d93e3285..9003c76e3d3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h @@ -8,6 +8,7 @@ #include #include "net/third_party/quiche/src/quic/core/quic_interval.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" #include "net/third_party/quiche/src/quic/core/quic_types.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" @@ -28,16 +29,16 @@ class QUIC_EXPORT_PRIVATE PacketNumberQueue { PacketNumberQueue& operator=(const PacketNumberQueue& other); PacketNumberQueue& operator=(PacketNumberQueue&& other); - typedef QuicDeque>::const_iterator - const_iterator; - typedef QuicDeque>::const_reverse_iterator + typedef QuicIntervalSet::const_iterator const_iterator; + typedef QuicIntervalSet::const_reverse_iterator const_reverse_iterator; // Adds |packet_number| to the set of packets in the queue. void Add(QuicPacketNumber packet_number); - // Adds packets between [lower, higher) to the set of packets in the queue. It - // is undefined behavior to call this with |higher| < |lower|. + // Adds packets between [lower, higher) to the set of packets in the queue. + // No-op if |higher| < |lower|. + // NOTE(wub): Only used in tests as of Nov 2019. void AddRange(QuicPacketNumber lower, QuicPacketNumber higher); // Removes packets with values less than |higher| from the set of packets in @@ -86,7 +87,7 @@ class QUIC_EXPORT_PRIVATE PacketNumberQueue { const PacketNumberQueue& q); private: - QuicDeque> packet_number_deque_; + QuicIntervalSet packet_number_intervals_; }; struct QUIC_EXPORT_PRIVATE QuicAckFrame { 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 5e85fc0b4e3..e640179c460 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 @@ -254,6 +254,101 @@ QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) { return copy; } +QuicFrame CopyQuicFrame(QuicBufferAllocator* allocator, + const QuicFrame& frame) { + QuicFrame copy; + switch (frame.type) { + case PADDING_FRAME: + copy = QuicFrame(QuicPaddingFrame(frame.padding_frame)); + break; + case RST_STREAM_FRAME: + copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame)); + break; + case CONNECTION_CLOSE_FRAME: + copy = QuicFrame( + new QuicConnectionCloseFrame(*frame.connection_close_frame)); + break; + case GOAWAY_FRAME: + copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame)); + break; + case WINDOW_UPDATE_FRAME: + copy = QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame)); + break; + case BLOCKED_FRAME: + copy = QuicFrame(new QuicBlockedFrame(*frame.blocked_frame)); + break; + case STOP_WAITING_FRAME: + copy = QuicFrame(QuicStopWaitingFrame(frame.stop_waiting_frame)); + break; + case PING_FRAME: + copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id)); + break; + case CRYPTO_FRAME: + copy = QuicFrame(new QuicCryptoFrame(*frame.crypto_frame)); + break; + case STREAM_FRAME: + copy = QuicFrame(QuicStreamFrame(frame.stream_frame)); + break; + case ACK_FRAME: + copy = QuicFrame(new QuicAckFrame(*frame.ack_frame)); + break; + case MTU_DISCOVERY_FRAME: + copy = QuicFrame(QuicMtuDiscoveryFrame(frame.mtu_discovery_frame)); + break; + case NEW_CONNECTION_ID_FRAME: + copy = QuicFrame( + new QuicNewConnectionIdFrame(*frame.new_connection_id_frame)); + break; + case MAX_STREAMS_FRAME: + copy = QuicFrame(QuicMaxStreamsFrame(frame.max_streams_frame)); + break; + case STREAMS_BLOCKED_FRAME: + copy = QuicFrame(QuicStreamsBlockedFrame(frame.streams_blocked_frame)); + break; + case PATH_RESPONSE_FRAME: + copy = QuicFrame(new QuicPathResponseFrame(*frame.path_response_frame)); + break; + case PATH_CHALLENGE_FRAME: + copy = QuicFrame(new QuicPathChallengeFrame(*frame.path_challenge_frame)); + break; + case STOP_SENDING_FRAME: + copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame)); + break; + case MESSAGE_FRAME: + copy = QuicFrame(new QuicMessageFrame(frame.message_frame->message_id)); + copy.message_frame->data = frame.message_frame->data; + copy.message_frame->message_length = frame.message_frame->message_length; + for (const auto& slice : frame.message_frame->message_data) { + QuicMemSlice copy_slice(allocator, slice.length()); + memcpy(const_cast(copy_slice.data()), slice.data(), + slice.length()); + copy.message_frame->message_data.push_back(std::move(copy_slice)); + } + break; + case NEW_TOKEN_FRAME: + copy = QuicFrame(new QuicNewTokenFrame(*frame.new_token_frame)); + break; + case RETIRE_CONNECTION_ID_FRAME: + copy = QuicFrame( + new QuicRetireConnectionIdFrame(*frame.retire_connection_id_frame)); + break; + default: + QUIC_BUG << "Cannot copy frame: " << frame; + copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId)); + break; + } + return copy; +} + +QuicFrames CopyQuicFrames(QuicBufferAllocator* allocator, + const QuicFrames& frames) { + QuicFrames copy; + for (const auto& frame : frames) { + copy.push_back(CopyQuicFrame(allocator, frame)); + } + return copy; +} + std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) { switch (frame.type) { 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 1fa9e01af56..226cbfb2d83 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 @@ -140,6 +140,14 @@ QUIC_EXPORT_PRIVATE void SetControlFrameId(QuicControlFrameId control_frame_id, QUIC_EXPORT_PRIVATE QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame); +// Returns a copy of |frame|. +QUIC_EXPORT_PRIVATE QuicFrame CopyQuicFrame(QuicBufferAllocator* allocator, + const QuicFrame& frame); + +// Returns a copy of |frames|. +QUIC_EXPORT_PRIVATE QuicFrames CopyQuicFrames(QuicBufferAllocator* allocator, + const QuicFrames& frames); + // Human-readable description suitable for logging. QUIC_EXPORT_PRIVATE std::string QuicFramesToString(const QuicFrames& frames); 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 8492a0c5112..1764e170f03 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 @@ -204,9 +204,9 @@ TEST_F(QuicFramesTest, WindowUpdateFrameToString) { EXPECT_EQ(3u, GetControlFrameId(frame)); std::ostringstream stream; window_update.stream_id = 1; - window_update.byte_offset = 2; + window_update.max_data = 2; stream << window_update; - EXPECT_EQ("{ control_frame_id: 3, stream_id: 1, byte_offset: 2 }\n", + EXPECT_EQ("{ control_frame_id: 3, stream_id: 1, max_data: 2 }\n", stream.str()); EXPECT_TRUE(IsControlFrame(frame.type)); } @@ -376,30 +376,27 @@ TEST_F(QuicFramesTest, AddInterval) { EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min()); EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max()); - std::vector> expected_intervals; - expected_intervals.emplace_back(QuicInterval( - QuicPacketNumber(1), QuicPacketNumber(10))); - expected_intervals.emplace_back(QuicInterval( - QuicPacketNumber(50), QuicPacketNumber(100))); + std::vector> expected_intervals{ + {QuicPacketNumber(1), QuicPacketNumber(10)}, + {QuicPacketNumber(50), QuicPacketNumber(100)}, + }; const std::vector> actual_intervals( ack_frame1.packets.begin(), ack_frame1.packets.end()); EXPECT_EQ(expected_intervals, actual_intervals); - // Ensure adding a range within the existing ranges fails. - EXPECT_QUIC_BUG( - ack_frame1.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(30)), - ""); + // Add a range in the middle. + ack_frame1.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(30)); const std::vector> actual_intervals2( ack_frame1.packets.begin(), ack_frame1.packets.end()); - std::vector> expected_intervals2; - expected_intervals2.emplace_back(QuicInterval( - QuicPacketNumber(1), QuicPacketNumber(10))); - expected_intervals2.emplace_back(QuicInterval( - QuicPacketNumber(50), QuicPacketNumber(100))); + std::vector> expected_intervals2{ + {QuicPacketNumber(1), QuicPacketNumber(10)}, + {QuicPacketNumber(20), QuicPacketNumber(30)}, + {QuicPacketNumber(50), QuicPacketNumber(100)}, + }; EXPECT_EQ(expected_intervals2.size(), ack_frame1.packets.NumIntervals()); EXPECT_EQ(expected_intervals2, actual_intervals2); @@ -415,17 +412,13 @@ TEST_F(QuicFramesTest, AddInterval) { const std::vector> actual_intervals8( ack_frame2.packets.begin(), ack_frame2.packets.end()); - std::vector> expected_intervals8; - expected_intervals8.emplace_back(QuicInterval( - QuicPacketNumber(10), QuicPacketNumber(15))); - expected_intervals8.emplace_back(QuicInterval( - QuicPacketNumber(20), QuicPacketNumber(25))); - expected_intervals8.emplace_back(QuicInterval( - QuicPacketNumber(40), QuicPacketNumber(45))); - expected_intervals8.emplace_back(QuicInterval( - QuicPacketNumber(60), QuicPacketNumber(65))); - expected_intervals8.emplace_back(QuicInterval( - QuicPacketNumber(80), QuicPacketNumber(85))); + std::vector> expected_intervals8{ + {QuicPacketNumber(10), QuicPacketNumber(15)}, + {QuicPacketNumber(20), QuicPacketNumber(25)}, + {QuicPacketNumber(40), QuicPacketNumber(45)}, + {QuicPacketNumber(60), QuicPacketNumber(65)}, + {QuicPacketNumber(80), QuicPacketNumber(85)}, + }; EXPECT_EQ(expected_intervals8, actual_intervals8); } @@ -481,6 +474,104 @@ TEST_F(QuicFramesTest, RemoveSmallestInterval) { EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max()); } +TEST_F(QuicFramesTest, CopyQuicFrames) { + QuicFrames frames; + SimpleBufferAllocator allocator; + QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); + QuicMessageFrame* message_frame = + new QuicMessageFrame(1, MakeSpan(&allocator, "message", &storage)); + // Construct a frame list. + for (uint8_t i = 0; i < NUM_FRAME_TYPES; ++i) { + switch (i) { + case PADDING_FRAME: + frames.push_back(QuicFrame(QuicPaddingFrame(-1))); + break; + case RST_STREAM_FRAME: + frames.push_back(QuicFrame(new QuicRstStreamFrame())); + break; + case CONNECTION_CLOSE_FRAME: + frames.push_back(QuicFrame(new QuicConnectionCloseFrame())); + break; + case GOAWAY_FRAME: + frames.push_back(QuicFrame(new QuicGoAwayFrame())); + break; + case WINDOW_UPDATE_FRAME: + frames.push_back(QuicFrame(new QuicWindowUpdateFrame())); + break; + case BLOCKED_FRAME: + frames.push_back(QuicFrame(new QuicBlockedFrame())); + break; + case STOP_WAITING_FRAME: + frames.push_back(QuicFrame(QuicStopWaitingFrame())); + break; + case PING_FRAME: + frames.push_back(QuicFrame(QuicPingFrame())); + break; + case CRYPTO_FRAME: + frames.push_back(QuicFrame(new QuicCryptoFrame())); + break; + case STREAM_FRAME: + frames.push_back(QuicFrame(QuicStreamFrame())); + break; + case ACK_FRAME: + frames.push_back(QuicFrame(new QuicAckFrame())); + break; + case MTU_DISCOVERY_FRAME: + frames.push_back(QuicFrame(QuicMtuDiscoveryFrame())); + break; + case NEW_CONNECTION_ID_FRAME: + frames.push_back(QuicFrame(new QuicNewConnectionIdFrame())); + break; + case MAX_STREAMS_FRAME: + frames.push_back(QuicFrame(QuicMaxStreamsFrame())); + break; + case STREAMS_BLOCKED_FRAME: + frames.push_back(QuicFrame(QuicStreamsBlockedFrame())); + break; + case PATH_RESPONSE_FRAME: + frames.push_back(QuicFrame(new QuicPathResponseFrame())); + break; + case PATH_CHALLENGE_FRAME: + frames.push_back(QuicFrame(new QuicPathChallengeFrame())); + break; + case STOP_SENDING_FRAME: + frames.push_back(QuicFrame(new QuicStopSendingFrame())); + break; + case MESSAGE_FRAME: + frames.push_back(QuicFrame(message_frame)); + break; + case NEW_TOKEN_FRAME: + frames.push_back(QuicFrame(new QuicNewTokenFrame())); + break; + case RETIRE_CONNECTION_ID_FRAME: + frames.push_back(QuicFrame(new QuicRetireConnectionIdFrame())); + break; + default: + ASSERT_TRUE(false) + << "Please fix CopyQuicFrames if a new frame type is added."; + break; + } + } + + QuicFrames copy = CopyQuicFrames(&allocator, frames); + ASSERT_EQ(NUM_FRAME_TYPES, copy.size()); + for (uint8_t i = 0; i < NUM_FRAME_TYPES; ++i) { + EXPECT_EQ(i, copy[i].type); + if (i != MESSAGE_FRAME) { + continue; + } + // Verify message frame is correctly copied. + EXPECT_EQ(1u, copy[i].message_frame->message_id); + EXPECT_EQ(nullptr, copy[i].message_frame->data); + EXPECT_EQ(7u, copy[i].message_frame->message_length); + ASSERT_EQ(1u, copy[i].message_frame->message_data.size()); + EXPECT_EQ(0, memcmp(copy[i].message_frame->message_data[0].data(), + frames[i].message_frame->message_data[0].data(), 7)); + } + DeleteFrames(&frames); + DeleteFrames(©); +} + class PacketNumberQueueTest : public QuicTest {}; // Tests that a queue contains the expected data after calls to Add(). diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc index b9413c7e271..d0e65d20d13 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc @@ -43,4 +43,14 @@ std::ostream& operator<<(std::ostream& os, return os; } +bool QuicStreamFrame::operator==(const QuicStreamFrame& rhs) const { + return fin == rhs.fin && data_length == rhs.data_length && + stream_id == rhs.stream_id && data_buffer == rhs.data_buffer && + offset == rhs.offset; +} + +bool QuicStreamFrame::operator!=(const QuicStreamFrame& rhs) const { + return !(*this == rhs); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h index 6cd510d41f5..5c5323b2d57 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h @@ -31,6 +31,10 @@ struct QUIC_EXPORT_PRIVATE QuicStreamFrame friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const QuicStreamFrame& s); + bool operator==(const QuicStreamFrame& rhs) const; + + bool operator!=(const QuicStreamFrame& rhs) const; + bool fin; QuicPacketLength data_length; QuicStreamId stream_id; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc index 07e31687fbd..81ca125b64c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc @@ -13,16 +13,16 @@ QuicWindowUpdateFrame::QuicWindowUpdateFrame() QuicWindowUpdateFrame::QuicWindowUpdateFrame( QuicControlFrameId control_frame_id, QuicStreamId stream_id, - QuicStreamOffset byte_offset) + QuicByteCount max_data) : control_frame_id(control_frame_id), stream_id(stream_id), - byte_offset(byte_offset) {} + max_data(max_data) {} std::ostream& operator<<(std::ostream& os, const QuicWindowUpdateFrame& window_update_frame) { os << "{ control_frame_id: " << window_update_frame.control_frame_id << ", stream_id: " << window_update_frame.stream_id - << ", byte_offset: " << window_update_frame.byte_offset << " }\n"; + << ", max_data: " << window_update_frame.max_data << " }\n"; return os; } diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h index 73163cecb19..ff4478528dd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h @@ -12,15 +12,13 @@ namespace quic { // Flow control updates per-stream and at the connection level. -// Based on SPDY's WINDOW_UPDATE frame, but uses an absolute byte offset rather -// than a window delta. -// TODO(rjshade): A possible future optimization is to make stream_id and -// byte_offset variable length, similar to stream frames. +// Based on SPDY's WINDOW_UPDATE frame, but uses an absolute max data bytes +// rather than a window delta. struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame { QuicWindowUpdateFrame(); QuicWindowUpdateFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, - QuicStreamOffset byte_offset); + QuicByteCount max_data); friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( std::ostream& os, @@ -34,13 +32,9 @@ struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame { // connection rather than a specific stream. QuicStreamId stream_id; - // Byte offset in the stream or connection. The receiver of this frame must - // not send data which would result in this offset being exceeded. - // - // TODO(fkastenholz): Rename this to max_data and change the type to - // QuicByteCount because the IETF defines this as the "maximum - // amount of data that can be sent". - QuicStreamOffset byte_offset; + // Maximum data allowed in the stream or connection. The receiver of this + // frame must not send data which would exceedes this restriction. + QuicByteCount max_data; }; } // 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 new file mode 100644 index 00000000000..9eae32ab8cf --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ +#define QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ + +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +class QuicDecrypter; +class QuicEncrypter; + +// Pure virtual class to get notified when particular handshake events occurred. +class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface { + public: + virtual ~HandshakerDelegateInterface() {} + + // Called when new keys are available. + virtual void OnNewKeysAvailable(EncryptionLevel level, + std::unique_ptr decrypter, + bool set_alternative_decrypter, + bool latch_once_used, + std::unique_ptr encrypter) = 0; + + // Called to set default encryption level to |level|. + virtual void SetDefaultEncryptionLevel(EncryptionLevel level) = 0; + + // Called to discard old decryption keys to stop processing packets of + // encryption |level|. + virtual void DiscardOldDecryptionKey(EncryptionLevel level) = 0; + + // Called to discard old encryption keys (and neuter obsolete data). + // TODO(fayang): consider to combine this with DiscardOldDecryptionKey. + virtual void DiscardOldEncryptionKey(EncryptionLevel level) = 0; + + // Called to neuter ENCRYPTION_INITIAL data (without discarding initial keys). + virtual void NeuterUnencryptedData() = 0; + + // Called to neuter data of HANDSHAKE_DATA packet number space. In QUIC + // crypto, this is called 1) when a client switches to forward secure + // encryption level and 2) a server successfully processes a forward secure + // packet. Temporarily use this method in TLS handshake when both endpoints + // switch to forward secure encryption level. + // TODO(fayang): use DiscardOldEncryptionKey instead of this method in TLS + // handshake when handshake key discarding settles down. + virtual void NeuterHandshakeData() = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ 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 e7d0329b2af..df2b458d588 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 @@ -14,7 +14,6 @@ #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/http/http_constants.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" #include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" @@ -42,6 +41,8 @@ #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h" #include "net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" @@ -66,7 +67,6 @@ #include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h" using spdy::kV3LowestPriority; -using spdy::SETTINGS_MAX_HEADER_LIST_SIZE; using spdy::SpdyFramer; using spdy::SpdyHeaderBlock; using spdy::SpdySerializedFrame; @@ -141,12 +141,12 @@ std::vector GetTestParams(bool use_tls_handshake) { ParsedQuicVersionVector all_supported_versions = FilterSupportedVersions(AllSupportedVersions()); - // Buckets are separated by versions: versions prior to QUIC_VERSION_47 use + // Buckets are separated by versions: versions without crypto frames use // STREAM frames for the handshake, and only have QUIC crypto as the handshake - // protocol. Version 47 and greater use CRYPTO frames for the handshake, and - // must also be split based on the handshake protocol. If the handshake - // protocol (QUIC crypto or TLS) changes, the ClientHello/CHLO must be - // reconstructed for the correct protocol. + // protocol. Versions that use CRYPTO frames for the handshake must also be + // split based on the handshake protocol. If the handshake protocol (QUIC + // crypto or TLS) changes, the ClientHello/CHLO must be reconstructed for the + // correct protocol. ParsedQuicVersionVector version_buckets[3]; for (const ParsedQuicVersion& version : all_supported_versions) { @@ -248,7 +248,6 @@ class EndToEndTest : public QuicTestWithParam { support_server_push_(false), expected_server_connection_id_length_(kQuicDefaultConnectionIdLength) { SetQuicReloadableFlag(quic_supports_tls_handshake, true); - SetQuicReloadableFlag(quic_simplify_stop_waiting, true); client_supported_versions_ = GetParam().client_supported_versions; server_supported_versions_ = GetParam().server_supported_versions; negotiated_version_ = GetParam().negotiated_version; @@ -682,6 +681,21 @@ TEST_P(EndToEndTestWithTls, SimpleRequestResponse) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } +TEST_P(EndToEndTestWithTls, SendAndReceiveCoalescedPackets) { + ASSERT_TRUE(Initialize()); + if (!GetClientConnection()->version().CanSendCoalescedPackets()) { + return; + } + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + // Verify client successfully processes coalesced packets. + QuicConnectionStats client_stats = GetClientConnection()->GetStats(); + EXPECT_LT(0u, client_stats.num_coalesced_packets_received); + EXPECT_EQ(client_stats.num_coalesced_packets_processed, + client_stats.num_coalesced_packets_received); + // TODO(fayang): verify server successfully processes coalesced packets. +} + // Simple transaction, but set a non-default ack delay at the client // and ensure it gets to the server. TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) { @@ -1628,8 +1642,9 @@ TEST_P(EndToEndTest, InvalidStream) { session, GetNthServerInitiatedBidirectionalId(0)); client_->SendCustomSynchronousRequest(headers, body); - EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error()); - EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error()); + EXPECT_THAT(client_->stream_error(), + IsStreamError(QUIC_STREAM_CONNECTION_ERROR)); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_INVALID_STREAM_ID)); } // Test that if the server will close the connection if the client attempts @@ -1654,11 +1669,11 @@ TEST_P(EndToEndTest, LargeHeaders) { ->client_session() ->connection() ->transport_version())) { - EXPECT_EQ(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, - client_->connection_error()); + EXPECT_THAT(client_->connection_error(), + IsError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)); } else { - EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, client_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE)); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } } @@ -1679,8 +1694,8 @@ TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) { client_->SendCustomSynchronousRequest(headers, large_body); EXPECT_EQ("bad", client_->response_body()); EXPECT_EQ("500", client_->response_headers()->find(":status")->second); - EXPECT_EQ(QUIC_STREAM_NO_ERROR, client_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->stream_error(), IsQuicStreamNoError()); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } // TODO(rch): this test seems to cause net_unittests timeouts :| @@ -1726,11 +1741,13 @@ TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) { ASSERT_TRUE(Initialize()); if (VersionHasIetfQuicFrames( GetParam().negotiated_version.transport_version)) { - // Do not run this test for /IETF QUIC. Note that the test needs - // to be here, after calling Initialize(), because all tests end up calling - // EndToEndTest::TearDown(), which asserts that Initialize has been called - // and then proceeds to tear things down -- which fails if they are not - // properly set up. + // Do not run this test for /IETF QUIC. This test relies on the fact that + // Google QUIC allows a small number of additional streams beyond the + // negotiated limit, which is not supported in IETF QUIC. Note that the test + // needs to be here, after calling Initialize(), because all tests end up + // calling EndToEndTest::TearDown(), which asserts that Initialize has been + // called and then proceeds to tear things down -- which fails if they are + // not properly set up. return; } EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -1755,8 +1772,8 @@ TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) { client_->WaitForResponse(); EXPECT_TRUE(client_->connected()); - EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->stream_error(), IsStreamError(QUIC_REFUSED_STREAM)); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) { @@ -2090,7 +2107,7 @@ TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) { } // It should be completely fine to RST a stream before any data has been // received for that stream. - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) { @@ -2604,7 +2621,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicReset) { // The request should fail. EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); EXPECT_TRUE(client_->response_headers()->empty()); - EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_PUBLIC_RESET)); } // Send a public reset from the server for a different connection ID. @@ -2650,7 +2667,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) { // ID. EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); EXPECT_TRUE(client_->response_headers()->empty()); - EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_PUBLIC_RESET)); return; } // The connection should be unaffected. @@ -2745,8 +2762,8 @@ TEST_P(EndToEndTestWithTls, BadPacketHeaderTruncated) { server_thread_->Pause(); QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server_thread_->server()); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, - QuicDispatcherPeer::GetAndClearLastError(dispatcher)); + EXPECT_THAT(QuicDispatcherPeer::GetAndClearLastError(dispatcher), + IsError(QUIC_INVALID_PACKET_HEADER)); server_thread_->Resume(); // The connection should not be terminated. @@ -2796,8 +2813,8 @@ TEST_P(EndToEndTestWithTls, BadPacketHeaderFlags) { server_thread_->Pause(); QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server_thread_->server()); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, - QuicDispatcherPeer::GetAndClearLastError(dispatcher)); + EXPECT_THAT(QuicDispatcherPeer::GetAndClearLastError(dispatcher), + IsError(QUIC_INVALID_PACKET_HEADER)); server_thread_->Resume(); // The connection should not be terminated. @@ -2834,8 +2851,8 @@ TEST_P(EndToEndTestWithTls, BadEncryptedData) { server_thread_->Pause(); QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server_thread_->server()); - EXPECT_EQ(QUIC_NO_ERROR, - QuicDispatcherPeer::GetAndClearLastError(dispatcher)); + EXPECT_THAT(QuicDispatcherPeer::GetAndClearLastError(dispatcher), + IsQuicNoError()); server_thread_->Resume(); // The connection should not be terminated. @@ -3105,7 +3122,6 @@ TEST_P(EndToEndTestWithTls, Trailers) { SpdyHeaderBlock headers; headers[":status"] = "200"; - headers[":version"] = "HTTP/1.1"; headers["content-length"] = QuicTextUtils::Uint64ToString(kBody.size()); SpdyHeaderBlock trailers; @@ -3159,7 +3175,6 @@ class EndToEndTestServerPush : public EndToEndTest { ? large_resource : QuicStrCat("This is server push response body for ", url); SpdyHeaderBlock response_headers; - response_headers[":version"] = "HTTP/1.1"; response_headers[":status"] = "200"; response_headers["content-length"] = QuicTextUtils::Uint64ToString(body.size()); @@ -3235,6 +3250,7 @@ TEST_P(EndToEndTestServerPush, ServerPush) { } TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { + SetQuicReloadableFlag(quic_send_max_push_id_with_settings, true); // Tests that sending a request which has 4 push resources will trigger server // to push those 4 resources and client can handle pushed resources and match // them with requests later. @@ -3340,6 +3356,7 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { } TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { + SetQuicReloadableFlag(quic_send_max_push_id_with_settings, true); // Tests that when server tries to send more large resources(large enough to // be blocked by flow control window or congestion control window) than max // open outgoing streams , server can open upto max number of outgoing @@ -3555,8 +3572,8 @@ TEST_P(EndToEndTest, WayTooLongRequestHeaders) { client_->SendMessage(headers, ""); client_->WaitForResponse(); - EXPECT_EQ(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, - client_->connection_error()); + EXPECT_THAT(client_->connection_error(), + IsError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)); } class WindowUpdateObserver : public QuicConnectionDebugVisitor { @@ -3633,7 +3650,7 @@ TEST_P(EndToEndTest, client_.reset(CreateQuicClient(client_writer_)); EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); - EXPECT_EQ(QUIC_HANDSHAKE_FAILED, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_FAILED)); } // Regression test for b/116200989. @@ -3670,7 +3687,7 @@ TEST_P(EndToEndTest, // Second, a /big_response request with big response should fail. EXPECT_LT(client_->SendSynchronousRequest("/big_response").length(), kBigResponseBodySize); - EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_PUBLIC_RESET)); } // Regression test of b/70782529. @@ -3742,7 +3759,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyMismatch)) { // return whether it is successful. ASSERT_FALSE(Initialize() && client_->client()->WaitForCryptoHandshakeConfirmed()); - EXPECT_EQ(QUIC_HANDSHAKE_TIMEOUT, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); } // TODO: reenable once we have a way to make this run faster. @@ -3754,7 +3771,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoClient)) { pre_shared_key_server_ = "foobar"; ASSERT_FALSE(Initialize() && client_->client()->WaitForCryptoHandshakeConfirmed()); - EXPECT_EQ(QUIC_HANDSHAKE_TIMEOUT, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); } // TODO: reenable once we have a way to make this run faster. @@ -3766,7 +3783,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoServer)) { pre_shared_key_client_ = "foobar"; ASSERT_FALSE(Initialize() && client_->client()->WaitForCryptoHandshakeConfirmed()); - EXPECT_EQ(QUIC_HANDSHAKE_TIMEOUT, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); } TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) { @@ -3801,15 +3818,12 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) { client_->WaitForDelayedAcks(); // The real expectation is the test does not crash or timeout. - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } TEST_P(EndToEndTest, ResetStreamOnTtlExpires) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); - if (!GetClientSession()->session_decides_what_to_write()) { - return; - } SetPacketLossPercentage(30); QuicSpdyClientStream* stream = client_->GetOrCreateStream(); @@ -3821,7 +3835,7 @@ TEST_P(EndToEndTest, ResetStreamOnTtlExpires) { std::string body(1024 * 1024, 'a'); stream->WriteOrBufferBody(body, true); client_->WaitForResponse(); - EXPECT_EQ(QUIC_STREAM_TTL_EXPIRED, client_->stream_error()); + EXPECT_THAT(client_->stream_error(), IsStreamError(QUIC_STREAM_TTL_EXPIRED)); } TEST_P(EndToEndTest, SendMessages) { @@ -3888,7 +3902,7 @@ TEST_P(EndToEndTest, SendMessages) { client_session->GetCurrentLargestMessagePayload() + 1), &storage)) .status); - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } class EndToEndPacketReorderingTest : public EndToEndTest { @@ -4037,14 +4051,15 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) { client_->WaitForDelayedAcks(); // The real expectation is the test does not crash or timeout. - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); // And that the stop-sending code is received. QuicSimpleClientStream* client_stream = static_cast(client_->latest_created_stream()); ASSERT_NE(nullptr, client_stream); // Make sure we have the correct stream EXPECT_EQ(stream_id, client_stream->id()); - EXPECT_EQ(kStopSendingTestCode, client_stream->last_stop_sending_code()); + EXPECT_EQ(kStopSendingTestCode, + static_cast(client_stream->stream_error())); } TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) { @@ -4127,7 +4142,7 @@ TEST_P(EndToEndTest, ZeroRttProtectedConnectionClose) { EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); // Verify ZERO_RTT_PROTECTED connection close is successfully processed by // client which switches to FORWARD_SECURE. - EXPECT_EQ(QUIC_PACKET_WRITE_ERROR, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_PACKET_WRITE_ERROR)); } class BadShloPacketWriter2 : public QuicPacketWriterWrapper { @@ -4185,7 +4200,7 @@ TEST_P(EndToEndTest, ForwardSecureConnectionClose) { EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); // Verify ZERO_RTT_PROTECTED connection close is successfully processed by // client. - EXPECT_EQ(QUIC_PACKET_WRITE_ERROR, client_->connection_error()); + EXPECT_THAT(client_->connection_error(), IsError(QUIC_PACKET_WRITE_ERROR)); } // Test that the stream id manager closes the connection if a stream @@ -4215,8 +4230,9 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) { QuicSessionPeer::SetNextOutgoingBidirectionalStreamId( session, GetNthClientInitiatedBidirectionalId(max_number_of_streams + 1)); client_->SendCustomSynchronousRequest(headers, body); - EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error()); - EXPECT_EQ(QUIC_INVALID_STREAM_ID, GetClientSession()->error()); + EXPECT_THAT(client_->stream_error(), + IsStreamError(QUIC_STREAM_CONNECTION_ERROR)); + EXPECT_THAT(GetClientSession()->error(), IsError(QUIC_INVALID_STREAM_ID)); EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, GetClientSession()->close_type()); EXPECT_TRUE( diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc index 42b4dd2a5ac..751ca5876bb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" using ::testing::_; using ::testing::Eq; @@ -133,7 +134,7 @@ class HttpDecoderTest : public QuicTest { }; TEST_F(HttpDecoderTest, InitialState) { - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -171,7 +172,7 @@ TEST_F(HttpDecoderTest, UnknownFrame) { EXPECT_EQ(total_length, decoder_.ProcessInput(input.get(), total_length)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); ASSERT_EQ("", decoder_.error_detail()); EXPECT_EQ(frame_type, current_frame_type()); } @@ -189,19 +190,19 @@ TEST_F(HttpDecoderTest, CancelPush) { EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1}))) .WillOnce(Return(false)); EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1}))); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1}))); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -233,7 +234,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()).WillOnce(Return(false)); EXPECT_EQ(0u, ProcessInputWithGarbageAppended("")); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. @@ -242,7 +243,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("Headers"))); EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. @@ -257,7 +258,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("s"))); EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process push id incrementally and append headers with last byte of push id. @@ -267,7 +268,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); ProcessInputCharByChar(input.substr(0, 9)); EXPECT_EQ(8u, ProcessInput(input.substr(9))); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -286,7 +287,7 @@ TEST_F(HttpDecoderTest, CorruptPushPromiseFrame) { decoder.ProcessInput(input.data(), input.size()); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error()); + EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("PUSH_PROMISE frame malformed.", decoder.error_detail()); } { @@ -298,7 +299,7 @@ TEST_F(HttpDecoderTest, CorruptPushPromiseFrame) { decoder.ProcessInput(&c, 1); } - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error()); + EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("PUSH_PROMISE frame malformed.", decoder.error_detail()); } } @@ -314,19 +315,19 @@ TEST_F(HttpDecoderTest, MaxPushId) { EXPECT_CALL(visitor_, OnMaxPushIdFrame(MaxPushIdFrame({1}))) .WillOnce(Return(false)); EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnMaxPushIdFrame(MaxPushIdFrame({1}))); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnMaxPushIdFrame(MaxPushIdFrame({1}))); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -341,19 +342,19 @@ TEST_F(HttpDecoderTest, DuplicatePush) { EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1}))) .WillOnce(Return(false)); EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1}))); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1}))); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -386,21 +387,21 @@ TEST_F(HttpDecoderTest, PriorityFrame) { EXPECT_CALL(visitor_, OnPriorityFrame(frame)).WillOnce(Return(false)); processed_bytes = ProcessInputWithGarbageAppended(remaining_input); EXPECT_EQ(remaining_input.size(), processed_bytes); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnPriorityFrameStart(2)); EXPECT_CALL(visitor_, OnPriorityFrame(frame)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnPriorityFrameStart(2)); EXPECT_CALL(visitor_, OnPriorityFrame(frame)); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); std::string input2 = QuicTextUtils::HexDecode( @@ -417,7 +418,7 @@ TEST_F(HttpDecoderTest, PriorityFrame) { EXPECT_CALL(visitor_, OnPriorityFrameStart(2)); EXPECT_CALL(visitor_, OnPriorityFrame(frame2)); EXPECT_EQ(input2.size(), ProcessInput(input2)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -462,7 +463,7 @@ TEST_F(HttpDecoderTest, CorruptPriorityFrame) { QuicByteCount processed_bytes = decoder.ProcessInput(input.data(), input.size()); EXPECT_EQ(input.size(), processed_bytes); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error()); + EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } } @@ -495,21 +496,21 @@ TEST_F(HttpDecoderTest, SettingsFrame) { EXPECT_CALL(visitor_, OnSettingsFrame(frame)).WillOnce(Return(false)); processed_bytes = ProcessInputWithGarbageAppended(remaining_input); EXPECT_EQ(remaining_input.size(), processed_bytes); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnSettingsFrameStart(2)); EXPECT_CALL(visitor_, OnSettingsFrame(frame)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnSettingsFrameStart(2)); EXPECT_CALL(visitor_, OnSettingsFrame(frame)); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -543,7 +544,7 @@ TEST_F(HttpDecoderTest, CorruptSettingsFrame) { QuicByteCount processed_bytes = decoder.ProcessInput(input.data(), input.size()); EXPECT_EQ(input.size(), processed_bytes); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error()); + EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } } @@ -562,7 +563,7 @@ TEST_F(HttpDecoderTest, DuplicateSettingsIdentifier) { EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Duplicate SETTINGS identifier.", decoder_.error_detail()); } @@ -587,7 +588,7 @@ TEST_F(HttpDecoderTest, DataFrame) { EXPECT_CALL(visitor_, OnDataFrameEnd()).WillOnce(Return(false)); EXPECT_EQ(0u, ProcessInputWithGarbageAppended("")); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. @@ -595,7 +596,7 @@ TEST_F(HttpDecoderTest, DataFrame) { EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("Data!"))); EXPECT_CALL(visitor_, OnDataFrameEnd()); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. @@ -607,7 +608,7 @@ TEST_F(HttpDecoderTest, DataFrame) { EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("!"))); EXPECT_CALL(visitor_, OnDataFrameEnd()); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -615,28 +616,27 @@ TEST_F(HttpDecoderTest, FrameHeaderPartialDelivery) { InSequence s; // A large input that will occupy more than 1 byte in the length field. std::string input(2048, 'x'); - HttpEncoder encoder; std::unique_ptr buffer; QuicByteCount header_length = - encoder.SerializeDataFrameHeader(input.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(input.length(), &buffer); std::string header = std::string(buffer.get(), header_length); // Partially send only 1 byte of the header to process. EXPECT_EQ(1u, decoder_.ProcessInput(header.data(), 1)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Send the rest of the header. EXPECT_CALL(visitor_, OnDataFrameStart(3)); EXPECT_EQ(header_length - 1, decoder_.ProcessInput(header.data() + 1, header_length - 1)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Send data. EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece(input))); EXPECT_CALL(visitor_, OnDataFrameEnd()); EXPECT_EQ(2048u, decoder_.ProcessInput(input.data(), 2048)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -662,7 +662,7 @@ TEST_F(HttpDecoderTest, PartialDeliveryOfLargeFrameType) { EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); } - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); EXPECT_EQ(frame_type, current_frame_type()); } @@ -678,19 +678,19 @@ TEST_F(HttpDecoderTest, GoAway) { EXPECT_CALL(visitor_, OnGoAwayFrame(GoAwayFrame({1}))) .WillOnce(Return(false)); EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnGoAwayFrame(GoAwayFrame({1}))); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnGoAwayFrame(GoAwayFrame({1}))); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -716,7 +716,7 @@ TEST_F(HttpDecoderTest, HeadersFrame) { EXPECT_CALL(visitor_, OnHeadersFrameEnd()).WillOnce(Return(false)); EXPECT_EQ(0u, ProcessInputWithGarbageAppended("")); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. @@ -724,7 +724,7 @@ TEST_F(HttpDecoderTest, HeadersFrame) { EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers"))); EXPECT_CALL(visitor_, OnHeadersFrameEnd()); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. @@ -738,7 +738,7 @@ TEST_F(HttpDecoderTest, HeadersFrame) { EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("s"))); EXPECT_CALL(visitor_, OnHeadersFrameEnd()); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -754,21 +754,21 @@ TEST_F(HttpDecoderTest, EmptyDataFrame) { EXPECT_CALL(visitor_, OnDataFrameEnd()).WillOnce(Return(false)); EXPECT_EQ(0u, ProcessInputWithGarbageAppended("")); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnDataFrameStart(2)); EXPECT_CALL(visitor_, OnDataFrameEnd()); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnDataFrameStart(2)); EXPECT_CALL(visitor_, OnDataFrameEnd()); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -784,21 +784,21 @@ TEST_F(HttpDecoderTest, EmptyHeadersFrame) { EXPECT_CALL(visitor_, OnHeadersFrameEnd()).WillOnce(Return(false)); EXPECT_EQ(0u, ProcessInputWithGarbageAppended("")); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. EXPECT_CALL(visitor_, OnHeadersFrameStart(2)); EXPECT_CALL(visitor_, OnHeadersFrameEnd()); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. EXPECT_CALL(visitor_, OnHeadersFrameStart(2)); EXPECT_CALL(visitor_, OnHeadersFrameEnd()); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -816,7 +816,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()).WillOnce(Return(false)); EXPECT_EQ(0u, ProcessInputWithGarbageAppended("")); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the full frame. @@ -824,7 +824,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { EXPECT_CALL(visitor_, OnPushPromiseFramePushId(1, 1)); EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); // Process the frame incrementally. @@ -832,7 +832,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { EXPECT_CALL(visitor_, OnPushPromiseFramePushId(1, 1)); EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); ProcessInputCharByChar(input); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -844,7 +844,7 @@ TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) { // Process the full frame. EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(2u, ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Frame is too large", decoder_.error_detail()); } @@ -859,7 +859,7 @@ TEST_F(HttpDecoderTest, MalformedSettingsFrame) { writer.WriteStringPiece("Malformed payload"); EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(5u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Frame is too large", decoder_.error_detail()); } @@ -891,7 +891,7 @@ TEST_F(HttpDecoderTest, HeadersPausedThenData) { processed_bytes = ProcessInput(remaining_input); EXPECT_EQ(remaining_input.size(), processed_bytes); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -945,7 +945,7 @@ TEST_F(HttpDecoderTest, CorruptFrame) { QuicStringPiece input(test_data.input); decoder.ProcessInput(input.data(), input.size()); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error()); + EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } { @@ -956,7 +956,7 @@ TEST_F(HttpDecoderTest, CorruptFrame) { for (auto c : input) { decoder.ProcessInput(&c, 1); } - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error()); + EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } } @@ -969,7 +969,7 @@ TEST_F(HttpDecoderTest, EmptyCancelPushFrame) { EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Unable to read push_id", decoder_.error_detail()); } @@ -984,7 +984,7 @@ TEST_F(HttpDecoderTest, EmptySettingsFrame) { EXPECT_CALL(visitor_, OnSettingsFrame(empty_frame)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } @@ -996,7 +996,7 @@ TEST_F(HttpDecoderTest, EmptyPushPromiseFrame) { EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Corrupt PUSH_PROMISE frame.", decoder_.error_detail()); } @@ -1007,7 +1007,7 @@ TEST_F(HttpDecoderTest, EmptyGoAwayFrame) { EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Unable to read GOAWAY stream_id", decoder_.error_detail()); } @@ -1018,7 +1018,7 @@ TEST_F(HttpDecoderTest, EmptyMaxPushIdFrame) { EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Unable to read push_id", decoder_.error_detail()); } @@ -1029,20 +1029,19 @@ TEST_F(HttpDecoderTest, EmptyDuplicatePushFrame) { EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Unable to read push_id", decoder_.error_detail()); } TEST_F(HttpDecoderTest, LargeStreamIdInGoAway) { - HttpEncoder encoder; GoAwayFrame frame; frame.stream_id = 1 << 30; std::unique_ptr buffer; - uint64_t length = encoder.SerializeGoAwayFrame(frame, &buffer); + uint64_t length = HttpEncoder::SerializeGoAwayFrame(frame, &buffer); EXPECT_CALL(visitor_, OnGoAwayFrame(frame)); EXPECT_GT(length, 0u); EXPECT_EQ(length, decoder_.ProcessInput(buffer.get(), length)); - EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); EXPECT_EQ("", decoder_.error_detail()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc index b97f7f79619..6bb25cf16fe 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc @@ -40,12 +40,45 @@ uint8_t SetPriorityFields(uint8_t num, } } -} // namespace +bool WriteFrameHeader(QuicByteCount length, + HttpFrameType type, + QuicDataWriter* writer) { + return writer->WriteVarInt62(static_cast(type)) && + writer->WriteVarInt62(length); +} -HttpEncoder::HttpEncoder() {} +QuicByteCount GetTotalLength(QuicByteCount payload_length, HttpFrameType type) { + return QuicDataWriter::GetVarInt62Len(payload_length) + + QuicDataWriter::GetVarInt62Len(static_cast(type)) + + payload_length; +} + +// Write prioritized element id and element dependency id if needed. +bool MaybeWriteIds(const PriorityFrame& priority, QuicDataWriter* writer) { + if (priority.prioritized_type != ROOT_OF_TREE) { + if (!writer->WriteVarInt62(priority.prioritized_element_id)) { + return false; + } + } else { + DCHECK_EQ(0u, priority.prioritized_element_id) + << "Prioritized element id should be 0 when prioritized type is " + "ROOT_OF_TREE"; + } + if (priority.dependency_type != ROOT_OF_TREE) { + if (!writer->WriteVarInt62(priority.element_dependency_id)) { + return false; + } + } else { + DCHECK_EQ(0u, priority.element_dependency_id) + << "Element dependency id should be 0 when dependency type is " + "ROOT_OF_TREE"; + } + return true; +} -HttpEncoder::~HttpEncoder() {} +} // namespace +// static QuicByteCount HttpEncoder::SerializeDataFrameHeader( QuicByteCount payload_length, std::unique_ptr* output) { @@ -65,6 +98,7 @@ QuicByteCount HttpEncoder::SerializeDataFrameHeader( return 0; } +// static QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( QuicByteCount payload_length, std::unique_ptr* output) { @@ -86,6 +120,7 @@ QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( return 0; } +// static QuicByteCount HttpEncoder::SerializePriorityFrame( const PriorityFrame& priority, std::unique_ptr* output) { @@ -127,6 +162,7 @@ QuicByteCount HttpEncoder::SerializePriorityFrame( return 0; } +// static QuicByteCount HttpEncoder::SerializeCancelPushFrame( const CancelPushFrame& cancel_push, std::unique_ptr* output) { @@ -147,6 +183,7 @@ QuicByteCount HttpEncoder::SerializeCancelPushFrame( return 0; } +// static QuicByteCount HttpEncoder::SerializeSettingsFrame( const SettingsFrame& settings, std::unique_ptr* output) { @@ -180,6 +217,7 @@ QuicByteCount HttpEncoder::SerializeSettingsFrame( return total_length; } +// static QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( const PushPromiseFrame& push_promise, std::unique_ptr* output) { @@ -205,6 +243,7 @@ QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( return 0; } +// static QuicByteCount HttpEncoder::SerializeGoAwayFrame( const GoAwayFrame& goaway, std::unique_ptr* output) { @@ -225,6 +264,7 @@ QuicByteCount HttpEncoder::SerializeGoAwayFrame( return 0; } +// static QuicByteCount HttpEncoder::SerializeMaxPushIdFrame( const MaxPushIdFrame& max_push_id, std::unique_ptr* output) { @@ -245,6 +285,7 @@ QuicByteCount HttpEncoder::SerializeMaxPushIdFrame( return 0; } +// static QuicByteCount HttpEncoder::SerializeDuplicatePushFrame( const DuplicatePushFrame& duplicate_push, std::unique_ptr* output) { @@ -266,41 +307,4 @@ QuicByteCount HttpEncoder::SerializeDuplicatePushFrame( return 0; } -bool HttpEncoder::WriteFrameHeader(QuicByteCount length, - HttpFrameType type, - QuicDataWriter* writer) { - return writer->WriteVarInt62(static_cast(type)) && - writer->WriteVarInt62(length); -} - -QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length, - HttpFrameType type) { - return QuicDataWriter::GetVarInt62Len(payload_length) + - QuicDataWriter::GetVarInt62Len(static_cast(type)) + - payload_length; -} - -bool HttpEncoder::MaybeWriteIds(const PriorityFrame& priority, - QuicDataWriter* writer) { - if (priority.prioritized_type != ROOT_OF_TREE) { - if (!writer->WriteVarInt62(priority.prioritized_element_id)) { - return false; - } - } else { - DCHECK_EQ(0u, priority.prioritized_element_id) - << "Prioritized element id should be 0 when prioritized type is " - "ROOT_OF_TREE"; - } - if (priority.dependency_type != ROOT_OF_TREE) { - if (!writer->WriteVarInt62(priority.element_dependency_id)) { - return false; - } - } else { - DCHECK_EQ(0u, priority.element_dependency_id) - << "Element dependency id should be 0 when dependency type is " - "ROOT_OF_TREE"; - } - return true; -} - } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h index 12c5bab56c2..4420fc65b7b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h @@ -17,68 +17,59 @@ class QuicDataWriter; // session. class QUIC_EXPORT_PRIVATE HttpEncoder { public: - HttpEncoder(); - - ~HttpEncoder(); + HttpEncoder() = delete; // Serializes a DATA frame header into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeDataFrameHeader(QuicByteCount payload_length, - std::unique_ptr* output); + static QuicByteCount SerializeDataFrameHeader( + QuicByteCount payload_length, + std::unique_ptr* output); // Serializes a HEADERS frame header into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeHeadersFrameHeader(QuicByteCount payload_length, - std::unique_ptr* output); + static QuicByteCount SerializeHeadersFrameHeader( + QuicByteCount payload_length, + std::unique_ptr* output); // Serializes a PRIORITY frame into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializePriorityFrame(const PriorityFrame& priority, - std::unique_ptr* output); + static QuicByteCount SerializePriorityFrame(const PriorityFrame& priority, + std::unique_ptr* output); // Serializes a CANCEL_PUSH frame into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeCancelPushFrame(const CancelPushFrame& cancel_push, - std::unique_ptr* output); + static QuicByteCount SerializeCancelPushFrame( + const CancelPushFrame& cancel_push, + std::unique_ptr* output); // Serializes a SETTINGS frame into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeSettingsFrame(const SettingsFrame& settings, - std::unique_ptr* output); + static QuicByteCount SerializeSettingsFrame(const SettingsFrame& settings, + std::unique_ptr* output); // Serializes the header and push_id of a PUSH_PROMISE frame into a new buffer // stored in |output|. Returns the length of the buffer on success, or 0 // otherwise. - QuicByteCount SerializePushPromiseFrameWithOnlyPushId( + static QuicByteCount SerializePushPromiseFrameWithOnlyPushId( const PushPromiseFrame& push_promise, std::unique_ptr* output); // Serializes a GOAWAY frame into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeGoAwayFrame(const GoAwayFrame& goaway, - std::unique_ptr* output); + static QuicByteCount SerializeGoAwayFrame(const GoAwayFrame& goaway, + std::unique_ptr* output); // Serializes a MAX_PUSH frame into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeMaxPushIdFrame(const MaxPushIdFrame& max_push_id, - std::unique_ptr* output); + static QuicByteCount SerializeMaxPushIdFrame( + const MaxPushIdFrame& max_push_id, + std::unique_ptr* output); // Serialize a DUPLICATE_PUSH frame into a new buffer stored in |output|. // Returns the length of the buffer on success, or 0 otherwise. - QuicByteCount SerializeDuplicatePushFrame( + static QuicByteCount SerializeDuplicatePushFrame( const DuplicatePushFrame& duplicate_push, std::unique_ptr* output); - - private: - bool WriteFrameHeader(QuicByteCount length, - HttpFrameType type, - QuicDataWriter* writer); - - QuicByteCount GetTotalLength(QuicByteCount payload_length, - HttpFrameType type); - - // Write prioritized element id and element dependency id if needed. - bool MaybeWriteIds(const PriorityFrame& priority, QuicDataWriter* writer); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc index 43ae7cd4a29..2df89bd4ae6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc @@ -11,16 +11,10 @@ namespace quic { namespace test { -class HttpEncoderTest : public QuicTest { - public: - HttpEncoderTest() {} - HttpEncoder encoder_; -}; - -TEST_F(HttpEncoderTest, SerializeDataFrameHeader) { +TEST(HttpEncoderTest, SerializeDataFrameHeader) { std::unique_ptr buffer; uint64_t length = - encoder_.SerializeDataFrameHeader(/* payload_length = */ 5, &buffer); + HttpEncoder::SerializeDataFrameHeader(/* payload_length = */ 5, &buffer); char output[] = {// type (DATA) 0x00, // length @@ -30,10 +24,10 @@ TEST_F(HttpEncoderTest, SerializeDataFrameHeader) { QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializeHeadersFrameHeader) { +TEST(HttpEncoderTest, SerializeHeadersFrameHeader) { std::unique_ptr buffer; - uint64_t length = - encoder_.SerializeHeadersFrameHeader(/* payload_length = */ 7, &buffer); + uint64_t length = HttpEncoder::SerializeHeadersFrameHeader( + /* payload_length = */ 7, &buffer); char output[] = {// type (HEADERS) 0x01, // length @@ -43,7 +37,7 @@ TEST_F(HttpEncoderTest, SerializeHeadersFrameHeader) { QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializePriorityFrame) { +TEST(HttpEncoderTest, SerializePriorityFrame) { PriorityFrame priority; priority.prioritized_type = REQUEST_STREAM; priority.dependency_type = REQUEST_STREAM; @@ -65,7 +59,7 @@ TEST_F(HttpEncoderTest, SerializePriorityFrame) { 0xFF}; std::unique_ptr buffer; - uint64_t length = encoder_.SerializePriorityFrame(priority, &buffer); + uint64_t length = HttpEncoder::SerializePriorityFrame(priority, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); @@ -86,7 +80,7 @@ TEST_F(HttpEncoderTest, SerializePriorityFrame) { 0x04, // weight 0xff}; - length = encoder_.SerializePriorityFrame(priority2, &buffer); + length = HttpEncoder::SerializePriorityFrame(priority2, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output2), length); CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output2, QUIC_ARRAYSIZE(output2)); @@ -104,13 +98,13 @@ TEST_F(HttpEncoderTest, SerializePriorityFrame) { 0xf8, // weight 0xff}; - length = encoder_.SerializePriorityFrame(priority3, &buffer); + length = HttpEncoder::SerializePriorityFrame(priority3, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output3), length); CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output3, QUIC_ARRAYSIZE(output3)); } -TEST_F(HttpEncoderTest, SerializeCancelPushFrame) { +TEST(HttpEncoderTest, SerializeCancelPushFrame) { CancelPushFrame cancel_push; cancel_push.push_id = 0x01; char output[] = {// type (CANCEL_PUSH) @@ -120,13 +114,13 @@ TEST_F(HttpEncoderTest, SerializeCancelPushFrame) { // Push Id 0x01}; std::unique_ptr buffer; - uint64_t length = encoder_.SerializeCancelPushFrame(cancel_push, &buffer); + uint64_t length = HttpEncoder::SerializeCancelPushFrame(cancel_push, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("CANCEL_PUSH", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializeSettingsFrame) { +TEST(HttpEncoderTest, SerializeSettingsFrame) { SettingsFrame settings; settings.values[1] = 2; settings.values[6] = 5; @@ -148,13 +142,13 @@ TEST_F(HttpEncoderTest, SerializeSettingsFrame) { // content 0x04}; std::unique_ptr buffer; - uint64_t length = encoder_.SerializeSettingsFrame(settings, &buffer); + uint64_t length = HttpEncoder::SerializeSettingsFrame(settings, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("SETTINGS", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializePushPromiseFrameWithOnlyPushId) { +TEST(HttpEncoderTest, SerializePushPromiseFrameWithOnlyPushId) { PushPromiseFrame push_promise; push_promise.push_id = 0x01; push_promise.headers = "Headers"; @@ -165,14 +159,14 @@ TEST_F(HttpEncoderTest, SerializePushPromiseFrameWithOnlyPushId) { // Push Id 0x01}; std::unique_ptr buffer; - uint64_t length = - encoder_.SerializePushPromiseFrameWithOnlyPushId(push_promise, &buffer); + uint64_t length = HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( + push_promise, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("PUSH_PROMISE", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializeGoAwayFrame) { +TEST(HttpEncoderTest, SerializeGoAwayFrame) { GoAwayFrame goaway; goaway.stream_id = 0x1; char output[] = {// type (GOAWAY) @@ -182,13 +176,13 @@ TEST_F(HttpEncoderTest, SerializeGoAwayFrame) { // StreamId 0x01}; std::unique_ptr buffer; - uint64_t length = encoder_.SerializeGoAwayFrame(goaway, &buffer); + uint64_t length = HttpEncoder::SerializeGoAwayFrame(goaway, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("GOAWAY", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializeMaxPushIdFrame) { +TEST(HttpEncoderTest, SerializeMaxPushIdFrame) { MaxPushIdFrame max_push_id; max_push_id.push_id = 0x1; char output[] = {// type (MAX_PUSH_ID) @@ -198,13 +192,13 @@ TEST_F(HttpEncoderTest, SerializeMaxPushIdFrame) { // Push Id 0x01}; std::unique_ptr buffer; - uint64_t length = encoder_.SerializeMaxPushIdFrame(max_push_id, &buffer); + uint64_t length = HttpEncoder::SerializeMaxPushIdFrame(max_push_id, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("MAX_PUSH_ID", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); } -TEST_F(HttpEncoderTest, SerializeDuplicatePushFrame) { +TEST(HttpEncoderTest, SerializeDuplicatePushFrame) { DuplicatePushFrame duplicate_push; duplicate_push.push_id = 0x1; char output[] = {// type (DUPLICATE_PUSH) @@ -215,7 +209,7 @@ TEST_F(HttpEncoderTest, SerializeDuplicatePushFrame) { 0x01}; std::unique_ptr buffer; uint64_t length = - encoder_.SerializeDuplicatePushFrame(duplicate_push, &buffer); + HttpEncoder::SerializeDuplicatePushFrame(duplicate_push, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("DUPLICATE_PUSH", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h index dde8b1e6f9e..215fa568d29 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h @@ -34,7 +34,7 @@ enum class HttpFrameType : uint8_t { // // DATA frames (type=0x0) convey arbitrary, variable-length sequences of // octets associated with an HTTP request or response payload. -struct DataFrame { +struct QUIC_EXPORT_PRIVATE DataFrame { QuicStringPiece data; }; @@ -42,7 +42,7 @@ struct DataFrame { // // The HEADERS frame (type=0x1) is used to carry a header block, // compressed using QPACK. -struct HeadersFrame { +struct QUIC_EXPORT_PRIVATE HeadersFrame { QuicStringPiece headers; }; @@ -65,7 +65,7 @@ enum PriorityElementType : uint8_t { ROOT_OF_TREE = 3 }; -struct PriorityFrame { +struct QUIC_EXPORT_PRIVATE PriorityFrame { PriorityElementType prioritized_type = REQUEST_STREAM; PriorityElementType dependency_type = REQUEST_STREAM; bool exclusive = false; @@ -103,7 +103,7 @@ struct PriorityFrame { // server push prior to the push stream being created. using PushId = uint64_t; -struct CancelPushFrame { +struct QUIC_EXPORT_PRIVATE CancelPushFrame { PushId push_id; bool operator==(const CancelPushFrame& rhs) const { @@ -119,7 +119,7 @@ struct CancelPushFrame { using SettingsMap = std::map; -struct SettingsFrame { +struct QUIC_EXPORT_PRIVATE SettingsFrame { SettingsMap values; bool operator==(const SettingsFrame& rhs) const { @@ -148,7 +148,7 @@ struct SettingsFrame { // // The PUSH_PROMISE frame (type=0x05) is used to carry a request header // set from server to client, as in HTTP/2. -struct PushPromiseFrame { +struct QUIC_EXPORT_PRIVATE PushPromiseFrame { PushId push_id; QuicStringPiece headers; @@ -161,7 +161,7 @@ struct PushPromiseFrame { // // The GOAWAY frame (type=0x7) is used to initiate graceful shutdown of // a connection by a server. -struct GoAwayFrame { +struct QUIC_EXPORT_PRIVATE GoAwayFrame { QuicStreamId stream_id; bool operator==(const GoAwayFrame& rhs) const { @@ -173,7 +173,7 @@ struct GoAwayFrame { // // The MAX_PUSH_ID frame (type=0xD) is used by clients to control the // number of server pushes that the server can initiate. -struct MaxPushIdFrame { +struct QUIC_EXPORT_PRIVATE MaxPushIdFrame { PushId push_id; bool operator==(const MaxPushIdFrame& rhs) const { @@ -186,7 +186,7 @@ struct MaxPushIdFrame { // The DUPLICATE_PUSH frame (type=0xE) is used by servers to indicate // that an existing pushed resource is related to multiple client // requests. -struct DuplicatePushFrame { +struct QUIC_EXPORT_PRIVATE DuplicatePushFrame { PushId push_id; bool operator==(const DuplicatePushFrame& rhs) const { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h index bf614051fc1..9268940240e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h @@ -84,7 +84,7 @@ class QUIC_EXPORT_PRIVATE QuicClientPromisedInfo private: friend class test::QuicClientPromisedInfoPeer; - class CleanupAlarm : public QuicAlarm::Delegate { + class QUIC_EXPORT_PRIVATE CleanupAlarm : public QuicAlarm::Delegate { public: explicit CleanupAlarm(QuicClientPromisedInfo* promised) : promised_(promised) {} 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 e244fcf83c3..27d9fe89630 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 @@ -89,7 +89,6 @@ class QuicClientPromisedInfoTest : public QuicTest { push_promise_[":path"] = "/bar"; push_promise_[":authority"] = "www.google.com"; - push_promise_[":version"] = "HTTP/1.1"; push_promise_[":method"] = "GET"; push_promise_[":scheme"] = "https"; 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 933ef6bb808..3ca377eb729 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 @@ -60,7 +60,6 @@ class QuicClientPushPromiseIndexTest : public QuicTest { url_) { request_[":path"] = "/bar"; request_[":authority"] = "www.google.com"; - request_[":version"] = "HTTP/1.1"; request_[":method"] = "GET"; request_[":scheme"] = "https"; url_ = SpdyServerPushUtils::GetPromisedUrlFromHeaders(request_); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc index f9b730bcb4c..cba3e587ab3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/http/quic_header_list.h" +#include #include #include "net/third_party/quiche/src/quic/core/quic_packets.h" @@ -13,7 +14,7 @@ namespace quic { QuicHeaderList::QuicHeaderList() - : max_header_list_size_(kDefaultMaxUncompressedHeaderSize), + : max_header_list_size_(std::numeric_limits::max()), current_header_list_size_(0), uncompressed_header_bytes_(0), compressed_header_bytes_(0) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list_test.cc index 67bd35f2644..5ff3c5a6b58 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list_test.cc @@ -37,9 +37,12 @@ TEST_F(QuicHeaderListTest, DebugString) { } TEST_F(QuicHeaderListTest, TooLarge) { + const size_t kMaxHeaderListSize = 256; + QuicHeaderList headers; + headers.set_max_header_list_size(kMaxHeaderListSize); std::string key = "key"; - std::string value(1 << 18, '1'); + std::string value(kMaxHeaderListSize, '1'); // Send a header that exceeds max_header_list_size. headers.OnHeader(key, value); // Send a second header exceeding max_header_list_size. @@ -48,8 +51,8 @@ TEST_F(QuicHeaderListTest, TooLarge) { EXPECT_LT(headers.DebugString().size(), 2 * value.size()); size_t total_bytes = 2 * (key.size() + value.size()) + 1; headers.OnHeaderBlockEnd(total_bytes, total_bytes); - EXPECT_TRUE(headers.empty()); + EXPECT_TRUE(headers.empty()); EXPECT_EQ("{ }", headers.DebugString()); } 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 079150638f4..4cf11cc2976 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 @@ -25,6 +25,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" #include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" @@ -36,7 +37,6 @@ using spdy::SETTINGS_HEADER_TABLE_SIZE; using spdy::SETTINGS_INITIAL_WINDOW_SIZE; using spdy::SETTINGS_MAX_CONCURRENT_STREAMS; using spdy::SETTINGS_MAX_FRAME_SIZE; -using spdy::SETTINGS_MAX_HEADER_LIST_SIZE; using spdy::Spdy3PriorityToHttp2Weight; using spdy::SpdyAltSvcWireFormat; using spdy::SpdyDataIR; @@ -200,7 +200,6 @@ class QuicHeadersStreamTest : public QuicTestWithParam { QuicSpdySessionPeer::SetMaxInboundHeaderListSize(&session_, 256 * 1024); session_.Initialize(); headers_stream_ = QuicSpdySessionPeer::GetHeadersStream(&session_); - headers_[":version"] = "HTTP/1.1"; headers_[":status"] = "200 Ok"; headers_["content-length"] = "11"; framer_ = std::unique_ptr( @@ -228,7 +227,7 @@ class QuicHeadersStreamTest : public QuicTestWithParam { QuicConsumedData SaveIov(size_t write_length) { char* buf = new char[write_length]; - QuicDataWriter writer(write_length, buf, NETWORK_BYTE_ORDER); + QuicDataWriter writer(write_length, buf, quiche::NETWORK_BYTE_ORDER); headers_stream_->WriteStreamData(headers_stream_->stream_bytes_written(), write_length, &writer); saved_data_.append(buf, write_length); @@ -306,7 +305,7 @@ class QuicHeadersStreamTest : public QuicTestWithParam { } else { EXPECT_CALL(visitor_, OnHeaders(stream_id, !kHasPriority, - /*priority=*/0, + /*weight=*/0, /*parent_stream_id=*/0, /*exclusive=*/false, fin, kFrameComplete)); } @@ -521,13 +520,7 @@ TEST_P(QuicHeadersStreamTest, ProcessPriorityFrame) { SpdyPriorityIR priority_frame(stream_id, parent_stream_id, weight, true); SpdySerializedFrame frame(framer_->SerializeFrame(priority_frame)); parent_stream_id = stream_id; - if (transport_version() <= QUIC_VERSION_39) { - EXPECT_CALL(*connection_, - CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, - "SPDY PRIORITY frame received.", _)) - .WillRepeatedly(InvokeWithoutArgs( - this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); - } else if (perspective() == Perspective::IS_CLIENT) { + if (perspective() == Perspective::IS_CLIENT) { EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, "Server must not send PRIORITY frames.", _)) 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 4d78106f372..c949fa77c7f 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 @@ -9,6 +9,7 @@ #include "net/third_party/quiche/src/quic/core/http/http_constants.h" #include "net/third_party/quiche/src/quic/core/http/http_decoder.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" namespace quic { @@ -65,9 +66,15 @@ class QuicReceiveControlStream::HttpDecoderVisitor return false; } - bool OnGoAwayFrame(const GoAwayFrame& /*frame*/) override { - CloseConnectionOnWrongFrame("Goaway"); - return false; + bool OnGoAwayFrame(const GoAwayFrame& frame) override { + QuicSpdySession* spdy_session = + static_cast(stream_->session()); + if (spdy_session->perspective() == Perspective::IS_SERVER) { + CloseConnectionOnWrongFrame("Go Away"); + return false; + } + spdy_session->OnHttp3GoAway(frame.stream_id); + return true; } bool OnSettingsFrameStart(QuicByteCount header_length) override { 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 73b30b3ff09..8418766a97a 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 @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h" #include "net/third_party/quiche/src/quic/core/http/http_constants.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_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -17,7 +18,6 @@ namespace test { namespace { using ::testing::_; -using ::testing::AtLeast; using ::testing::StrictMock; struct TestParams { @@ -103,18 +103,16 @@ class QuicReceiveControlStreamTest : public QuicTestWithParam { Perspective perspective() const { return GetParam().perspective; } std::string EncodeSettings(const SettingsFrame& settings) { - HttpEncoder encoder; std::unique_ptr buffer; QuicByteCount settings_frame_length = - encoder.SerializeSettingsFrame(settings, &buffer); + HttpEncoder::SerializeSettingsFrame(settings, &buffer); return std::string(buffer.get(), settings_frame_length); } std::string PriorityFrame(const PriorityFrame& frame) { - HttpEncoder encoder; std::unique_ptr priority_buffer; QuicByteCount priority_frame_length = - encoder.SerializePriorityFrame(frame, &priority_buffer); + HttpEncoder::SerializePriorityFrame(frame, &priority_buffer); return std::string(priority_buffer.get(), priority_frame_length); } @@ -214,11 +212,11 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) { } TEST_P(QuicReceiveControlStreamTest, ReceiveWrongFrame) { - GoAwayFrame goaway; - goaway.stream_id = 0x1; - HttpEncoder encoder; + DuplicatePushFrame dup; + dup.push_id = 0x1; std::unique_ptr buffer; - QuicByteCount header_length = encoder.SerializeGoAwayFrame(goaway, &buffer); + QuicByteCount header_length = + HttpEncoder::SerializeDuplicatePushFrame(dup, &buffer); std::string data = std::string(buffer.get(), header_length); QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data); @@ -245,14 +243,35 @@ TEST_P(QuicReceiveControlStreamTest, ReceivePriorityFrame) { EXPECT_EQ(1u, stream_->precedence().spdy3_priority()); } +TEST_P(QuicReceiveControlStreamTest, ReceiveGoAwayFrame) { + GoAwayFrame goaway; + goaway.stream_id = 0x00; + + std::unique_ptr buffer; + QuicByteCount header_length = + HttpEncoder::SerializeGoAwayFrame(goaway, &buffer); + std::string data = std::string(buffer.get(), header_length); + + QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data); + EXPECT_FALSE(session_.http3_goaway_received()); + + if (perspective() == Perspective::IS_SERVER) { + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)); + } + + receive_control_stream_->OnStreamFrame(frame); + if (perspective() == Perspective::IS_CLIENT) { + EXPECT_TRUE(session_.http3_goaway_received()); + } +} + TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) { PushPromiseFrame push_promise; push_promise.push_id = 0x01; push_promise.headers = "Headers"; std::unique_ptr buffer; - HttpEncoder encoder; - uint64_t length = - encoder.SerializePushPromiseFrameWithOnlyPushId(push_promise, &buffer); + uint64_t length = HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( + push_promise, &buffer); QuicStreamFrame frame(receive_control_stream_->id(), false, 1, buffer.get(), length); // TODO(lassey) Check for HTTP_WRONG_STREAM error code. 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 da7f79e0f92..ed7cd7ffb40 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 @@ -3,11 +3,15 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h" +#include #include "net/third_party/quiche/src/quic/core/http/http_constants.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" #include "net/third_party/quiche/src/quic/core/quic_session.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_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" namespace quic { @@ -55,7 +59,7 @@ void QuicSendControlStream::MaybeSendSettingsFrame() { std::unique_ptr buffer; QuicByteCount frame_length = - encoder_.SerializeSettingsFrame(settings, &buffer); + HttpEncoder::SerializeSettingsFrame(settings, &buffer); QUIC_DVLOG(1) << "Control stream " << id() << " is writing settings frame " << settings; QuicSpdySession* spdy_session = static_cast(session()); @@ -72,7 +76,7 @@ void QuicSendControlStream::WritePriority(const PriorityFrame& priority) { MaybeSendSettingsFrame(); std::unique_ptr buffer; QuicByteCount frame_length = - encoder_.SerializePriorityFrame(priority, &buffer); + HttpEncoder::SerializePriorityFrame(priority, &buffer); QUIC_DVLOG(1) << "Control Stream " << id() << " is writing " << priority; WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), false, nullptr); @@ -85,9 +89,29 @@ void QuicSendControlStream::SendMaxPushIdFrame(PushId max_push_id) { MaxPushIdFrame frame; frame.push_id = max_push_id; std::unique_ptr buffer; - QuicByteCount frame_length = encoder_.SerializeMaxPushIdFrame(frame, &buffer); + QuicByteCount frame_length = + HttpEncoder::SerializeMaxPushIdFrame(frame, &buffer); WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), /*fin = */ false, nullptr); } +void QuicSendControlStream::SendGoAway(QuicStreamId stream_id) { + QuicConnection::ScopedPacketFlusher flusher(session()->connection()); + + MaybeSendSettingsFrame(); + GoAwayFrame frame; + // If the peer hasn't created any stream yet. Use stream id 0 to indicate no + // request is accepted. + if (stream_id == + QuicUtils::GetInvalidStreamId(session()->transport_version())) { + stream_id = 0; + } + frame.stream_id = stream_id; + std::unique_ptr buffer; + QuicByteCount frame_length = + HttpEncoder::SerializeGoAwayFrame(frame, &buffer); + WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), false, + nullptr); +} + } // namespace quic 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 aa8fff156b3..ac946d35a6f 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 @@ -7,6 +7,7 @@ #include "net/third_party/quiche/src/quic/core/http/http_encoder.h" #include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" namespace quic { @@ -42,12 +43,14 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream { // Send |Priority| on this stream. It must be sent after settings. void WritePriority(const PriorityFrame& priority); + // Serialize a GOAWAY frame from |stream_id| and send it on this stream. + void SendGoAway(QuicStreamId stream_id); + // The send control stream is write unidirectional, so this method should // never be called. void OnDataAvailable() override { QUIC_NOTREACHED(); } private: - HttpEncoder encoder_; // Track if a settings frame is already sent. bool settings_sent_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc index a06a3196880..de2e705e8c6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc @@ -93,7 +93,6 @@ class QuicSendControlStreamTest : public QuicTestWithParam { MockAlarmFactory alarm_factory_; StrictMock* connection_; StrictMock session_; - HttpEncoder encoder_; QuicSendControlStream* send_control_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 c7ab6236c29..9e8c749025b 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 @@ -152,9 +152,10 @@ class QuicServerSessionBaseTest : public QuicTestWithParam { QuicCryptoServerConfig::ConfigOptions()); SetQuicReloadableFlag(quic_supports_tls_handshake, true); session_->Initialize(); - QuicSessionPeer::GetMutableCryptoStream(session_.get()) - ->OnSuccessfulVersionNegotiation(supported_versions.front()); - visitor_ = QuicConnectionPeer::GetVisitor(connection_); + if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + QuicSessionPeer::GetMutableCryptoStream(session_.get()) + ->OnSuccessfulVersionNegotiation(supported_versions.front()); + } QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( session_->config(), kMinimumFlowControlSendWindow); session_->OnConfigNegotiated(); @@ -208,7 +209,6 @@ class QuicServerSessionBaseTest : public QuicTestWithParam { QuicMemoryCacheBackend memory_cache_backend_; std::unique_ptr session_; std::unique_ptr handshake_message_; - QuicConnectionVisitorInterface* visitor_; }; // Compares CachedNetworkParameters. @@ -253,7 +253,7 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { OnStreamReset(GetNthClientInitiatedBidirectionalId(0), QUIC_RST_ACKNOWLEDGEMENT)); } - visitor_->OnRstStream(rst1); + session_->OnRstStream(rst1); // For version-99 will create and receive a stop-sending, completing // the full-close expected by this test. @@ -263,7 +263,7 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); // Send the same two bytes of payload in a new packet. - visitor_->OnStreamFrame(data1); + session_->OnStreamFrame(data1); // The stream should not be re-opened. EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); @@ -284,7 +284,7 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { OnStreamReset(GetNthClientInitiatedBidirectionalId(0), QUIC_RST_ACKNOWLEDGEMENT)); } - visitor_->OnRstStream(rst1); + session_->OnRstStream(rst1); // For version-99 will create and receive a stop-sending, completing // the full-close expected by this test. @@ -296,7 +296,7 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { // Send two bytes of payload. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, QuicStringPiece("HT")); - visitor_->OnStreamFrame(data1); + session_->OnStreamFrame(data1); // The stream should never be opened, now that the reset is received. EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); @@ -309,8 +309,8 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { QuicStringPiece("\1\0\0\0\0\0\0\0HT")); QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0, QuicStringPiece("\2\0\0\0\0\0\0\0HT")); - visitor_->OnStreamFrame(frame1); - visitor_->OnStreamFrame(frame2); + session_->OnStreamFrame(frame1); + session_->OnStreamFrame(frame2); EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); // Send a reset (and expect the peer to send a RST in response). @@ -326,7 +326,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { OnStreamReset(GetNthClientInitiatedBidirectionalId(0), QUIC_RST_ACKNOWLEDGEMENT)); } - visitor_->OnRstStream(rst); + session_->OnRstStream(rst); // For version-99 will create and receive a stop-sending, completing // the full-close expected by this test. @@ -340,8 +340,8 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { QuicStringPiece("TP")); QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2, QuicStringPiece("TP")); - visitor_->OnStreamFrame(frame3); - visitor_->OnStreamFrame(frame4); + session_->OnStreamFrame(frame3); + session_->OnStreamFrame(frame4); // The stream should never be opened, now that the reset is received. EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); EXPECT_TRUE(connection_->connected()); @@ -570,8 +570,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { SerializedPacket packet( QuicPacketNumber(1) + kMinPacketsBetweenServerConfigUpdates, PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false, false); - sent_packet_manager->OnPacketSent(&packet, QuicPacketNumber(), now, - NOT_RETRANSMISSION, + sent_packet_manager->OnPacketSent(&packet, now, NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); // Verify that the proto has exactly the values we expect. 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 c6f99ff9f61..da3336d26a0 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 @@ -53,6 +53,9 @@ 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 (!GetQuicReloadableFlag(quic_use_common_stream_check) && !VersionHasIetfQuicFrames(transport_version())) { if (GetNumOpenOutgoingStreams() >= @@ -61,14 +64,14 @@ bool QuicSpdyClientSession::ShouldCreateOutgoingBidirectionalStream() { << "Already " << GetNumOpenOutgoingStreams() << " open."; return false; } - 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; } return true; } - 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; @@ -132,7 +135,10 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) { QUIC_BUG << "ShouldCreateIncomingStream called when disconnected"; return false; } - if (goaway_received() && respect_goaway_) { + bool goaway_received = quic::VersionUsesHttp3(transport_version()) + ? http3_goaway_received() + : QuicSession::goaway_received(); + 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.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h index 3611c69bcf0..b3def0aca29 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h @@ -20,7 +20,7 @@ namespace quic { class QuicConnection; class QuicServerId; -class QuicSpdyClientSession : public QuicSpdyClientSessionBase { +class QUIC_NO_EXPORT QuicSpdyClientSession : public QuicSpdyClientSessionBase { public: // Takes ownership of |connection|. Caller retains ownership of // |promised_by_url|. 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 aef68c8ff8f..7dd2aec34e7 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 @@ -39,15 +39,6 @@ void QuicSpdyClientSessionBase::OnConfigNegotiated() { QuicSpdySession::OnConfigNegotiated(); } -void QuicSpdyClientSessionBase::OnCryptoHandshakeEvent( - CryptoHandshakeEvent event) { - QuicSpdySession::OnCryptoHandshakeEvent(event); - if (event == HANDSHAKE_CONFIRMED && max_allowed_push_id() > 0 && - VersionUsesHttp3(transport_version())) { - SendMaxPushId(); - } -} - void QuicSpdyClientSessionBase::OnInitialHeadersComplete( QuicStreamId stream_id, const SpdyHeaderBlock& response_headers) { 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 aec5e75947f..3ca3499e8c7 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 @@ -50,9 +50,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase void OnConfigNegotiated() override; - // Override base class to set FEC policy before any data is sent by client. - void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; - // Called by |headers_stream_| when push promise headers have been // completely received. void OnPromiseHeaderList(QuicStreamId stream_id, 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 59634f8ef69..7c4d914da98 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 @@ -32,6 +32,7 @@ using spdy::SpdyHeaderBlock; using testing::_; using testing::AnyNumber; +using testing::AtLeast; using testing::AtMost; using testing::Invoke; using testing::Truly; @@ -106,7 +107,6 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam { session_->Initialize(); push_promise_[":path"] = "/bar"; push_promise_[":authority"] = "www.google.com"; - push_promise_[":version"] = "HTTP/1.1"; push_promise_[":method"] = "GET"; push_promise_[":scheme"] = "https"; promise_url_ = @@ -165,9 +165,11 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam { config.SetMaxIncomingBidirectionalStreamsToSend( server_max_incoming_streams); } + std::unique_ptr crypto_config = + crypto_test_utils::CryptoServerConfigForTesting(); crypto_test_utils::HandshakeWithFakeServer( - &config, &helper_, &alarm_factory_, connection_, stream, - AlpnForVersion(connection_->version())); + &config, crypto_config.get(), &helper_, &alarm_factory_, connection_, + stream, AlpnForVersion(connection_->version())); } QuicCryptoClientConfig crypto_config_; @@ -244,8 +246,6 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) { // TODO(nharper): Add support for Transport Parameters in the TLS handshake. return; } - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AnyNumber()); - EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(AnyNumber()); uint32_t kServerMaxIncomingStreams = 1; CompleteCryptoHandshake(kServerMaxIncomingStreams); @@ -276,8 +276,6 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) { // TODO(nharper): Add support for Transport Parameters in the TLS handshake. return; } - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AnyNumber()); - EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(AnyNumber()); uint32_t kServerMaxIncomingStreams = 1; CompleteCryptoHandshake(kServerMaxIncomingStreams); @@ -345,7 +343,9 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { QuicStreamId stream_id = stream->id(); - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1); session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); @@ -395,7 +395,9 @@ TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) { // Send the RST, which results in the stream being closed locally (but some // state remains while the client waits for a response from the server). QuicStreamId stream_id = stream->id(); - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1); session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); @@ -532,14 +534,15 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) { // A packet with invalid framing should cause a connection to be closed. TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { + const ParsedQuicVersion version = GetParam(); + if (version.handshake_protocol == PROTOCOL_TLS1_3) { // TODO(nharper, b/112643533): Figure out why this test fails when TLS is // enabled and fix it. return; } QuicSocketAddress server_address(TestPeerIPAddress(), kTestPort); QuicSocketAddress client_address(TestPeerIPAddress(), kTestPort); - if (GetParam().KnowsWhichDecrypterToUse()) { + if (version.KnowsWhichDecrypterToUse()) { connection_->InstallDecrypter( ENCRYPTION_FORWARD_SECURE, std::make_unique(Perspective::IS_CLIENT)); @@ -560,10 +563,9 @@ TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { QuicConnectionId source_connection_id = EmptyQuicConnectionId(); QuicFramerPeer::SetLastSerializedServerConnectionId( QuicConnectionPeer::GetFramer(connection_), destination_connection_id); - ParsedQuicVersionVector versions = {GetParam()}; bool version_flag = false; QuicConnectionIdIncluded scid_included = CONNECTION_ID_ABSENT; - if (VersionHasIetfInvariantHeader(GetParam().transport_version)) { + if (VersionHasIetfInvariantHeader(version.transport_version)) { version_flag = true; source_connection_id = destination_connection_id; scid_included = CONNECTION_ID_PRESENT; @@ -571,7 +573,7 @@ TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { std::unique_ptr packet(ConstructMisFramedEncryptedPacket( destination_connection_id, source_connection_id, version_flag, false, 100, "data", CONNECTION_ID_ABSENT, scid_included, PACKET_4BYTE_PACKET_NUMBER, - &versions, Perspective::IS_SERVER)); + version, Perspective::IS_SERVER)); std::unique_ptr received( ConstructReceivedPacket(*packet, QuicTime::Zero())); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); @@ -618,7 +620,6 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseStreamIdTooHigh) { headers.OnHeaderBlockStart(); headers.OnHeader(":path", "/bar"); headers.OnHeader(":authority", "www.google.com"); - headers.OnHeader(":version", "HTTP/1.1"); headers.OnHeader(":method", "GET"); headers.OnHeader(":scheme", "https"); headers.OnHeaderBlockEnd(0, 0); @@ -924,7 +925,6 @@ TEST_P(QuicSpdyClientSessionTest, TooManyPushPromises) { headers.OnHeaderBlockStart(); headers.OnHeader(":path", QuicStrCat("/", promise_count)); headers.OnHeader(":authority", "www.google.com"); - headers.OnHeader(":version", "HTTP/1.1"); headers.OnHeader(":method", "GET"); headers.OnHeader(":scheme", "https"); headers.OnHeaderBlockEnd(0, 0); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h index 9c94b700936..5cd27d4a6b8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h @@ -19,7 +19,7 @@ class QuicSpdyClientSession; // All this does right now is send an SPDY request, and aggregate the // SPDY response. -class QuicSpdyClientStream : public QuicSpdyStream { +class QUIC_NO_EXPORT QuicSpdyClientStream : public QuicSpdyStream { public: QuicSpdyClientStream(QuicStreamId id, QuicSpdyClientSession* session, 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 84a207ad26c..dd1cadebbd8 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 @@ -96,7 +96,6 @@ class QuicSpdyClientStreamTest : public QuicTestWithParam { std::unique_ptr stream_visitor_; SpdyHeaderBlock headers_; std::string body_; - HttpEncoder encoder_; }; INSTANTIATE_TEST_SUITE_P(Tests, @@ -113,7 +112,8 @@ TEST_P(QuicSpdyClientStreamTest, TestReceivingIllegalResponseStatusCode) { auto headers = AsHeaderList(headers_); stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), headers); - EXPECT_EQ(QUIC_BAD_APPLICATION_PAYLOAD, stream_->stream_error()); + EXPECT_THAT(stream_->stream_error(), + IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD)); } TEST_P(QuicSpdyClientStreamTest, TestFraming) { @@ -122,7 +122,7 @@ TEST_P(QuicSpdyClientStreamTest, TestFraming) { headers); std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body_.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = VersionUsesHttp3(connection_->transport_version()) ? header + body_ @@ -153,7 +153,7 @@ TEST_P(QuicSpdyClientStreamTest, TestFramingOnePacket) { headers); std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body_.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = VersionUsesHttp3(connection_->transport_version()) ? header + body_ @@ -173,12 +173,12 @@ TEST_P(QuicSpdyClientStreamTest, stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), headers); // The headers should parse successfully. - EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); EXPECT_EQ("200", stream_->response_headers().find(":status")->second); EXPECT_EQ(200, stream_->response_code()); std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(large_body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(large_body.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = VersionUsesHttp3(connection_->transport_version()) ? header + large_body @@ -222,7 +222,7 @@ TEST_P(QuicSpdyClientStreamTest, ReceivingTrailers) { // received, as well as all data. std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body_.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = VersionUsesHttp3(connection_->transport_version()) ? header + body_ diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h index ad0d32699f0..b66b459d021 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h @@ -9,7 +9,7 @@ namespace quic { -class QuicSpdyServerStreamBase : public QuicSpdyStream { +class QUIC_NO_EXPORT QuicSpdyServerStreamBase : public QuicSpdyStream { public: QuicSpdyServerStreamBase(QuicStreamId id, QuicSpdySession* session, 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 1888e033f25..1a8eef2935f 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 @@ -31,6 +31,7 @@ class QuicSpdyServerStreamBaseTest : public QuicTest { : session_(new MockQuicConnection(&helper_, &alarm_factory_, Perspective::IS_SERVER)) { + session_.Initialize(); stream_ = new TestQuicSpdyServerStream(GetNthClientInitiatedBidirectionalStreamId( session_.transport_version(), 0), 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 c876e3d1a93..3a3441bc416 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 @@ -11,6 +11,8 @@ #include "net/third_party/quiche/src/quic/core/http/http_constants.h" #include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.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" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" @@ -44,7 +46,6 @@ using spdy::SpdyPriorityIR; using spdy::SpdyPushPromiseIR; using spdy::SpdySerializedFrame; using spdy::SpdySettingsId; -using spdy::SpdySettingsIR; using spdy::SpdyStreamId; namespace quic { @@ -245,11 +246,6 @@ class QuicSpdySession::SpdyFramerVisitor int weight, bool exclusive) override { DCHECK(!VersionUsesHttp3(session_->transport_version())); - if (session_->transport_version() <= QUIC_VERSION_39) { - CloseConnection("SPDY PRIORITY frame received.", - QUIC_INVALID_HEADERS_STREAM_DATA); - return; - } if (!session_->IsConnected()) { return; } @@ -303,7 +299,6 @@ class QuicSpdySession::SpdyFramerVisitor } } - private: QuicSpdySession* session_; QuicHeaderList header_list_; }; @@ -352,7 +347,10 @@ QuicSpdySession::QuicSpdySession( spdy_framer_visitor_(new SpdyFramerVisitor(this)), max_allowed_push_id_(0), destruction_indicator_(123456789), - debug_visitor_(nullptr) { + debug_visitor_(nullptr), + http3_goaway_received_(false), + http3_goaway_sent_(false), + http3_max_push_id_sent_(false) { 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()); @@ -416,18 +414,16 @@ void QuicSpdySession::Initialize() { void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) { DCHECK(VersionUsesHttp3(transport_version())); - // TODO(b/124216424): Use HTTP_QPACK_DECODER_STREAM_ERROR. CloseConnectionWithDetails( - QUIC_DECOMPRESSION_FAILURE, + QUIC_QPACK_DECODER_STREAM_ERROR, QuicStrCat("Decoder stream error: ", error_message)); } void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) { DCHECK(VersionUsesHttp3(transport_version())); - // TODO(b/124216424): Use HTTP_QPACK_ENCODER_STREAM_ERROR. CloseConnectionWithDetails( - QUIC_DECOMPRESSION_FAILURE, + QUIC_QPACK_ENCODER_STREAM_ERROR, QuicStrCat("Encoder stream error: ", error_message)); } @@ -520,9 +516,6 @@ size_t QuicSpdySession::WritePriority(QuicStreamId id, int weight, bool exclusive) { DCHECK(!VersionUsesHttp3(transport_version())); - if (transport_version() <= QUIC_VERSION_39) { - return 0; - } SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive); SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame)); headers_stream()->WriteOrBufferData( @@ -537,10 +530,29 @@ void QuicSpdySession::WriteH3Priority(const PriorityFrame& priority) { << "Server must not send priority"; QuicConnection::ScopedPacketFlusher flusher(connection()); - SendInitialData(); send_control_stream_->WritePriority(priority); } +void QuicSpdySession::OnHttp3GoAway(QuicStreamId stream_id) { + DCHECK_EQ(perspective(), Perspective::IS_CLIENT); + if (!QuicUtils::IsBidirectionalStreamId(stream_id) || + IsIncomingStream(stream_id)) { + CloseConnectionWithDetails( + QUIC_INVALID_STREAM_ID, + "GOAWAY's last stream id has to point to a request stream"); + return; + } + http3_goaway_received_ = true; +} + +void QuicSpdySession::SendHttp3GoAway() { + DCHECK_EQ(perspective(), Perspective::IS_SERVER); + DCHECK(VersionUsesHttp3(transport_version())); + http3_goaway_sent_ = true; + send_control_stream_->SendGoAway( + GetLargestPeerCreatedStreamId(/*unidirectional = */ false)); +} + void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id, QuicStreamId promised_stream_id, SpdyHeaderBlock headers) { @@ -580,27 +592,18 @@ void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id, } void QuicSpdySession::SendInitialData() { - if (VersionUsesHttp3(transport_version())) { - QuicConnection::ScopedPacketFlusher flusher(connection()); - send_control_stream_->MaybeSendSettingsFrame(); - // TODO(renjietang): Remove this once stream id manager can take dynamically - // created HTTP/3 unidirectional streams. - qpack_encoder_send_stream_->MaybeSendStreamType(); - qpack_decoder_send_stream_->MaybeSendStreamType(); + if (!VersionUsesHttp3(transport_version())) { return; } - if (GetQuicReloadableFlag(quic_do_not_send_settings)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_do_not_send_settings); - return; + QuicConnection::ScopedPacketFlusher flusher(connection()); + send_control_stream_->MaybeSendSettingsFrame(); + if (GetQuicReloadableFlag(quic_send_max_push_id_with_settings) && + perspective() == Perspective::IS_CLIENT && !http3_max_push_id_sent_) { + SendMaxPushId(); + http3_max_push_id_sent_ = true; } - - SpdySettingsIR settings_frame; - settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, - max_inbound_header_list_size_); - - SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame)); - headers_stream()->WriteOrBufferData( - QuicStringPiece(frame.data(), frame.size()), false, nullptr); + qpack_decoder_send_stream_->MaybeSendStreamType(); + qpack_encoder_send_stream_->MaybeSendStreamType(); } QpackEncoder* QuicSpdySession::qpack_encoder() { @@ -630,19 +633,20 @@ QuicSpdyStream* QuicSpdySession::GetSpdyDataStream( void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { QuicSession::OnCryptoHandshakeEvent(event); - if (VersionUsesHttp3(transport_version()) || - (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize())) { - SendInitialData(); - } + SendInitialData(); +} + +void QuicSpdySession::SetDefaultEncryptionLevel(quic::EncryptionLevel level) { + QuicSession::SetDefaultEncryptionLevel(level); + SendInitialData(); } // True if there are open HTTP requests. bool QuicSpdySession::ShouldKeepConnectionAlive() const { - if (GetQuicReloadableFlag(quic_aggressive_connection_aliveness)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_aggressive_connection_aliveness); - return GetNumActiveStreams() > 0; + if (!VersionUsesHttp3(transport_version())) { + DCHECK(pending_streams().empty()); } - return GetNumOpenDynamicStreams() > 0; + return GetNumActiveStreams() + pending_streams().size() > 0; } bool QuicSpdySession::UsesPendingStreams() const { @@ -1035,9 +1039,8 @@ void QuicSpdySession::SetMaxAllowedPushId(QuicStreamId max_allowed_push_id) { } DCHECK(perspective() == Perspective::IS_CLIENT); - if (IsHandshakeConfirmed()) { + if (IsCryptoHandshakeConfirmed()) { SendMaxPushId(); - send_control_stream_->SendMaxPushIdFrame(max_allowed_push_id_); } } 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 0eb3751e679..575d6641a61 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 @@ -21,7 +21,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -153,6 +152,13 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // Writes a HTTP/3 PRIORITY frame to the peer. void WriteH3Priority(const PriorityFrame& priority); + // Process received HTTP/3 GOAWAY frame. This method should only be called on + // the client side. + virtual void OnHttp3GoAway(QuicStreamId stream_id); + + // Write the GOAWAY |frame| on control stream. + void SendHttp3GoAway(); + // Write |headers| for |promised_stream_id| on |original_stream_id| in a // PUSH_PROMISE frame to peer. virtual void WritePushPromise(QuicStreamId original_stream_id, @@ -237,6 +243,10 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession Http3DebugVisitor* debug_visitor() { return debug_visitor_; } + bool http3_goaway_received() const { return http3_goaway_received_; } + + bool http3_goaway_sent() const { return http3_goaway_sent_; } + // Log header compression ratio histogram. // |using_qpack| is true for QPACK, false for HPACK. // |is_sent| is true for sent headers, false for received ones. @@ -255,6 +265,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession QuicByteCount compressed, QuicByteCount uncompressed); + // True if any dynamic table entries have been referenced from either a sent + // or received header block. Used for stats. + bool dynamic_table_entry_referenced() const { + return (qpack_encoder_ && + qpack_encoder_->dynamic_table_entry_referenced()) || + (qpack_decoder_ && qpack_decoder_->dynamic_table_entry_referenced()); + } + protected: // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to @@ -295,6 +313,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession QuicReferenceCountedPointer ack_listener); void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override; bool supports_push_promise() { return supports_push_promise_; } @@ -416,6 +435,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // Not owned by the session. Http3DebugVisitor* debug_visitor_; + + // If the endpoint has received HTTP/3 GOAWAY frame. + bool http3_goaway_received_; + // If the endpoint has sent HTTP/3 GOAWAY frame. + bool http3_goaway_sent_; + + // If the sendpoint has sent the initial HTTP/3 MAX_PUSH_ID frame. + bool http3_max_push_id_sent_; }; } // 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 85e79a7a987..b37246acd23 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 @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" #include "net/third_party/quiche/src/quic/core/http/http_constants.h" +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" @@ -29,8 +30,9 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h" @@ -39,6 +41,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/spdy/core/spdy_framer.h" using spdy::kV3HighestPriority; @@ -95,11 +98,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); } - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); session()->OnConfigNegotiated(); - session()->connection()->SetDefaultEncryptionLevel( - ENCRYPTION_FORWARD_SECURE); - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + if (session()->use_handshake_delegate()) { + session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + } else { + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + } } // QuicCryptoStream implementation @@ -114,6 +122,7 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { CryptoMessageParser* crypto_message_parser() override { return QuicCryptoHandshaker::crypto_message_parser(); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} MOCK_METHOD0(OnCanWrite, void()); @@ -296,6 +305,7 @@ class TestSession : public QuicSpdySession { } using QuicSession::closed_streams; + using QuicSession::ShouldKeepConnectionAlive; using QuicSession::zombie_streams; using QuicSpdySession::ProcessPendingStream; using QuicSpdySession::UsesPendingStreams; @@ -350,10 +360,9 @@ class QuicSpdySessionTestBase : public QuicTestWithParam { void CheckClosedStreams() { QuicStreamId first_stream_id = QuicUtils::GetFirstBidirectionalStreamId( - connection_->transport_version(), Perspective::IS_CLIENT); - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { - first_stream_id = - QuicUtils::GetCryptoStreamId(connection_->transport_version()); + transport_version(), Perspective::IS_CLIENT); + if (!QuicVersionUsesCryptoFrames(transport_version())) { + first_stream_id = QuicUtils::GetCryptoStreamId(transport_version()); } for (QuicStreamId i = first_stream_id; i < 100; i++) { if (!QuicContainsKey(closed_streams_, i)) { @@ -388,18 +397,16 @@ class QuicSpdySessionTestBase : public QuicTestWithParam { } QuicStreamId GetNthServerInitiatedBidirectionalId(int n) { - return GetNthServerInitiatedBidirectionalStreamId( - connection_->transport_version(), n); + return GetNthServerInitiatedBidirectionalStreamId(transport_version(), n); } QuicStreamId IdDelta() { - return QuicUtils::StreamIdDelta(connection_->transport_version()); + return QuicUtils::StreamIdDelta(transport_version()); } std::string EncodeSettings(const SettingsFrame& settings) { - HttpEncoder encoder; std::unique_ptr buffer; - auto header_length = encoder.SerializeSettingsFrame(settings, &buffer); + auto header_length = HttpEncoder::SerializeSettingsFrame(settings, &buffer); return std::string(buffer.get(), header_length); } @@ -456,8 +463,7 @@ TEST_P(QuicSpdySessionTestServer, SelfAddress) { } TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) { - if (!GetQuicReloadableFlag(quic_do_not_send_settings) || - VersionUsesHttp3(transport_version())) { + if (VersionUsesHttp3(transport_version())) { MockPacketWriter* writer = static_cast( QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) @@ -473,10 +479,9 @@ TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) { TEST_P(QuicSpdySessionTestServer, IsClosedStreamDefault) { // Ensure that no streams are initially closed. QuicStreamId first_stream_id = QuicUtils::GetFirstBidirectionalStreamId( - connection_->transport_version(), Perspective::IS_CLIENT); - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { - first_stream_id = - QuicUtils::GetCryptoStreamId(connection_->transport_version()); + transport_version(), Perspective::IS_CLIENT); + if (!QuicVersionUsesCryptoFrames(transport_version())) { + first_stream_id = QuicUtils::GetCryptoStreamId(transport_version()); } for (QuicStreamId i = first_stream_id; i < 100; i++) { EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i; @@ -850,7 +855,7 @@ TEST_P(QuicSpdySessionTestServer, BufferedHandshake) { // This tests prioritization of the crypto stream when flow control limits are // reached. When CRYPTO frames are in use, there is no flow control for the // crypto handshake, so this test is irrelevant. - if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + if (QuicVersionUsesCryptoFrames(transport_version())) { return; } session_.set_writev_consumes_all_data(true); @@ -867,7 +872,7 @@ TEST_P(QuicSpdySessionTestServer, BufferedHandshake) { // Blocking (due to buffering of) the Crypto stream is detected. session_.MarkConnectionLevelWriteBlocked( - QuicUtils::GetCryptoStreamId(connection_->transport_version())); + QuicUtils::GetCryptoStreamId(transport_version())); EXPECT_TRUE(session_.HasPendingHandshake()); TestStream* stream4 = session_.CreateOutgoingBidirectionalStream(); @@ -940,9 +945,9 @@ TEST_P(QuicSpdySessionTestServer, // Mark the crypto and headers streams as write blocked, we expect them to be // allowed to write later. - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + if (!QuicVersionUsesCryptoFrames(transport_version())) { session_.MarkConnectionLevelWriteBlocked( - QuicUtils::GetCryptoStreamId(connection_->transport_version())); + QuicUtils::GetCryptoStreamId(transport_version())); } // Create a data stream, and although it is write blocked we never expect it @@ -953,18 +958,18 @@ TEST_P(QuicSpdySessionTestServer, // The crypto and headers streams should be called even though we are // connection flow control blocked. - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + if (!QuicVersionUsesCryptoFrames(transport_version())) { TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); EXPECT_CALL(*crypto_stream, OnCanWrite()); } - if (!VersionUsesHttp3(connection_->transport_version())) { + if (!VersionUsesHttp3(transport_version())) { TestHeadersStream* headers_stream; QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); headers_stream = new TestHeadersStream(&session_); QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); session_.MarkConnectionLevelWriteBlocked( - QuicUtils::GetHeadersStreamId(connection_->transport_version())); + QuicUtils::GetHeadersStreamId(transport_version())); EXPECT_CALL(*headers_stream, OnCanWrite()); } @@ -978,7 +983,7 @@ TEST_P(QuicSpdySessionTestServer, TEST_P(QuicSpdySessionTestServer, SendGoAway) { if (VersionHasIetfQuicFrames(transport_version())) { - // GoAway frames are not in version 99 + // HTTP/3 GOAWAY has different semantic and thus has its own test. return; } connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); @@ -1001,10 +1006,24 @@ TEST_P(QuicSpdySessionTestServer, SendGoAway) { EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId)); } +TEST_P(QuicSpdySessionTestServer, SendHttp3GoAway) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + + session_.SendHttp3GoAway(); + EXPECT_TRUE(session_.http3_goaway_sent()); + + const QuicStreamId kTestStreamId = + GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0); + EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, _)).Times(0); + EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId)); +} + TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) { if (VersionHasIetfQuicFrames(transport_version())) { - // TODO(b/118808809): Enable this test for version 99 when GOAWAY is - // supported. + // HTTP/3 GOAWAY doesn't have such restriction. return; } EXPECT_CALL(*connection_, SendControlFrame(_)) @@ -1016,8 +1035,7 @@ TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) { TEST_P(QuicSpdySessionTestServer, InvalidGoAway) { if (VersionHasIetfQuicFrames(transport_version())) { - // TODO(b/118808809): Enable this test for version 99 when GOAWAY is - // supported. + // HTTP/3 GOAWAY has different semantics and thus has its own test. return; } QuicGoAwayFrame go_away(kInvalidControlFrameId, QUIC_PEER_GOING_AWAY, @@ -1049,8 +1067,7 @@ TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) { } TEST_P(QuicSpdySessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { - if (!GetQuicReloadableFlag(quic_do_not_send_settings) || - VersionUsesHttp3(transport_version())) { + if (VersionUsesHttp3(transport_version())) { MockPacketWriter* writer = static_cast( QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) @@ -1115,7 +1132,7 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameFinStaticStreamId) { QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1)); session_.OnStreamFrame(data1); } else { - id = QuicUtils::GetHeadersStreamId(connection_->transport_version()); + id = QuicUtils::GetHeadersStreamId(transport_version()); } // Send two bytes of payload. @@ -1137,7 +1154,7 @@ TEST_P(QuicSpdySessionTestServer, OnRstStreamStaticStreamId) { QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1)); session_.OnStreamFrame(data1); } else { - id = QuicUtils::GetHeadersStreamId(connection_->transport_version()); + id = QuicUtils::GetHeadersStreamId(transport_version()); } // Send two bytes of payload. @@ -1152,9 +1169,8 @@ TEST_P(QuicSpdySessionTestServer, OnRstStreamStaticStreamId) { TEST_P(QuicSpdySessionTestServer, OnStreamFrameInvalidStreamId) { // Send two bytes of payload. - QuicStreamFrame data1( - QuicUtils::GetInvalidStreamId(connection_->transport_version()), true, 0, - QuicStringPiece("HT")); + QuicStreamFrame data1(QuicUtils::GetInvalidStreamId(transport_version()), + true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, CloseConnection( QUIC_INVALID_STREAM_ID, "Received data for an invalid stream", @@ -1164,10 +1180,9 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameInvalidStreamId) { TEST_P(QuicSpdySessionTestServer, OnRstStreamInvalidStreamId) { // Send two bytes of payload. - QuicRstStreamFrame rst1( - kInvalidControlFrameId, - QuicUtils::GetInvalidStreamId(connection_->transport_version()), - QUIC_ERROR_PROCESSING_STREAM, 0); + QuicRstStreamFrame rst1(kInvalidControlFrameId, + QuicUtils::GetInvalidStreamId(transport_version()), + QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(*connection_, CloseConnection( QUIC_INVALID_STREAM_ID, "Received data for an invalid stream", @@ -1213,7 +1228,7 @@ TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { - if (QuicVersionUsesCryptoFrames(GetParam().transport_version)) { + if (QuicVersionUsesCryptoFrames(transport_version())) { // QUIC version 47 onwards uses CRYPTO frames for the handshake, so this // test doesn't make sense for those versions. return; @@ -1230,13 +1245,8 @@ TEST_P(QuicSpdySessionTestServer, EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); - if (VersionHasIetfQuicFrames(transport_version())) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&ClearControlFrame)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&ClearControlFrame)); for (QuicStreamId i = 0; !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) { EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); @@ -1247,7 +1257,7 @@ TEST_P(QuicSpdySessionTestServer, config.ToHandshakeMessage(&crypto_message, transport_version()); crypto_stream->SendHandshakeMessage(crypto_message); char buf[1000]; - QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); + QuicDataWriter writer(1000, buf, quiche::NETWORK_BYTE_ORDER); crypto_stream->WriteStreamData(offset, crypto_message.size(), &writer); } EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked()); @@ -1262,8 +1272,7 @@ TEST_P(QuicSpdySessionTestServer, CryptoHandshakeMessage msg; session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); EXPECT_TRUE(QuicSessionPeer::IsStreamWriteBlocked( - &session_, - QuicUtils::GetCryptoStreamId(connection_->transport_version()))); + &session_, QuicUtils::GetCryptoStreamId(transport_version()))); // Stream is now unblocked and will no longer have buffered data. EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); @@ -1280,7 +1289,7 @@ TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedHeadersStream) { // This test depends on stream-level flow control for the crypto stream, which // doesn't exist when CRYPTO frames are used. - if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + if (QuicVersionUsesCryptoFrames(transport_version())) { return; } @@ -1341,8 +1350,7 @@ TEST_P(QuicSpdySessionTestServer, EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); EXPECT_TRUE(headers_stream->HasBufferedData()); EXPECT_TRUE(QuicSessionPeer::IsStreamWriteBlocked( - &session_, - QuicUtils::GetHeadersStreamId(connection_->transport_version()))); + &session_, QuicUtils::GetHeadersStreamId(transport_version()))); } #endif // !defined(OS_IOS) @@ -1566,7 +1574,7 @@ TEST_P(QuicSpdySessionTestServer, FlowControlWithInvalidFinalOffset) { } TEST_P(QuicSpdySessionTestServer, WindowUpdateUnblocksHeadersStream) { - if (VersionUsesHttp3(GetParam().transport_version)) { + if (VersionUsesHttp3(transport_version())) { // The test relies on headers stream, which no longer exists in IETF QUIC. return; } @@ -1620,8 +1628,7 @@ TEST_P(QuicSpdySessionTestServer, GetNthClientInitiatedBidirectionalId(kMaxStreams); // Create kMaxStreams data streams, and close them all without receiving a // FIN or a RST_STREAM from the client. - const QuicStreamId kNextId = - QuicUtils::StreamIdDelta(connection_->transport_version()); + const QuicStreamId kNextId = QuicUtils::StreamIdDelta(transport_version()); for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += kNextId) { QuicStreamFrame data1(i, false, 0, QuicStringPiece("HT")); session_.OnStreamFrame(data1); @@ -1738,6 +1745,21 @@ TEST_P(QuicSpdySessionTestClient, BadStreamFramePendingStream) { session_.OnStreamFrame(data1); } +TEST_P(QuicSpdySessionTestClient, PendingStreamKeepsConnectionAlive) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + + QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), Perspective::IS_SERVER); + + QuicStreamFrame frame(stream_id, false, 1, "test"); + EXPECT_FALSE(session_.ShouldKeepConnectionAlive()); + session_.OnStreamFrame(frame); + EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id)); + EXPECT_TRUE(session_.ShouldKeepConnectionAlive()); +} + TEST_P(QuicSpdySessionTestClient, AvailableStreamsClient) { ASSERT_TRUE(session_.GetOrCreateStream( GetNthServerInitiatedBidirectionalId(2)) != nullptr); @@ -1838,21 +1860,17 @@ TEST_P(QuicSpdySessionTestClient, WritePriority) { QuicStreamSendBuffer& send_buffer = QuicStreamPeer::SendBuffer(headers_stream); - if (transport_version() > QUIC_VERSION_39) { - ASSERT_EQ(1u, send_buffer.size()); - - SpdyPriorityIR priority_frame( - id, parent_stream_id, Spdy3PriorityToHttp2Weight(priority), exclusive); - SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION); - SpdySerializedFrame frame = spdy_framer.SerializeFrame(priority_frame); - - const QuicMemSlice& slice = - QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer)->slice; - EXPECT_EQ(QuicStringPiece(frame.data(), frame.size()), - QuicStringPiece(slice.data(), slice.length())); - } else { - EXPECT_EQ(0u, send_buffer.size()); - } + ASSERT_EQ(1u, send_buffer.size()); + + SpdyPriorityIR priority_frame( + id, parent_stream_id, Spdy3PriorityToHttp2Weight(priority), exclusive); + SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION); + SpdySerializedFrame frame = spdy_framer.SerializeFrame(priority_frame); + + const QuicMemSlice& slice = + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer)->slice; + EXPECT_EQ(QuicStringPiece(frame.data(), frame.size()), + QuicStringPiece(slice.data(), slice.length())); } TEST_P(QuicSpdySessionTestClient, Http3ServerPush) { @@ -1936,7 +1954,6 @@ TEST_P(QuicSpdySessionTestServer, ZombieStreams) { } TEST_P(QuicSpdySessionTestServer, OnStreamFrameLost) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); InSequence s; // Drive congestion control manually. @@ -1952,16 +1969,15 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameLost) { // Lost data on cryption stream, streams 2 and 4. EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + if (!QuicVersionUsesCryptoFrames(transport_version())) { EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) .WillOnce(Return(true)); } EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); session_.OnFrameLost(QuicFrame(frame3)); - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { - QuicStreamFrame frame1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, - 0, 1300); + if (!QuicVersionUsesCryptoFrames(transport_version())) { + QuicStreamFrame frame1(QuicUtils::GetCryptoStreamId(transport_version()), + false, 0, 1300); session_.OnFrameLost(QuicFrame(frame1)); } else { QuicCryptoFrame crypto_frame(ENCRYPTION_INITIAL, 0, 1300); @@ -1978,7 +1994,7 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameLost) { // stream go first. // Do not check congestion window when crypto stream has lost data. EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0); - if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + if (!QuicVersionUsesCryptoFrames(transport_version())) { EXPECT_CALL(*crypto_stream, OnCanWrite()); EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) .WillOnce(Return(false)); @@ -2010,7 +2026,14 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameLost) { } TEST_P(QuicSpdySessionTestServer, DonotRetransmitDataOfClosedStreams) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); + // Resetting a stream will send a QPACK Stream Cancellation instruction on the + // decoder stream. For simplicity, ignore writes on this stream. + NoopQpackStreamSenderDelegate qpack_stream_sender_delegate; + if (VersionUsesHttp3(transport_version())) { + session_.qpack_decoder()->set_qpack_stream_sender_delegate( + &qpack_stream_sender_delegate); + } + InSequence s; TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); @@ -2050,7 +2073,6 @@ TEST_P(QuicSpdySessionTestServer, DonotRetransmitDataOfClosedStreams) { } TEST_P(QuicSpdySessionTestServer, RetransmitFrames) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); MockSendAlgorithm* send_algorithm = new StrictMock; QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); InSequence s; @@ -2290,10 +2312,9 @@ TEST_P(QuicSpdySessionTestServer, StreamClosedWhileHeaderDecodingBlocked) { // HEADERS frame referencing first dynamic table entry. std::string headers_payload = QuicTextUtils::HexDecode("020080"); std::unique_ptr headers_buffer; - HttpEncoder encoder; QuicByteCount headers_frame_header_length = - encoder.SerializeHeadersFrameHeader(headers_payload.length(), - &headers_buffer); + HttpEncoder::SerializeHeadersFrameHeader(headers_payload.length(), + &headers_buffer); QuicStringPiece headers_frame_header(headers_buffer.get(), headers_frame_header_length); std::string headers = QuicStrCat(headers_frame_header, headers_payload); @@ -2325,10 +2346,9 @@ TEST_P(QuicSpdySessionTestServer, SessionDestroyedWhileHeaderDecodingBlocked) { // HEADERS frame referencing first dynamic table entry. std::string headers_payload = QuicTextUtils::HexDecode("020080"); std::unique_ptr headers_buffer; - HttpEncoder encoder; QuicByteCount headers_frame_header_length = - encoder.SerializeHeadersFrameHeader(headers_payload.length(), - &headers_buffer); + HttpEncoder::SerializeHeadersFrameHeader(headers_payload.length(), + &headers_buffer); QuicStringPiece headers_frame_header(headers_buffer.get(), headers_frame_header_length); std::string headers = QuicStrCat(headers_frame_header, headers_payload); @@ -2384,12 +2404,6 @@ TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) { QUIC_STREAM_CANCELLED, /* bytes_written = */ payload.size()); - // This will trigger the sending of two control frames: one RESET_STREAM with - // QUIC_RST_ACKNOWLEDGEMENT, and one STOP_SENDING. - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly(Invoke(&ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_RST_ACKNOWLEDGEMENT)); session_.OnRstStream(rst_frame); // The stream is closed. @@ -2457,12 +2471,6 @@ TEST_P(QuicSpdySessionTestClient, ResetInMiddleOfStreamType) { QUIC_STREAM_CANCELLED, /* bytes_written = */ payload.size()); - // This will trigger the sending of two control frames: one RESET_STREAM with - // QUIC_RST_ACKNOWLEDGEMENT, and one STOP_SENDING. - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly(Invoke(&ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_RST_ACKNOWLEDGEMENT)); session_.OnRstStream(rst_frame); // The stream is closed. @@ -2567,7 +2575,7 @@ TEST_P(QuicSpdySessionTestClient, EncoderStreamError) { EXPECT_CALL( *connection_, - CloseConnection(QUIC_DECOMPRESSION_FAILURE, + CloseConnection(QUIC_QPACK_ENCODER_STREAM_ERROR, "Encoder stream error: Invalid relative index.", _)); session_.OnStreamFrame(frame); } @@ -2588,11 +2596,25 @@ TEST_P(QuicSpdySessionTestClient, DecoderStreamError) { EXPECT_CALL( *connection_, - CloseConnection(QUIC_DECOMPRESSION_FAILURE, + CloseConnection(QUIC_QPACK_DECODER_STREAM_ERROR, "Decoder stream error: Invalid increment value 0.", _)); session_.OnStreamFrame(frame); } +TEST_P(QuicSpdySessionTestClient, InvalidHttp3GoAway) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + EXPECT_CALL( + *connection_, + CloseConnection( + QUIC_INVALID_STREAM_ID, + "GOAWAY's last stream id has to point to a request stream", _)); + QuicStreamId stream_id = + GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0); + session_.OnHttp3GoAway(stream_id); +} + } // 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 5dd9f3a832f..f7a13f62254 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 @@ -193,6 +193,7 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, visitor_(nullptr), blocked_on_decoding_headers_(false), headers_decompressed_(false), + header_list_size_limit_exceeded_(false), headers_payload_length_(0), trailers_payload_length_(0), trailers_decompressed_(false), @@ -227,6 +228,7 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending, visitor_(nullptr), blocked_on_decoding_headers_(false), headers_decompressed_(false), + header_list_size_limit_exceeded_(false), headers_payload_length_(0), trailers_payload_length_(0), trailers_decompressed_(false), @@ -297,7 +299,7 @@ void QuicSpdyStream::WriteOrBufferBody(QuicStringPiece data, bool fin) { // Write frame header. std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(data.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(data.length(), &buffer); unacked_frame_headers_offsets_.Add( send_buffer().stream_offset(), send_buffer().stream_offset() + header_length); @@ -310,7 +312,7 @@ void QuicSpdyStream::WriteOrBufferBody(QuicStringPiece data, bool fin) { // Write body. QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id() << " is writing DATA frame payload of length " - << data.length(); + << data.length() << " with fin " << fin; WriteOrBufferData(data, fin, nullptr); } @@ -358,7 +360,7 @@ void QuicSpdyStream::WritePushPromise(const PushPromiseFrame& frame) { DCHECK(VersionUsesHttp3(transport_version())); std::unique_ptr push_promise_frame_with_id; const size_t push_promise_frame_length = - encoder_.SerializePushPromiseFrameWithOnlyPushId( + HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( frame, &push_promise_frame_with_id); unacked_frame_headers_offsets_.Add(send_buffer().stream_offset(), @@ -401,7 +403,7 @@ QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices, std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(slices.total_length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(slices.total_length(), &buffer); if (!CanWriteNewDataAfterData(header_length)) { return {0, false}; } @@ -517,13 +519,13 @@ void QuicSpdyStream::OnStreamHeaderList(bool fin, size_t frame_len, const QuicHeaderList& header_list) { // TODO(b/134706391): remove |fin| argument. - // The headers list avoid infinite buffering by clearing the headers list - // if the current headers are too large. So if the list is empty here - // then the headers list must have been too large, and the stream should - // be reset. - // TODO(rch): Use an explicit "headers too large" signal. An empty header list - // might be acceptable if it corresponds to a trailing header frame. - if (header_list.empty()) { + // When using Google QUIC, an empty header list indicates that the size limit + // has been exceeded. + // When using IETF QUIC, there is an explicit signal from + // QpackDecodedHeadersAccumulator. + if ((VersionUsesHttp3(transport_version()) && + header_list_size_limit_exceeded_) || + (!VersionUsesHttp3(transport_version()) && header_list.empty())) { OnHeadersTooLarge(); if (IsDoneReading()) { return; @@ -537,26 +539,46 @@ void QuicSpdyStream::OnStreamHeaderList(bool fin, } void QuicSpdyStream::OnHeadersDecoded(QuicHeaderList headers) { - blocked_on_decoding_headers_ = false; - ProcessDecodedHeaders(headers); - // Continue decoding HTTP/3 frames. - OnDataAvailable(); + header_list_size_limit_exceeded_ = + qpack_decoded_headers_accumulator_->header_list_size_limit_exceeded(); + qpack_decoded_headers_accumulator_.reset(); + + QuicSpdySession::LogHeaderCompressionRatioHistogram( + /* using_qpack = */ true, + /* is_sent = */ false, headers.compressed_header_bytes(), + headers.uncompressed_header_bytes()); + + if (spdy_session_->promised_stream_id() == + QuicUtils::GetInvalidStreamId(session()->transport_version())) { + const QuicByteCount frame_length = headers_decompressed_ + ? trailers_payload_length_ + : headers_payload_length_; + OnStreamHeaderList(/* fin = */ false, frame_length, headers); + } else { + spdy_session_->OnHeaderList(headers); + } + + if (blocked_on_decoding_headers_) { + blocked_on_decoding_headers_ = false; + // Continue decoding HTTP/3 frames. + OnDataAvailable(); + } } -void QuicSpdyStream::OnHeaderDecodingError() { - // TODO(b/124216424): Use HTTP_EXCESSIVE_LOAD or - // HTTP_QPACK_DECOMPRESSION_FAILED error code as indicated by - // |qpack_decoded_headers_accumulator_|. - std::string error_message = QuicStrCat( - "Error during async decoding of ", - headers_decompressed_ ? "trailers" : "headers", " on stream ", id(), ": ", - qpack_decoded_headers_accumulator_->error_message()); - CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message); +void QuicSpdyStream::OnHeaderDecodingError(QuicStringPiece error_message) { + qpack_decoded_headers_accumulator_.reset(); + + std::string connection_close_error_message = QuicStrCat( + "Error decoding ", headers_decompressed_ ? "trailers" : "headers", + " on stream ", id(), ": ", error_message); + CloseConnectionWithDetails(QUIC_QPACK_DECOMPRESSION_FAILED, + connection_close_error_message); } void QuicSpdyStream::OnHeadersTooLarge() { if (VersionUsesHttp3(transport_version())) { - // TODO(124216424): Use HTTP_EXCESSIVE_LOAD error code. + // TODO(b/124216424): Reset stream with H3_REQUEST_CANCELLED (if client) + // or with H3_REQUEST_REJECTED (if server). std::string error_message = QuicStrCat("Too large headers received on stream ", id()); CloseConnectionWithDetails(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, @@ -658,9 +680,12 @@ void QuicSpdyStream::OnPriorityFrame( void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) { if (frame.error_code != QUIC_STREAM_NO_ERROR) { + // TODO(b/145684124) Call QpackDecoder::OnStreamReset(). + QuicStream::OnStreamReset(frame); return; } + QUIC_DVLOG(1) << ENDPOINT << "Received QUIC_STREAM_NO_ERROR, not discarding response"; set_rst_received(true); @@ -669,6 +694,12 @@ void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) { CloseWriteSide(); } +void QuicSpdyStream::Reset(QuicRstStreamErrorCode error) { + // TODO(b/145684124) Call QpackDecoder::OnStreamReset(). + + QuicStream::Reset(error); +} + void QuicSpdyStream::OnDataAvailable() { if (!VersionUsesHttp3(transport_version())) { // Sequencer must be blocked until headers are consumed. @@ -899,18 +930,14 @@ bool QuicSpdyStream::OnHeadersFramePayload(QuicStringPiece payload) { headers_payload_length_ += payload.length(); } - const bool success = qpack_decoded_headers_accumulator_->Decode(payload); + qpack_decoded_headers_accumulator_->Decode(payload); - sequencer()->MarkConsumed(body_manager_.OnNonBody(payload.size())); - - if (!success) { - // TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code. - std::string error_message = - QuicStrCat("Error decompressing header block on stream ", id(), ": ", - qpack_decoded_headers_accumulator_->error_message()); - CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message); + // |qpack_decoded_headers_accumulator_| is reset if an error is detected. + if (!qpack_decoded_headers_accumulator_) { return false; } + + sequencer()->MarkConsumed(body_manager_.OnNonBody(payload.size())); return true; } @@ -918,25 +945,15 @@ bool QuicSpdyStream::OnHeadersFrameEnd() { DCHECK(VersionUsesHttp3(transport_version())); DCHECK(qpack_decoded_headers_accumulator_); - auto result = qpack_decoded_headers_accumulator_->EndHeaderBlock(); + qpack_decoded_headers_accumulator_->EndHeaderBlock(); - if (result == QpackDecodedHeadersAccumulator::Status::kError) { - // TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code. - std::string error_message = - QuicStrCat("Error decompressing header block on stream ", id(), ": ", - qpack_decoded_headers_accumulator_->error_message()); - CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message); - return false; - } - - if (result == QpackDecodedHeadersAccumulator::Status::kBlocked) { + // If decoding is complete or an error is detected, then + // |qpack_decoded_headers_accumulator_| is already reset. + if (qpack_decoded_headers_accumulator_) { blocked_on_decoding_headers_ = true; return false; } - DCHECK(result == QpackDecodedHeadersAccumulator::Status::kSuccess); - - ProcessDecodedHeaders(qpack_decoded_headers_accumulator_->quic_header_list()); return !sequencer()->IsClosed() && !reading_stopped(); } @@ -999,24 +1016,6 @@ bool QuicSpdyStream::OnUnknownFrameEnd() { return true; } -void QuicSpdyStream::ProcessDecodedHeaders(const QuicHeaderList& headers) { - QuicSpdySession::LogHeaderCompressionRatioHistogram( - /* using_qpack = */ true, - /* is_sent = */ false, headers.compressed_header_bytes(), - headers.uncompressed_header_bytes()); - - if (spdy_session_->promised_stream_id() == - QuicUtils::GetInvalidStreamId(session()->transport_version())) { - const QuicByteCount frame_length = headers_decompressed_ - ? trailers_payload_length_ - : headers_payload_length_; - OnStreamHeaderList(/* fin = */ false, frame_length, headers); - } else { - spdy_session_->OnHeaderList(headers); - } - qpack_decoded_headers_accumulator_.reset(); -} - size_t QuicSpdyStream::WriteHeadersImpl( spdy::SpdyHeaderBlock header_block, bool fin, @@ -1044,8 +1043,8 @@ size_t QuicSpdyStream::WriteHeadersImpl( // Write HEADERS frame. std::unique_ptr headers_frame_header; const size_t headers_frame_header_length = - encoder_.SerializeHeadersFrameHeader(encoded_headers.size(), - &headers_frame_header); + HttpEncoder::SerializeHeadersFrameHeader(encoded_headers.size(), + &headers_frame_header); unacked_frame_headers_offsets_.Add( send_buffer().stream_offset(), send_buffer().stream_offset() + headers_frame_header_length); @@ -1059,7 +1058,7 @@ size_t QuicSpdyStream::WriteHeadersImpl( QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id() << " is writing HEADERS frame payload of length " - << encoded_headers.length(); + << encoded_headers.length() << " with fin " << fin; WriteOrBufferData(encoded_headers, fin, nullptr); QuicSpdySession::LogHeaderCompressionRatioHistogram( 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 6da102bd56c..8610dbb1f2d 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 @@ -102,6 +102,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream // QUIC_STREAM_NO_ERROR. void OnStreamReset(const QuicRstStreamFrame& frame) override; + void Reset(QuicRstStreamErrorCode error) override; + // Called by the sequencer when new data is available. Decodes the data and // calls OnBodyAvailable() to pass to the upper layer. void OnDataAvailable() override; @@ -211,11 +213,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream // will be available. bool IsClosed() { return sequencer()->IsClosed(); } - using QuicStream::CloseWriteSide; - // QpackDecodedHeadersAccumulator::Visitor implementation. void OnHeadersDecoded(QuicHeaderList headers) override; - void OnHeaderDecodingError() override; + void OnHeaderDecodingError(QuicStringPiece error_message) override; protected: // Called when the received headers are too large. By default this will @@ -267,9 +267,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream bool OnUnknownFramePayload(QuicStringPiece payload); bool OnUnknownFrameEnd(); - // Called internally when headers are decoded. - void ProcessDecodedHeaders(const QuicHeaderList& headers); - // Given the interval marked by [|offset|, |offset| + |data_length|), return // the number of frame header bytes contained in it. QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset, @@ -286,6 +283,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream bool blocked_on_decoding_headers_; // True if the headers have been completely decompressed. bool headers_decompressed_; + // True if uncompressed headers or trailers exceed maximum allowed size + // advertised to peer via SETTINGS_MAX_HEADER_LIST_SIZE. + bool header_list_size_limit_exceeded_; // Contains a copy of the decompressed header (name, value) pairs until they // are consumed via Readv. QuicHeaderList header_list_; @@ -305,8 +305,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream // The parsed trailers received from the peer. spdy::SpdyHeaderBlock received_trailers_; - // Http encoder for writing streams. - HttpEncoder encoder_; // Headers accumulator for decoding HEADERS frame payload. std::unique_ptr qpack_decoded_headers_accumulator_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h index 6b2dd62b02d..1942c261188 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h @@ -77,7 +77,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyManager { // A Fragment instance represents a body fragment with a count of bytes // received afterwards but before the next body fragment that can be marked // consumed as soon as all of the body fragment is read. - struct Fragment { + struct QUIC_EXPORT_PRIVATE Fragment { // |body| must not be empty. QuicStringPiece body; // Might be zero. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc index 3a5b720d277..10b19f1d668 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc @@ -50,29 +50,29 @@ TEST_F(QuicSpdyStreamBodyManagerTest, ConsumeMoreThanAvailable) { EXPECT_EQ(0u, bytes_to_consume); } -struct { - std::vector frame_header_lengths; - std::vector frame_payloads; - std::vector body_bytes_to_read; - std::vector expected_return_values; -} const kOnBodyConsumedTestData[] = { - // One frame consumed in one call. - {{2}, {"foobar"}, {6}, {6}}, - // Two frames consumed in one call. - {{3, 5}, {"foobar", "baz"}, {9}, {14}}, - // One frame consumed in two calls. - {{2}, {"foobar"}, {4, 2}, {4, 2}}, - // Two frames consumed in two calls matching frame boundaries. - {{3, 5}, {"foobar", "baz"}, {6, 3}, {11, 3}}, - // Two frames consumed in two calls, - // the first call only consuming part of the first frame. - {{3, 5}, {"foobar", "baz"}, {5, 4}, {5, 9}}, - // Two frames consumed in two calls, - // the first call consuming the entire first frame and part of the second. - {{3, 5}, {"foobar", "baz"}, {7, 2}, {12, 2}}, -}; - TEST_F(QuicSpdyStreamBodyManagerTest, OnBodyConsumed) { + struct { + std::vector frame_header_lengths; + std::vector frame_payloads; + std::vector body_bytes_to_read; + std::vector expected_return_values; + } const kOnBodyConsumedTestData[] = { + // One frame consumed in one call. + {{2}, {"foobar"}, {6}, {6}}, + // Two frames consumed in one call. + {{3, 5}, {"foobar", "baz"}, {9}, {14}}, + // One frame consumed in two calls. + {{2}, {"foobar"}, {4, 2}, {4, 2}}, + // Two frames consumed in two calls matching frame boundaries. + {{3, 5}, {"foobar", "baz"}, {6, 3}, {11, 3}}, + // Two frames consumed in two calls, + // the first call only consuming part of the first frame. + {{3, 5}, {"foobar", "baz"}, {5, 4}, {5, 9}}, + // Two frames consumed in two calls, + // the first call consuming the entire first frame and part of the second. + {{3, 5}, {"foobar", "baz"}, {7, 2}, {12, 2}}, + }; + for (size_t test_case_index = 0; test_case_index < QUIC_ARRAYSIZE(kOnBodyConsumedTestData); ++test_case_index) { @@ -105,26 +105,26 @@ TEST_F(QuicSpdyStreamBodyManagerTest, OnBodyConsumed) { } } -struct { - std::vector frame_header_lengths; - std::vector frame_payloads; - size_t iov_len; -} const kPeekBodyTestData[] = { - // No frames, more iovecs than frames. - {{}, {}, 1}, - // One frame, same number of iovecs. - {{3}, {"foobar"}, 1}, - // One frame, more iovecs than frames. - {{3}, {"foobar"}, 2}, - // Two frames, fewer iovecs than frames. - {{3, 5}, {"foobar", "baz"}, 1}, - // Two frames, same number of iovecs. - {{3, 5}, {"foobar", "baz"}, 2}, - // Two frames, more iovecs than frames. - {{3, 5}, {"foobar", "baz"}, 3}, -}; - TEST_F(QuicSpdyStreamBodyManagerTest, PeekBody) { + struct { + std::vector frame_header_lengths; + std::vector frame_payloads; + size_t iov_len; + } const kPeekBodyTestData[] = { + // No frames, more iovecs than frames. + {{}, {}, 1}, + // One frame, same number of iovecs. + {{3}, {"foobar"}, 1}, + // One frame, more iovecs than frames. + {{3}, {"foobar"}, 2}, + // Two frames, fewer iovecs than frames. + {{3, 5}, {"foobar", "baz"}, 1}, + // Two frames, same number of iovecs. + {{3, 5}, {"foobar", "baz"}, 2}, + // Two frames, more iovecs than frames. + {{3, 5}, {"foobar", "baz"}, 3}, + }; + for (size_t test_case_index = 0; test_case_index < QUIC_ARRAYSIZE(kPeekBodyTestData); ++test_case_index) { const std::vector& frame_header_lengths = @@ -159,62 +159,65 @@ TEST_F(QuicSpdyStreamBodyManagerTest, PeekBody) { } } -struct { - std::vector frame_header_lengths; - std::vector frame_payloads; - std::vector> iov_lengths; - std::vector expected_total_bytes_read; - std::vector expected_return_values; -} const kReadBodyTestData[] = { - // One frame, one read with smaller iovec. - {{4}, {"foo"}, {{2}}, {2}, {2}}, - // One frame, one read with same size iovec. - {{4}, {"foo"}, {{3}}, {3}, {3}}, - // One frame, one read with larger iovec. - {{4}, {"foo"}, {{5}}, {3}, {3}}, - // One frame, one read with two iovecs, smaller total size. - {{4}, {"foobar"}, {{2, 3}}, {5}, {5}}, - // One frame, one read with two iovecs, same total size. - {{4}, {"foobar"}, {{2, 4}}, {6}, {6}}, - // One frame, one read with two iovecs, larger total size in last iovec. - {{4}, {"foobar"}, {{2, 6}}, {6}, {6}}, - // One frame, one read with extra iovecs, body ends at iovec boundary. - {{4}, {"foobar"}, {{2, 4, 4, 3}}, {6}, {6}}, - // One frame, one read with extra iovecs, body ends not at iovec boundary. - {{4}, {"foobar"}, {{2, 7, 4, 3}}, {6}, {6}}, - // One frame, two reads with two iovecs each, smaller total size. - {{4}, {"foobarbaz"}, {{2, 1}, {3, 2}}, {3, 5}, {3, 5}}, - // One frame, two reads with two iovecs each, same total size. - {{4}, {"foobarbaz"}, {{2, 1}, {4, 2}}, {3, 6}, {3, 6}}, - // One frame, two reads with two iovecs each, larger total size. - {{4}, {"foobarbaz"}, {{2, 1}, {4, 10}}, {3, 6}, {3, 6}}, - // Two frames, one read with smaller iovec. - {{4, 3}, {"foobar", "baz"}, {{8}}, {8}, {11}}, - // Two frames, one read with same size iovec. - {{4, 3}, {"foobar", "baz"}, {{9}}, {9}, {12}}, - // Two frames, one read with larger iovec. - {{4, 3}, {"foobar", "baz"}, {{10}}, {9}, {12}}, - // Two frames, one read with two iovecs, smaller total size. - {{4, 3}, {"foobar", "baz"}, {{4, 3}}, {7}, {10}}, - // Two frames, one read with two iovecs, same total size. - {{4, 3}, {"foobar", "baz"}, {{4, 5}}, {9}, {12}}, - // Two frames, one read with two iovecs, larger total size in last iovec. - {{4, 3}, {"foobar", "baz"}, {{4, 6}}, {9}, {12}}, - // Two frames, one read with extra iovecs, body ends at iovec boundary. - {{4, 3}, {"foobar", "baz"}, {{4, 6, 4, 3}}, {9}, {12}}, - // Two frames, one read with extra iovecs, body ends not at iovec boundary. - {{4, 3}, {"foobar", "baz"}, {{4, 7, 4, 3}}, {9}, {12}}, - // Two frames, two reads with two iovecs each, reads end on frame boundary. - {{4, 3}, {"foobar", "baz"}, {{2, 4}, {2, 1}}, {6, 3}, {9, 3}}, - // Three frames, three reads, extra iovecs, no iovec ends on frame boundary. - {{4, 3, 6}, - {"foobar", "bazquux", "qux"}, - {{4, 3}, {2, 3}, {5, 3}}, - {7, 5, 4}, - {10, 5, 10}}, -}; - TEST_F(QuicSpdyStreamBodyManagerTest, ReadBody) { + struct { + std::vector frame_header_lengths; + std::vector frame_payloads; + std::vector> iov_lengths; + std::vector expected_total_bytes_read; + std::vector expected_return_values; + } const kReadBodyTestData[] = { + // One frame, one read with smaller iovec. + {{4}, {"foo"}, {{2}}, {2}, {2}}, + // One frame, one read with same size iovec. + {{4}, {"foo"}, {{3}}, {3}, {3}}, + // One frame, one read with larger iovec. + {{4}, {"foo"}, {{5}}, {3}, {3}}, + // One frame, one read with two iovecs, smaller total size. + {{4}, {"foobar"}, {{2, 3}}, {5}, {5}}, + // One frame, one read with two iovecs, same total size. + {{4}, {"foobar"}, {{2, 4}}, {6}, {6}}, + // One frame, one read with two iovecs, larger total size in last iovec. + {{4}, {"foobar"}, {{2, 6}}, {6}, {6}}, + // One frame, one read with extra iovecs, body ends at iovec boundary. + {{4}, {"foobar"}, {{2, 4, 4, 3}}, {6}, {6}}, + // One frame, one read with extra iovecs, body ends not at iovec boundary. + {{4}, {"foobar"}, {{2, 7, 4, 3}}, {6}, {6}}, + // One frame, two reads with two iovecs each, smaller total size. + {{4}, {"foobarbaz"}, {{2, 1}, {3, 2}}, {3, 5}, {3, 5}}, + // One frame, two reads with two iovecs each, same total size. + {{4}, {"foobarbaz"}, {{2, 1}, {4, 2}}, {3, 6}, {3, 6}}, + // One frame, two reads with two iovecs each, larger total size. + {{4}, {"foobarbaz"}, {{2, 1}, {4, 10}}, {3, 6}, {3, 6}}, + // Two frames, one read with smaller iovec. + {{4, 3}, {"foobar", "baz"}, {{8}}, {8}, {11}}, + // Two frames, one read with same size iovec. + {{4, 3}, {"foobar", "baz"}, {{9}}, {9}, {12}}, + // Two frames, one read with larger iovec. + {{4, 3}, {"foobar", "baz"}, {{10}}, {9}, {12}}, + // Two frames, one read with two iovecs, smaller total size. + {{4, 3}, {"foobar", "baz"}, {{4, 3}}, {7}, {10}}, + // Two frames, one read with two iovecs, same total size. + {{4, 3}, {"foobar", "baz"}, {{4, 5}}, {9}, {12}}, + // Two frames, one read with two iovecs, larger total size in last iovec. + {{4, 3}, {"foobar", "baz"}, {{4, 6}}, {9}, {12}}, + // Two frames, one read with extra iovecs, body ends at iovec boundary. + {{4, 3}, {"foobar", "baz"}, {{4, 6, 4, 3}}, {9}, {12}}, + // Two frames, one read with extra iovecs, body ends not at iovec + // boundary. + {{4, 3}, {"foobar", "baz"}, {{4, 7, 4, 3}}, {9}, {12}}, + // Two frames, two reads with two iovecs each, reads end on frame + // boundary. + {{4, 3}, {"foobar", "baz"}, {{2, 4}, {2, 1}}, {6, 3}, {9, 3}}, + // Three frames, three reads, extra iovecs, no iovec ends on frame + // boundary. + {{4, 3, 6}, + {"foobar", "bazquux", "qux"}, + {{4, 3}, {2, 3}, {5, 3}}, + {7, 5, 4}, + {10, 5, 10}}, + }; + for (size_t test_case_index = 0; test_case_index < QUIC_ARRAYSIZE(kReadBodyTestData); ++test_case_index) { const std::vector& frame_header_lengths = 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 c545265dd77..62ef3b5015a 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 @@ -22,6 +22,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" @@ -231,21 +232,31 @@ class QuicSpdyStreamTest : public QuicTestWithParam { auto send_control_stream = QuicSpdySessionPeer::GetSendControlStream(session_.get()); // The control stream will write 3 times, including stream type, settings - // frame, priority for headers. + // frame and max push id, priority for headers. + int num_control_stream_writes = 2; + if (session_->perspective() == Perspective::IS_CLIENT) { + // The control stream also writes the max push id frame. + num_control_stream_writes++; + } EXPECT_CALL(*session_, WritevData(send_control_stream, send_control_stream->id(), _, _, _)) - .Times(2); - auto qpack_encoder_stream = - QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get()); - EXPECT_CALL(*session_, WritevData(qpack_encoder_stream, - qpack_encoder_stream->id(), 1, 0, _)); + .Times(num_control_stream_writes); auto qpack_decoder_stream = QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); EXPECT_CALL(*session_, WritevData(qpack_decoder_stream, qpack_decoder_stream->id(), 1, 0, _)); + auto qpack_encoder_stream = + QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get()); + EXPECT_CALL(*session_, WritevData(qpack_encoder_stream, + qpack_encoder_stream->id(), 1, 0, _)); + } + if (session_->use_handshake_delegate()) { + static_cast(session_.get()) + ->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + } else { + static_cast(session_.get()) + ->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED); } - static_cast(session_.get()) - ->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED); } QuicHeaderList ProcessHeaders(bool fin, const SpdyHeaderBlock& headers) { @@ -280,7 +291,8 @@ class QuicSpdyStreamTest : public QuicTestWithParam { std::string HeadersFrame(QuicStringPiece payload) { std::unique_ptr headers_buffer; QuicByteCount headers_frame_header_length = - encoder_.SerializeHeadersFrameHeader(payload.length(), &headers_buffer); + HttpEncoder::SerializeHeadersFrameHeader(payload.length(), + &headers_buffer); QuicStringPiece headers_frame_header(headers_buffer.get(), headers_frame_header_length); return QuicStrCat(headers_frame_header, payload); @@ -289,7 +301,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam { std::string DataFrame(QuicStringPiece payload) { std::unique_ptr data_buffer; QuicByteCount data_frame_header_length = - encoder_.SerializeDataFrameHeader(payload.length(), &data_buffer); + HttpEncoder::SerializeDataFrameHeader(payload.length(), &data_buffer); QuicStringPiece data_frame_header(data_buffer.get(), data_frame_header_length); return QuicStrCat(data_frame_header, payload); @@ -323,8 +335,6 @@ class QuicSpdyStreamTest : public QuicTestWithParam { TestStream* stream2_; SpdyHeaderBlock headers_; - - HttpEncoder encoder_; }; INSTANTIATE_TEST_SUITE_P(Tests, @@ -346,29 +356,36 @@ TEST_P(QuicSpdyStreamTest, ProcessHeaderList) { TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) { Initialize(kShouldProcessData); - QuicHeaderList headers; - stream_->OnStreamHeadersPriority( - spdy::SpdyStreamPrecedence(kV3HighestPriority)); - - const bool version_uses_qpack = - VersionUsesHttp3(GetParam().transport_version); + if (!UsesHttp3()) { + QuicHeaderList headers; + stream_->OnStreamHeadersPriority( + spdy::SpdyStreamPrecedence(kV3HighestPriority)); - if (version_uses_qpack) { - EXPECT_CALL( - *connection_, - CloseConnection( - QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, - MatchesRegex("Too large headers received on stream \\d+"), _)); - } else { EXPECT_CALL(*session_, SendRstStream(stream_->id(), QUIC_HEADERS_TOO_LARGE, 0)); - } + stream_->OnStreamHeaderList(false, 1 << 20, headers); - stream_->OnStreamHeaderList(false, 1 << 20, headers); + EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE)); - if (!version_uses_qpack) { - EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, stream_->stream_error()); + return; } + + // Header list size includes 32 bytes for overhead per header field. + session_->set_max_inbound_header_list_size(40); + std::string headers = + HeadersFrame({std::make_pair("foo", "too long headers")}); + + QuicStreamFrame frame(stream_->id(), false, 0, headers); + + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, + MatchesRegex("Too large headers received on stream \\d+"), + _)); + + stream_->OnStreamFrame(frame); + + EXPECT_TRUE(stream_->header_list().empty()); } TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) { @@ -386,7 +403,7 @@ TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) { EXPECT_EQ("", stream_->data()); EXPECT_FALSE(stream_->header_list().empty()); EXPECT_FALSE(stream_->IsDoneReading()); - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); } // A valid status code should be 3-digit integer. The first digit should be in @@ -469,7 +486,8 @@ TEST_P(QuicSpdyStreamTest, ProcessWrongFramesOnSpdyStream) { GoAwayFrame goaway; goaway.stream_id = 0x1; std::unique_ptr buffer; - QuicByteCount header_length = encoder_.SerializeGoAwayFrame(goaway, &buffer); + QuicByteCount header_length = + HttpEncoder::SerializeGoAwayFrame(goaway, &buffer); std::string data = std::string(buffer.get(), header_length); EXPECT_EQ("", stream_->data()); @@ -763,7 +781,8 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) { if (UsesHttp3()) { std::unique_ptr buffer; - header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); + header_length = + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); std::string header = std::string(buffer.get(), header_length); data = header + body; } else { @@ -812,7 +831,8 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) { if (UsesHttp3()) { std::unique_ptr buffer; - header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); + header_length = + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); std::string header = std::string(buffer.get(), header_length); data = header + body; } else { @@ -882,12 +902,13 @@ TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) { if (UsesHttp3()) { body = std::string(kWindow / 4 - 2, 'a'); std::unique_ptr buffer; - header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); + header_length = + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); std::string header = std::string(buffer.get(), header_length); data = header + body; std::unique_ptr buffer2; QuicByteCount header_length2 = - encoder_.SerializeDataFrameHeader(body2.length(), &buffer2); + HttpEncoder::SerializeDataFrameHeader(body2.length(), &buffer2); std::string header2 = std::string(buffer2.get(), header_length2); data2 = header2 + body2; } else { @@ -1023,7 +1044,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) { trailers_block["key2"] = "value2"; trailers_block["key3"] = "value3"; SpdyHeaderBlock trailers_block_with_final_offset = trailers_block.Clone(); - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { // :final-offset pseudo-header is only added if trailers are sent // on the headers stream. trailers_block_with_final_offset[kFinalOffsetHeaderKey] = "0"; @@ -1051,7 +1072,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) { TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) { // kFinalOffsetHeaderKey is not used when HEADERS are sent on the // request/response stream. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1098,7 +1119,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) { TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { // kFinalOffsetHeaderKey is not used when HEADERS are sent on the // request/response stream. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1130,7 +1151,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) { // In IETF QUIC, there is no such thing as FIN flag on HTTP/3 frames like the // HEADERS frame. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1161,7 +1182,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterHeadersWithFin) { // If HEADERS frames are sent on the request/response stream, then the // sequencer will signal an error if any stream data arrives after a FIN, // so QuicSpdyStream does not need to. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1183,7 +1204,7 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) { // If HEADERS frames are sent on the request/response stream, // then the sequencer will block them from reaching QuicSpdyStream // after the stream is closed. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1233,7 +1254,7 @@ TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) { TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) { Initialize(kShouldProcessData); - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { // In this case, TestStream::WriteHeadersImpl() does not prevent writes. EXPECT_CALL(*session_, WritevData(stream_, stream_->id(), _, _, _)) .Times(AtLeast(1)); @@ -1253,9 +1274,10 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) { TEST_P(QuicSpdyStreamTest, ClientWritesPriority) { SetQuicFlag(FLAGS_quic_allow_http3_priority, true); + SetQuicReloadableFlag(quic_send_max_push_id_with_settings, true); InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT); - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { // In this case, TestStream::WriteHeadersImpl() does not prevent writes. // Six writes include priority for headers, headers frame header, headers // frame, priority of trailers, trailing headers frame header, and trailers. @@ -1263,7 +1285,8 @@ TEST_P(QuicSpdyStreamTest, ClientWritesPriority) { .Times(4); auto send_control_stream = QuicSpdySessionPeer::GetSendControlStream(session_.get()); - // The control stream will write priority for headers. + // The control stream will write priority for headers as well as + // the settings/max_push_id. EXPECT_CALL(*session_, WritevData(send_control_stream, send_control_stream->id(), _, _, _)) .Times(1); @@ -1286,7 +1309,7 @@ TEST_P(QuicSpdyStreamTest, ClientWritesPriority) { TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) { Initialize(kShouldProcessData); - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { // In this case, TestStream::WriteHeadersImpl() does not prevent writes. EXPECT_CALL(*session_, WritevData(stream_, stream_->id(), _, _, _)) .Times(AtLeast(1)); @@ -1302,7 +1325,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) { QuicByteCount header_length = 0; if (UsesHttp3()) { std::unique_ptr buf; - header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); + header_length = HttpEncoder::SerializeDataFrameHeader(body.length(), &buf); } stream_->WriteOrBufferBody(body, false); @@ -1315,7 +1338,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) { SpdyHeaderBlock expected_trailers(trailers.Clone()); // :final-offset pseudo-header is only added if trailers are sent // on the headers stream. - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { expected_trailers[kFinalOffsetHeaderKey] = QuicTextUtils::Uint64ToString(body.length() + header_length); } @@ -1357,7 +1380,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) { // This test exercises sending trailers on the headers stream while data is // still queued on the response/request stream. In IETF QUIC, data and // trailers are sent on the same stream, so this test does not apply. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1416,7 +1439,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) { TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) { // There is no headers stream if QPACK is used. - if (VersionUsesHttp3(GetParam().transport_version)) { + if (UsesHttp3()) { return; } @@ -1652,10 +1675,11 @@ TEST_P(QuicSpdyStreamTest, HeadersAckNotReportedWriteOrBufferBody) { std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); std::string header = std::string(buffer.get(), header_length); - header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer); + header_length = + HttpEncoder::SerializeDataFrameHeader(body2.length(), &buffer); std::string header2 = std::string(buffer.get(), header_length); EXPECT_CALL(*mock_ack_listener, OnPacketAcked(body.length(), _)); @@ -1748,7 +1772,7 @@ TEST_P(QuicSpdyStreamTest, HeaderBytesNotReportedOnRetransmission) { } TEST_P(QuicSpdyStreamTest, HeadersFrameOnRequestStream) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -1776,7 +1800,7 @@ TEST_P(QuicSpdyStreamTest, HeadersFrameOnRequestStream) { } TEST_P(QuicSpdyStreamTest, ProcessBodyAfterTrailers) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -1820,7 +1844,7 @@ TEST_P(QuicSpdyStreamTest, ProcessBodyAfterTrailers) { // normal body. Make sure the http decoder stops processing body after the // connection shuts down. TEST_P(QuicSpdyStreamTest, MalformedHeadersStopHttpDecoder) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -1839,11 +1863,10 @@ TEST_P(QuicSpdyStreamTest, MalformedHeadersStopHttpDecoder) { EXPECT_CALL( *connection_, - CloseConnection( - QUIC_DECOMPRESSION_FAILURE, - MatchesRegex("Error decompressing header block on stream \\d+: " - "Incomplete header block."), - _)) + CloseConnection(QUIC_QPACK_DECOMPRESSION_FAILED, + MatchesRegex("Error decoding headers on stream \\d+: " + "Incomplete header block."), + _)) .WillOnce( (Invoke([this](QuicErrorCode error, const std::string& error_details, ConnectionCloseBehavior connection_close_behavior) { @@ -1861,8 +1884,50 @@ TEST_P(QuicSpdyStreamTest, MalformedHeadersStopHttpDecoder) { stream_->OnStreamFrame(frame); } +// Regression test for https://crbug.com/1027895: a HEADERS frame triggers an +// error in QuicSpdyStream::OnHeadersFramePayload(). This closes the +// connection, freeing the buffer of QuicStreamSequencer. Therefore +// QuicStreamSequencer::MarkConsumed() must not be called from +// QuicSpdyStream::OnHeadersFramePayload(). +TEST_P(QuicSpdyStreamTest, DoNotMarkConsumedAfterQpackDecodingError) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + + testing::InSequence s; + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_QPACK_DECOMPRESSION_FAILED, + MatchesRegex("Error decoding headers on stream \\d+: " + "Invalid relative index."), + _)) + .WillOnce( + (Invoke([this](QuicErrorCode error, const std::string& error_details, + ConnectionCloseBehavior connection_close_behavior) { + connection_->ReallyCloseConnection(error, error_details, + connection_close_behavior); + }))); + EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _)); + EXPECT_CALL(*session_, OnConnectionClosed(_, _)) + .WillOnce(Invoke([this](const QuicConnectionCloseFrame& frame, + ConnectionCloseSource source) { + session_->ReallyOnConnectionClosed(frame, source); + })); + EXPECT_CALL(*session_, SendRstStream(stream_->id(), _, _)); + EXPECT_CALL(*session_, SendRstStream(stream2_->id(), _, _)); + + // Invalid headers: Required Insert Count is zero, but the header block + // contains a dynamic table reference. + std::string headers = HeadersFrame(QuicTextUtils::HexDecode("000080")); + QuicStreamFrame frame(stream_->id(), false, 0, headers); + stream_->OnStreamFrame(frame); +} + TEST_P(QuicSpdyStreamTest, ImmediateHeaderDecodingWithDynamicTableEntries) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -1917,7 +1982,7 @@ TEST_P(QuicSpdyStreamTest, ImmediateHeaderDecodingWithDynamicTableEntries) { } TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -1974,7 +2039,7 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) { } TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingHeaders) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -1993,11 +2058,10 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingHeaders) { EXPECT_CALL( *connection_, - CloseConnection( - QUIC_DECOMPRESSION_FAILURE, - MatchesRegex("Error during async decoding of headers on stream \\d+: " - "Required Insert Count too large."), - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + CloseConnection(QUIC_QPACK_DECOMPRESSION_FAILED, + MatchesRegex("Error decoding headers on stream \\d+: " + "Required Insert Count too large."), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); // Deliver two dynamic table entries to decoder // to trigger decoding of header block. @@ -2005,8 +2069,37 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingHeaders) { session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar"); } +// Regression test for https://crbug.com/1024263 and for +// https://crbug.com/1025209#c11. +TEST_P(QuicSpdyStreamTest, BlockedHeaderDecodingUnblockedWithBufferedError) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + session_->qpack_decoder()->OnSetDynamicTableCapacity(1024); + + // Relative index 2 is invalid because it is larger than or equal to the Base. + std::string headers = HeadersFrame(QuicTextUtils::HexDecode("020082")); + stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), false, 0, headers)); + + // Decoding is blocked. + EXPECT_FALSE(stream_->headers_decompressed()); + + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_QPACK_DECOMPRESSION_FAILED, + MatchesRegex("Error decoding headers on stream \\d+: " + "Invalid relative index."), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + + // Deliver one dynamic table entry to decoder + // to trigger decoding of header block. + session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar"); +} + TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2053,13 +2146,12 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) { // Insert Count value advertised in the header block prefix. EXPECT_FALSE(stream_->trailers_decompressed()); - EXPECT_CALL(*connection_, - CloseConnection( - QUIC_DECOMPRESSION_FAILURE, - MatchesRegex( - "Error during async decoding of trailers on stream \\d+: " - "Required Insert Count too large."), - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_QPACK_DECOMPRESSION_FAILED, + MatchesRegex("Error decoding trailers on stream \\d+: " + "Required Insert Count too large."), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); // Deliver second dynamic table entry to decoder // to trigger decoding of trailing header block. @@ -2116,7 +2208,7 @@ INSTANTIATE_TEST_SUITE_P(Tests, // Test that stream bytes are consumed (by calling // sequencer()->MarkConsumed()) incrementally, as soon as possible. TEST_P(QuicSpdyStreamIncrementalConsumptionTest, OnlyKnownFrames) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2175,7 +2267,7 @@ TEST_P(QuicSpdyStreamIncrementalConsumptionTest, OnlyKnownFrames) { } TEST_P(QuicSpdyStreamIncrementalConsumptionTest, UnknownFramesInterleaved) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2268,9 +2360,8 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) { push_promise.push_id = 0x01; push_promise.headers = headers; std::unique_ptr buffer; - HttpEncoder encoder; - uint64_t length = - encoder.SerializePushPromiseFrameWithOnlyPushId(push_promise, &buffer); + uint64_t length = HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( + push_promise, &buffer); std::string data = std::string(buffer.get(), length) + headers; QuicStreamFrame frame(stream_->id(), false, 0, data); @@ -2282,7 +2373,7 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) { // Close connection if a DATA frame is received before a HEADERS frame. TEST_P(QuicSpdyStreamTest, DataBeforeHeaders) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2304,7 +2395,7 @@ TEST_P(QuicSpdyStreamTest, DataBeforeHeaders) { // Close connection if a HEADERS frame is received after the trailing HEADERS. TEST_P(QuicSpdyStreamTest, TrailersAfterTrailers) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2357,7 +2448,7 @@ TEST_P(QuicSpdyStreamTest, TrailersAfterTrailers) { // Regression test for https://crbug.com/978733. // Close connection if a DATA frame is received after the trailing HEADERS. TEST_P(QuicSpdyStreamTest, DataAfterTrailers) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2407,7 +2498,7 @@ TEST_P(QuicSpdyStreamTest, DataAfterTrailers) { // SETTINGS frames are invalid on bidirectional streams. If one is received, // the connection is closed. No more data should be processed. TEST_P(QuicSpdyStreamTest, StopProcessingIfConnectionClosed) { - if (!VersionUsesHttp3(GetParam().transport_version)) { + if (!UsesHttp3()) { return; } @@ -2438,6 +2529,45 @@ TEST_P(QuicSpdyStreamTest, StopProcessingIfConnectionClosed) { EXPECT_EQ(0u, stream_->sequencer()->NumBytesConsumed()); } +// Stream Cancellation instruction is sent on QPACK decoder stream +// when stream is reset. +// TODO(b/145684124) Re-enable. +TEST_P(QuicSpdyStreamTest, DISABLED_StreamCancellationWhenStreamReset) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + + auto qpack_decoder_stream = + QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); + EXPECT_CALL(*session_, WritevData(qpack_decoder_stream, + qpack_decoder_stream->id(), 1, 1, _)); + EXPECT_CALL(*session_, + SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, 0)); + + stream_->Reset(QUIC_STREAM_CANCELLED); +} + +// Stream Cancellation instruction is sent on QPACK decoder stream +// when RESET_STREAM frame is received. +// TODO(b/145684124) Re-enable. +TEST_P(QuicSpdyStreamTest, DISABLED_StreamCancellationOnResetReceived) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + + auto qpack_decoder_stream = + QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); + EXPECT_CALL(*session_, WritevData(qpack_decoder_stream, + qpack_decoder_stream->id(), 1, 1, _)); + + stream_->OnStreamReset(QuicRstStreamFrame( + kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 0)); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/spdy_server_push_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/spdy_server_push_utils_test.cc index 72d4a25ed13..0f6ec8a6287 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/spdy_server_push_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/spdy_server_push_utils_test.cc @@ -13,8 +13,6 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" using spdy::SpdyHeaderBlock; -using testing::Pair; -using testing::UnorderedElementsAre; namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h b/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h index 695ff7d91ec..470a58c1f11 100644 --- a/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h +++ b/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h @@ -35,7 +35,7 @@ namespace quic { // Because of that, it is not a general-purpose container and should not be used // as one. template -class PacketNumberIndexedQueue { +class QUIC_NO_EXPORT PacketNumberIndexedQueue { public: PacketNumberIndexedQueue() : number_of_present_entries_(0) {} @@ -86,7 +86,7 @@ class PacketNumberIndexedQueue { private: // Wrapper around T used to mark whether the entry is actually in the map. - struct EntryWrapper : T { + struct QUIC_NO_EXPORT EntryWrapper : T { bool present; EntryWrapper() : present(false) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md deleted file mode 100644 index 4f6697c66b5..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# QPACK Offline Interop Testing tools - -See -[QPACK Offline Interop](https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop) -for description of test data format. - -Example usage: - -```shell -$ # Download test data -$ cd $TEST_DATA -$ git clone https://github.com/qpackers/qifs.git -$ TEST_ENCODED_DATA=`pwd`/qifs/encoded/qpack-03 -$ TEST_QIF_DATA=`pwd`/qifs/qifs -$ -$ # Decode encoded test data in four files and verify that they match -$ # the original headers in corresponding files -$ $BIN/qpack_offline_decoder \ -> $TEST_ENCODED_DATA/f5/fb-req.qifencoded.4096.100.0 \ -> $TEST_QIF_DATA/fb-req.qif -> $TEST_ENCODED_DATA/h2o/fb-req-hq.out.512.0.1 \ -> $TEST_QIF_DATA/fb-req-hq.qif -> $TEST_ENCODED_DATA/ls-qpack/fb-resp-hq.out.0.0.0 \ -> $TEST_QIF_DATA/fb-resp-hq.qif -> $TEST_ENCODED_DATA/proxygen/netbsd.qif.proxygen.out.4096.0.0 \ -> $TEST_QIF_DATA/netbsd.qif -$ -``` diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc deleted file mode 100644 index 379cb6ad835..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h" - -#include -#include -#include - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_file_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" - -namespace quic { - -QpackOfflineDecoder::QpackOfflineDecoder() - : encoder_stream_error_detected_(false) {} - -bool QpackOfflineDecoder::DecodeAndVerifyOfflineData( - QuicStringPiece input_filename, - QuicStringPiece expected_headers_filename) { - if (!ParseInputFilename(input_filename)) { - QUIC_LOG(ERROR) << "Error parsing input filename " << input_filename; - return false; - } - - if (!DecodeHeaderBlocksFromFile(input_filename)) { - QUIC_LOG(ERROR) << "Error decoding header blocks in " << input_filename; - return false; - } - - if (!VerifyDecodedHeaderLists(expected_headers_filename)) { - QUIC_LOG(ERROR) << "Header lists decoded from " << input_filename - << " to not match expected headers parsed from " - << expected_headers_filename; - return false; - } - - return true; -} - -void QpackOfflineDecoder::OnEncoderStreamError(QuicStringPiece error_message) { - QUIC_LOG(ERROR) << "Encoder stream error: " << error_message; - encoder_stream_error_detected_ = true; -} - -bool QpackOfflineDecoder::ParseInputFilename(QuicStringPiece input_filename) { - auto pieces = QuicTextUtils::Split(input_filename, '.'); - - if (pieces.size() < 3) { - QUIC_LOG(ERROR) << "Not enough fields in input filename " << input_filename; - return false; - } - - auto piece_it = pieces.rbegin(); - - // Acknowledgement mode: 1 for immediate, 0 for none. - bool immediate_acknowledgement = false; - if (*piece_it == "0") { - immediate_acknowledgement = false; - } else if (*piece_it == "1") { - immediate_acknowledgement = true; - } else { - QUIC_LOG(ERROR) - << "Header acknowledgement field must be 0 or 1 in input filename " - << input_filename; - return false; - } - - ++piece_it; - - // Maximum allowed number of blocked streams. - uint64_t max_blocked_streams = 0; - if (!QuicTextUtils::StringToUint64(*piece_it, &max_blocked_streams)) { - QUIC_LOG(ERROR) << "Error parsing part of input filename \"" << *piece_it - << "\" as an integer."; - return false; - } - - ++piece_it; - - // Maximum Dynamic Table Capacity in bytes - uint64_t maximum_dynamic_table_capacity = 0; - if (!QuicTextUtils::StringToUint64(*piece_it, - &maximum_dynamic_table_capacity)) { - QUIC_LOG(ERROR) << "Error parsing part of input filename \"" << *piece_it - << "\" as an integer."; - return false; - } - qpack_decoder_ = std::make_unique( - maximum_dynamic_table_capacity, max_blocked_streams, this); - qpack_decoder_->set_qpack_stream_sender_delegate( - &decoder_stream_sender_delegate_); - - // The initial dynamic table capacity is zero according to - // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#eviction. - // However, for historical reasons, offline interop encoders use - // |maximum_dynamic_table_capacity| as initial capacity. - qpack_decoder_->OnSetDynamicTableCapacity(maximum_dynamic_table_capacity); - - return true; -} - -bool QpackOfflineDecoder::DecodeHeaderBlocksFromFile( - QuicStringPiece input_filename) { - // Store data in |input_data_storage|; use a QuicStringPiece to efficiently - // keep track of remaining portion yet to be decoded. - std::string input_data_storage; - ReadFileContents(input_filename, &input_data_storage); - QuicStringPiece input_data(input_data_storage); - - while (!input_data.empty()) { - // Parse stream_id and length. - if (input_data.size() < sizeof(uint64_t) + sizeof(uint32_t)) { - QUIC_LOG(ERROR) << "Unexpected end of input file."; - return false; - } - - uint64_t stream_id = QuicEndian::NetToHost64( - *reinterpret_cast(input_data.data())); - input_data = input_data.substr(sizeof(uint64_t)); - - uint32_t length = QuicEndian::NetToHost32( - *reinterpret_cast(input_data.data())); - input_data = input_data.substr(sizeof(uint32_t)); - - if (input_data.size() < length) { - QUIC_LOG(ERROR) << "Unexpected end of input file."; - return false; - } - - // Parse data. - QuicStringPiece data = input_data.substr(0, length); - input_data = input_data.substr(length); - - // Process data. - if (stream_id == 0) { - qpack_decoder_->encoder_stream_receiver()->Decode(data); - - if (encoder_stream_error_detected_) { - QUIC_LOG(ERROR) << "Error detected on encoder stream."; - return false; - } - } else { - auto headers_handler = std::make_unique(); - auto progressive_decoder = qpack_decoder_->CreateProgressiveDecoder( - stream_id, headers_handler.get()); - - progressive_decoder->Decode(data); - progressive_decoder->EndHeaderBlock(); - - if (headers_handler->decoding_error_detected()) { - QUIC_LOG(ERROR) << "Sync decoding error on stream " << stream_id << ": " - << headers_handler->error_message(); - return false; - } - - decoders_.push_back({std::move(headers_handler), - std::move(progressive_decoder), stream_id}); - } - - // Move decoded header lists from TestHeadersHandlers and append them to - // |decoded_header_lists_| while preserving the order in |decoders_|. - while (!decoders_.empty() && - decoders_.front().headers_handler->decoding_completed()) { - Decoder* decoder = &decoders_.front(); - - if (decoder->headers_handler->decoding_error_detected()) { - QUIC_LOG(ERROR) << "Async decoding error on stream " - << decoder->stream_id << ": " - << decoder->headers_handler->error_message(); - return false; - } - - if (!decoder->headers_handler->decoding_completed()) { - QUIC_LOG(ERROR) << "Decoding incomplete after reading entire" - " file, on stream " - << decoder->stream_id; - return false; - } - - decoded_header_lists_.push_back( - decoder->headers_handler->ReleaseHeaderList()); - decoders_.pop_front(); - } - } - - if (!decoders_.empty()) { - DCHECK(!decoders_.front().headers_handler->decoding_completed()); - - QUIC_LOG(ERROR) << "Blocked decoding uncomplete after reading entire" - " file, on stream " - << decoders_.front().stream_id; - return false; - } - - return true; -} - -bool QpackOfflineDecoder::VerifyDecodedHeaderLists( - QuicStringPiece expected_headers_filename) { - // Store data in |expected_headers_data_storage|; use a QuicStringPiece to - // efficiently keep track of remaining portion yet to be decoded. - std::string expected_headers_data_storage; - ReadFileContents(expected_headers_filename, &expected_headers_data_storage); - QuicStringPiece expected_headers_data(expected_headers_data_storage); - - while (!decoded_header_lists_.empty()) { - spdy::SpdyHeaderBlock decoded_header_list = - std::move(decoded_header_lists_.front()); - decoded_header_lists_.pop_front(); - - spdy::SpdyHeaderBlock expected_header_list; - if (!ReadNextExpectedHeaderList(&expected_headers_data, - &expected_header_list)) { - QUIC_LOG(ERROR) - << "Error parsing expected header list to match next decoded " - "header list."; - return false; - } - - if (!CompareHeaderBlocks(std::move(decoded_header_list), - std::move(expected_header_list))) { - QUIC_LOG(ERROR) << "Decoded header does not match expected header."; - return false; - } - } - - if (!expected_headers_data.empty()) { - QUIC_LOG(ERROR) - << "Not enough encoded header lists to match expected ones."; - return false; - } - - return true; -} - -bool QpackOfflineDecoder::ReadNextExpectedHeaderList( - QuicStringPiece* expected_headers_data, - spdy::SpdyHeaderBlock* expected_header_list) { - while (true) { - QuicStringPiece::size_type endline = expected_headers_data->find('\n'); - - // Even last header list must be followed by an empty line. - if (endline == QuicStringPiece::npos) { - QUIC_LOG(ERROR) << "Unexpected end of expected header list file."; - return false; - } - - if (endline == 0) { - // Empty line indicates end of header list. - *expected_headers_data = expected_headers_data->substr(1); - return true; - } - - QuicStringPiece header_field = expected_headers_data->substr(0, endline); - auto pieces = QuicTextUtils::Split(header_field, '\t'); - - if (pieces.size() != 2) { - QUIC_LOG(ERROR) << "Header key and value must be separated by TAB."; - return false; - } - - expected_header_list->AppendValueOrAddHeader(pieces[0], pieces[1]); - - *expected_headers_data = expected_headers_data->substr(endline + 1); - } -} - -bool QpackOfflineDecoder::CompareHeaderBlocks( - spdy::SpdyHeaderBlock decoded_header_list, - spdy::SpdyHeaderBlock expected_header_list) { - if (decoded_header_list == expected_header_list) { - return true; - } - - // The h2o decoder reshuffles the "content-length" header and pseudo-headers, - // see - // https://github.com/qpackers/qifs/blob/master/encoded/qpack-03/h2o/README.md. - // Remove such headers one by one if they match. - const char* kContentLength = "content-length"; - const char* kPseudoHeaderPrefix = ":"; - for (spdy::SpdyHeaderBlock::iterator decoded_it = decoded_header_list.begin(); - decoded_it != decoded_header_list.end();) { - const QuicStringPiece key = decoded_it->first; - if (key != kContentLength && - !QuicTextUtils::StartsWith(key, kPseudoHeaderPrefix)) { - ++decoded_it; - continue; - } - spdy::SpdyHeaderBlock::iterator expected_it = - expected_header_list.find(key); - if (expected_it == expected_header_list.end() || - decoded_it->second != expected_it->second) { - ++decoded_it; - continue; - } - // SpdyHeaderBlock does not support erasing by iterator, only by key. - ++decoded_it; - expected_header_list.erase(key); - // This will invalidate |key|. - decoded_header_list.erase(key); - } - - return decoded_header_list == expected_header_list; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h deleted file mode 100644 index c12c49181fa..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_ -#define QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_ - -#include - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" -#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" - -namespace quic { - -// A decoder to read encoded data from a file, decode it, and compare to -// a list of expected header lists read from another file. File format is -// described at -// https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop. -class QpackOfflineDecoder : public QpackDecoder::EncoderStreamErrorDelegate { - public: - QpackOfflineDecoder(); - ~QpackOfflineDecoder() override = default; - - // Read encoded header blocks and encoder stream data from |input_filename| - // and decode them, read expected header lists from - // |expected_headers_filename|, and compare decoded header lists to expected - // ones. Returns true if there is an equal number of them and the - // corresponding ones match, false otherwise. - bool DecodeAndVerifyOfflineData(QuicStringPiece input_filename, - QuicStringPiece expected_headers_filename); - - // QpackDecoder::EncoderStreamErrorDelegate implementation: - void OnEncoderStreamError(QuicStringPiece error_message) override; - - private: - // Data structure to hold TestHeadersHandler and QpackProgressiveDecoder until - // decoding of a header header block (and all preceding header blocks) is - // complete. - struct Decoder { - std::unique_ptr headers_handler; - std::unique_ptr progressive_decoder; - uint64_t stream_id; - }; - - // Parse decoder parameters from |input_filename| and set up |qpack_decoder_| - // accordingly. - bool ParseInputFilename(QuicStringPiece input_filename); - - // Read encoded header blocks and encoder stream data from |input_filename|, - // pass them to |qpack_decoder_| for decoding, and add decoded header lists to - // |decoded_header_lists_|. - bool DecodeHeaderBlocksFromFile(QuicStringPiece input_filename); - - // Read expected header lists from |expected_headers_filename| and verify - // decoded header lists in |decoded_header_lists_| against them. - bool VerifyDecodedHeaderLists(QuicStringPiece expected_headers_filename); - - // Parse next header list from |*expected_headers_data| into - // |*expected_header_list|, removing consumed data from the beginning of - // |*expected_headers_data|. Returns true on success, false if parsing fails. - bool ReadNextExpectedHeaderList(QuicStringPiece* expected_headers_data, - spdy::SpdyHeaderBlock* expected_header_list); - - // Compare two header lists. Allow for different orders of certain headers as - // described at - // https://github.com/qpackers/qifs/blob/master/encoded/qpack-03/h2o/README.md. - bool CompareHeaderBlocks(spdy::SpdyHeaderBlock decoded_header_list, - spdy::SpdyHeaderBlock expected_header_list); - - bool encoder_stream_error_detected_; - NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_; - std::unique_ptr qpack_decoder_; - - // Objects necessary for decoding, one list element for each header block. - std::list decoders_; - - // Decoded header lists. - std::list decoded_header_lists_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc deleted file mode 100644 index d72b0003da4..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h" - -#include -#include - -#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/platform/api/quic_string_piece.h" - -int main(int argc, char* argv[]) { - const char* usage = - "Usage: qpack_offline_decoder input_filename expected_headers_filename " - "...."; - std::vector args = - quic::QuicParseCommandLineFlags(usage, argc, argv); - - if (args.size() < 2 || args.size() % 2 != 0) { - quic::QuicPrintCommandLineFlagHelp(usage); - return 1; - } - - size_t i; - size_t success_count = 0; - for (i = 0; 2 * i < args.size(); ++i) { - const quic::QuicStringPiece input_filename(args[2 * i]); - const quic::QuicStringPiece expected_headers_filename(args[2 * i + 1]); - - // Every file represents a different connection, - // therefore every file needs a fresh decoding context. - quic::QpackOfflineDecoder decoder; - if (decoder.DecodeAndVerifyOfflineData(input_filename, - expected_headers_filename)) { - ++success_count; - } - } - - std::cout << "Processed " << i << " pairs of input files, " << success_count - << " passed, " << (i - success_count) << " failed." << std::endl; - - // Return success if all input files pass. - return (success_count == i) ? 0 : 1; -} diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc index ffec17280f6..3544f1ca10b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc @@ -24,7 +24,7 @@ bool QpackBlockingManager::OnHeaderAcknowledgement(QuicStreamId stream_id) { const uint64_t required_index_count = RequiredInsertCount(indices); if (known_received_count_ < required_index_count) { - IncreaseKnownReceivedCountTo(required_index_count); + known_received_count_ = required_index_count; } DecreaseReferenceCounts(indices); @@ -56,7 +56,7 @@ bool QpackBlockingManager::OnInsertCountIncrement(uint64_t increment) { return false; } - IncreaseKnownReceivedCountTo(known_received_count_ + increment); + known_received_count_ += increment; return true; } @@ -68,16 +68,6 @@ void QpackBlockingManager::OnHeaderBlockSent(QuicStreamId stream_id, header_blocks_[stream_id].push_back(std::move(indices)); } -void QpackBlockingManager::OnReferenceSentOnEncoderStream( - uint64_t inserted_index, - uint64_t referred_index) { - auto result = unacked_encoder_stream_references_.insert( - {inserted_index, referred_index}); - // Each dynamic table entry can refer to at most one |referred_index|. - DCHECK(result.second); - IncreaseReferenceCounts({referred_index}); -} - bool QpackBlockingManager::blocking_allowed_on_stream( QuicStreamId stream_id, uint64_t maximum_blocked_streams) const { @@ -141,26 +131,6 @@ uint64_t QpackBlockingManager::RequiredInsertCount(const IndexSet& indices) { return *indices.rbegin() + 1; } -void QpackBlockingManager::IncreaseKnownReceivedCountTo( - uint64_t new_known_received_count) { - DCHECK_GT(new_known_received_count, known_received_count_); - - known_received_count_ = new_known_received_count; - - // Remove referred indices with key less than new Known Received Count from - // |unacked_encoder_stream_references_| and |entry_reference_counts_|. - IndexSet acknowledged_references; - auto it = unacked_encoder_stream_references_.begin(); - while (it != unacked_encoder_stream_references_.end() && - it->first < known_received_count_) { - acknowledged_references.insert(it->second); - ++it; - } - unacked_encoder_stream_references_.erase( - unacked_encoder_stream_references_.begin(), it); - DecreaseReferenceCounts(acknowledged_references); -} - void QpackBlockingManager::IncreaseReferenceCounts(const IndexSet& indices) { for (const uint64_t index : indices) { auto it = entry_reference_counts_.lower_bound(index); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h index 60f7db7060a..6d2df9cfcf8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h @@ -48,12 +48,6 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager { // entries with |indices|. |indices| must not be empty. void OnHeaderBlockSent(QuicStreamId stream_id, IndexSet indices); - // Called when sending Insert With Name Reference or Duplicate instruction on - // encoder stream, inserting entry |inserted_index| referring to - // |referred_index|. - void OnReferenceSentOnEncoderStream(uint64_t inserted_index, - uint64_t referred_index); - // Returns true if sending blocking references on stream |stream_id| would not // increase the total number of blocked streams above // |maximum_blocked_streams|. Note that if |stream_id| is already blocked @@ -85,11 +79,6 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager { using HeaderBlocksForStream = std::list; using HeaderBlocks = QuicUnorderedMap; - // Increases |known_received_count_| to |new_known_received_count|, which must - // me larger than |known_received_count_|. Removes acknowledged references - // from |unacked_encoder_stream_references_|. - void IncreaseKnownReceivedCountTo(uint64_t new_known_received_count); - // Increase or decrease the reference count for each index in |indices|. void IncreaseReferenceCounts(const IndexSet& indices); void DecreaseReferenceCounts(const IndexSet& indices); @@ -98,13 +87,7 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager { // Must not contain a stream id with an empty queue. HeaderBlocks header_blocks_; - // Unacknowledged references on the encoder stream. - // The key is the absolute index of the inserted entry, - // the mapped value is the absolute index of the entry referred. - std::map unacked_encoder_stream_references_; - - // Number of references in |header_blocks_| and - // |unacked_encoder_stream_references_| for each entry index. + // Number of references in |header_blocks_| for each entry index. std::map entry_reference_counts_; uint64_t known_received_count_; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc index 64bfb97f71d..d92dda549ef 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc @@ -236,88 +236,6 @@ TEST_F(QpackBlockingManagerTest, CancelStream) { manager_.smallest_blocking_index()); } -TEST_F(QpackBlockingManagerTest, - ReferenceOnEncoderStreamUnblockedByInsertCountIncrement) { - EXPECT_EQ(0u, manager_.known_received_count()); - EXPECT_EQ(std::numeric_limits::max(), - manager_.smallest_blocking_index()); - - // Entry 1 refers to entry 0. - manager_.OnReferenceSentOnEncoderStream(1, 0); - // Entry 2 also refers to entry 0. - manager_.OnReferenceSentOnEncoderStream(2, 0); - - EXPECT_EQ(0u, manager_.known_received_count()); - EXPECT_EQ(0u, manager_.smallest_blocking_index()); - - // Acknowledging entry 1 still leaves one unacknowledged reference to entry 0. - EXPECT_TRUE(manager_.OnInsertCountIncrement(2)); - - EXPECT_EQ(2u, manager_.known_received_count()); - EXPECT_EQ(0u, manager_.smallest_blocking_index()); - - // Entry 3 also refers to entry 2. - manager_.OnReferenceSentOnEncoderStream(3, 2); - - EXPECT_EQ(2u, manager_.known_received_count()); - EXPECT_EQ(0u, manager_.smallest_blocking_index()); - - // Acknowledging entry 2 removes last reference to entry 0. - EXPECT_TRUE(manager_.OnInsertCountIncrement(1)); - - EXPECT_EQ(3u, manager_.known_received_count()); - EXPECT_EQ(2u, manager_.smallest_blocking_index()); - - // Acknowledging entry 4 (and implicitly 3) removes reference to entry 2. - EXPECT_TRUE(manager_.OnInsertCountIncrement(2)); - - EXPECT_EQ(5u, manager_.known_received_count()); - EXPECT_EQ(std::numeric_limits::max(), - manager_.smallest_blocking_index()); -} - -TEST_F(QpackBlockingManagerTest, - ReferenceOnEncoderStreamUnblockedByHeaderAcknowledgement) { - EXPECT_EQ(0u, manager_.known_received_count()); - EXPECT_EQ(std::numeric_limits::max(), - manager_.smallest_blocking_index()); - - // Entry 1 refers to entry 0. - manager_.OnReferenceSentOnEncoderStream(1, 0); - // Entry 2 also refers to entry 0. - manager_.OnReferenceSentOnEncoderStream(2, 0); - - EXPECT_EQ(0u, manager_.known_received_count()); - EXPECT_EQ(0u, manager_.smallest_blocking_index()); - - // Acknowledging a header block with entries up to 1 still leave one - // unacknowledged reference to entry 0. - manager_.OnHeaderBlockSent(/* stream_id = */ 0, {0, 1}); - manager_.OnHeaderAcknowledgement(/* stream_id = */ 0); - - EXPECT_EQ(2u, manager_.known_received_count()); - EXPECT_EQ(0u, manager_.smallest_blocking_index()); - - // Entry 3 also refers to entry 2. - manager_.OnReferenceSentOnEncoderStream(3, 2); - - // Acknowledging a header block with entries up to 2 removes last reference to - // entry 0. - manager_.OnHeaderBlockSent(/* stream_id = */ 0, {2, 0, 2}); - manager_.OnHeaderAcknowledgement(/* stream_id = */ 0); - - EXPECT_EQ(3u, manager_.known_received_count()); - EXPECT_EQ(2u, manager_.smallest_blocking_index()); - - // Acknowledging entry 4 (and implicitly 3) removes reference to entry 2. - manager_.OnHeaderBlockSent(/* stream_id = */ 0, {1, 4, 2, 0}); - manager_.OnHeaderAcknowledgement(/* stream_id = */ 0); - - EXPECT_EQ(5u, manager_.known_received_count()); - EXPECT_EQ(std::numeric_limits::max(), - manager_.smallest_blocking_index()); -} - TEST_F(QpackBlockingManagerTest, BlockingAllowedOnStream) { const QuicStreamId kStreamId1 = 1; const QuicStreamId kStreamId2 = 2; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc deleted file mode 100644 index 6644918b34a..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2018 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 "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" - -#include - -#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" - -namespace quic { - -namespace { - -// Validate that -// * in each instruction, the bits of |value| that are zero in |mask| are zero; -// * every byte matches exactly one opcode. -void ValidateLangague(const QpackLanguage* language) { -#ifndef NDEBUG - for (const auto* instruction : *language) { - DCHECK_EQ(0, instruction->opcode.value & ~instruction->opcode.mask); - } - - for (uint8_t byte = 0; byte < std::numeric_limits::max(); ++byte) { - size_t match_count = 0; - for (const auto* instruction : *language) { - if ((byte & instruction->opcode.mask) == instruction->opcode.value) { - ++match_count; - } - } - DCHECK_EQ(1u, match_count) << static_cast(byte); - } -#else - (void)language; -#endif -} - -} // namespace - -bool operator==(const QpackInstructionOpcode& a, - const QpackInstructionOpcode& b) { - return std::tie(a.value, a.mask) == std::tie(b.value, b.mask); -} - -const QpackInstruction* InsertWithNameReferenceInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b10000000, 0b10000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kSbit, 0b01000000}, - {QpackInstructionFieldType::kVarint, 6}, - {QpackInstructionFieldType::kValue, 7}}}; - return instruction; -} - -const QpackInstruction* InsertWithoutNameReferenceInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b01000000, 0b11000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kName, 5}, - {QpackInstructionFieldType::kValue, 7}}}; - return instruction; -} - -const QpackInstruction* DuplicateInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00000000, 0b11100000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}}; - return instruction; -} - -const QpackInstruction* SetDynamicTableCapacityInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00100000, 0b11100000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}}; - return instruction; -} - -const QpackLanguage* QpackEncoderStreamLanguage() { - static const QpackLanguage* const language = new QpackLanguage{ - InsertWithNameReferenceInstruction(), - InsertWithoutNameReferenceInstruction(), DuplicateInstruction(), - SetDynamicTableCapacityInstruction()}; - ValidateLangague(language); - return language; -} - -const QpackInstruction* InsertCountIncrementInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00000000, 0b11000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}}; - return instruction; -} - -const QpackInstruction* HeaderAcknowledgementInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b10000000, 0b10000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 7}}}; - return instruction; -} - -const QpackInstruction* StreamCancellationInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b01000000, 0b11000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}}; - return instruction; -} - -const QpackLanguage* QpackDecoderStreamLanguage() { - static const QpackLanguage* const language = new QpackLanguage{ - InsertCountIncrementInstruction(), HeaderAcknowledgementInstruction(), - StreamCancellationInstruction()}; - ValidateLangague(language); - return language; -} - -const QpackInstruction* QpackPrefixInstruction() { - // This opcode matches every input. - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00000000, 0b00000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kVarint, 8}, - {QpackInstructionFieldType::kSbit, 0b10000000}, - {QpackInstructionFieldType::kVarint2, 7}}}; - return instruction; -} - -const QpackLanguage* QpackPrefixLanguage() { - static const QpackLanguage* const language = - new QpackLanguage{QpackPrefixInstruction()}; - ValidateLangague(language); - return language; -} - -const QpackInstruction* QpackIndexedHeaderFieldInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b10000000, 0b10000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kSbit, 0b01000000}, - {QpackInstructionFieldType::kVarint, 6}}}; - return instruction; -} - -const QpackInstruction* QpackIndexedHeaderFieldPostBaseInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00010000, 0b11110000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 4}}}; - return instruction; -} - -const QpackInstruction* QpackLiteralHeaderFieldNameReferenceInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b01000000, 0b11000000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kSbit, 0b00010000}, - {QpackInstructionFieldType::kVarint, 4}, - {QpackInstructionFieldType::kValue, 7}}}; - return instruction; -} - -const QpackInstruction* QpackLiteralHeaderFieldPostBaseInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00000000, 0b11110000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kVarint, 3}, - {QpackInstructionFieldType::kValue, 7}}}; - return instruction; -} - -const QpackInstruction* QpackLiteralHeaderFieldInstruction() { - static const QpackInstructionOpcode* const opcode = - new QpackInstructionOpcode{0b00100000, 0b11100000}; - static const QpackInstruction* const instruction = - new QpackInstruction{*opcode, - {{QpackInstructionFieldType::kName, 3}, - {QpackInstructionFieldType::kValue, 7}}}; - return instruction; -} - -const QpackLanguage* QpackRequestStreamLanguage() { - static const QpackLanguage* const language = - new QpackLanguage{QpackIndexedHeaderFieldInstruction(), - QpackIndexedHeaderFieldPostBaseInstruction(), - QpackLiteralHeaderFieldNameReferenceInstruction(), - QpackLiteralHeaderFieldPostBaseInstruction(), - QpackLiteralHeaderFieldInstruction()}; - ValidateLangague(language); - return language; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h deleted file mode 100644 index 35e4d560bef..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_ -#define QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_ - -#include -#include -#include -#include - -#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" - -namespace quic { - -// Each instruction is identified with an opcode in the first byte. -// |mask| determines which bits are part of the opcode. -// |value| is the value of these bits. (Other bits in value must be zero.) -struct QUIC_EXPORT_PRIVATE QpackInstructionOpcode { - uint8_t value; - uint8_t mask; -}; - -bool operator==(const QpackInstructionOpcode& a, - const QpackInstructionOpcode& b); - -// Possible types of an instruction field. Decoding a static bit does not -// consume the current byte. Decoding an integer or a length-prefixed string -// literal consumes all bytes containing the field value. -enum class QpackInstructionFieldType { - // A single bit indicating whether the index refers to the static table, or - // indicating the sign of Delta Base. Called "S" bit because both "static" - // and "sign" start with the letter "S". - kSbit, - // An integer encoded with variable length encoding. This could be an index, - // stream ID, maximum size, or Encoded Required Insert Count. - kVarint, - // A second integer encoded with variable length encoding. This could be - // Delta Base. - kVarint2, - // A header name or header value encoded as: - // a bit indicating whether it is Huffman encoded; - // the encoded length of the string; - // the header name or value optionally Huffman encoded. - kName, - kValue -}; - -// Each instruction field has a type and a parameter. -// The meaning of the parameter depends on the field type. -struct QUIC_EXPORT_PRIVATE QpackInstructionField { - QpackInstructionFieldType type; - // For a kSbit field, |param| is a mask with exactly one bit set. - // For kVarint fields, |param| is the prefix length of the integer encoding. - // For kName and kValue fields, |param| is the prefix length of the length of - // the string, and the bit immediately preceding the prefix is interpreted as - // the Huffman bit. - uint8_t param; -}; - -using QpackInstructionFields = std::vector; - -// A QPACK instruction consists of an opcode identifying the instruction, -// followed by a non-empty list of fields. The last field must be integer or -// string literal type to guarantee that all bytes of the instruction are -// consumed. -struct QUIC_EXPORT_PRIVATE QpackInstruction { - QpackInstruction(const QpackInstruction&) = delete; - const QpackInstruction& operator=(const QpackInstruction&) = delete; - - QpackInstructionOpcode opcode; - QpackInstructionFields fields; -}; - -// A language is a collection of instructions. The order does not matter. -// Every possible input must match exactly one instruction. -using QpackLanguage = std::vector; - -// Wire format defined in -// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5 - -// 5.2 Encoder stream instructions - -// 5.2.1 Insert With Name Reference -const QpackInstruction* InsertWithNameReferenceInstruction(); - -// 5.2.2 Insert Without Name Reference -const QpackInstruction* InsertWithoutNameReferenceInstruction(); - -// 5.2.3 Duplicate -const QpackInstruction* DuplicateInstruction(); - -// 5.2.4 Dynamic Table Size Update -const QpackInstruction* SetDynamicTableCapacityInstruction(); - -// Encoder stream language. -const QpackLanguage* QpackEncoderStreamLanguage(); - -// 5.3 Decoder stream instructions - -// 5.3.1 Insert Count Increment -const QpackInstruction* InsertCountIncrementInstruction(); - -// 5.3.2 Header Acknowledgement -const QpackInstruction* HeaderAcknowledgementInstruction(); - -// 5.3.3 Stream Cancellation -const QpackInstruction* StreamCancellationInstruction(); - -// Decoder stream language. -const QpackLanguage* QpackDecoderStreamLanguage(); - -// 5.4.1. Header data prefix instructions - -const QpackInstruction* QpackPrefixInstruction(); - -const QpackLanguage* QpackPrefixLanguage(); - -// 5.4.2. Request and push stream instructions - -// 5.4.2.1. Indexed Header Field -const QpackInstruction* QpackIndexedHeaderFieldInstruction(); - -// 5.4.2.2. Indexed Header Field With Post-Base Index -const QpackInstruction* QpackIndexedHeaderFieldPostBaseInstruction(); - -// 5.4.2.3. Literal Header Field With Name Reference -const QpackInstruction* QpackLiteralHeaderFieldNameReferenceInstruction(); - -// 5.4.2.4. Literal Header Field With Post-Base Name Reference -const QpackInstruction* QpackLiteralHeaderFieldPostBaseInstruction(); - -// 5.4.2.5. Literal Header Field Without Name Reference -const QpackInstruction* QpackLiteralHeaderFieldInstruction(); - -// Request and push stream language. -const QpackLanguage* QpackRequestStreamLanguage(); - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc index 9cce57365b6..e16aa5a2de7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc @@ -8,6 +8,12 @@ namespace quic { +namespace { + +size_t kHeaderFieldSizeOverhead = 32; + +} + QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator( QuicStreamId id, QpackDecoder* qpack_decoder, @@ -15,12 +21,13 @@ QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator( size_t max_header_list_size) : decoder_(qpack_decoder->CreateProgressiveDecoder(id, this)), visitor_(visitor), - uncompressed_header_bytes_(0), + max_header_list_size_(max_header_list_size), + uncompressed_header_bytes_including_overhead_(0), + uncompressed_header_bytes_without_overhead_(0), compressed_header_bytes_(0), + header_list_size_limit_exceeded_(false), headers_decoded_(false), - blocked_(false), error_detected_(false) { - quic_header_list_.set_max_header_list_size(max_header_list_size); quic_header_list_.OnHeaderBlockStart(); } @@ -28,8 +35,21 @@ void QpackDecodedHeadersAccumulator::OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) { DCHECK(!error_detected_); - uncompressed_header_bytes_ += name.size() + value.size(); - quic_header_list_.OnHeader(name, value); + uncompressed_header_bytes_without_overhead_ += name.size() + value.size(); + + if (header_list_size_limit_exceeded_) { + return; + } + + uncompressed_header_bytes_including_overhead_ += + name.size() + value.size() + kHeaderFieldSizeOverhead; + + if (uncompressed_header_bytes_including_overhead_ > max_header_list_size_) { + header_list_size_limit_exceeded_ = true; + quic_header_list_.Clear(); + } else { + quic_header_list_.OnHeader(name, value); + } } void QpackDecodedHeadersAccumulator::OnDecodingCompleted() { @@ -37,12 +57,12 @@ void QpackDecodedHeadersAccumulator::OnDecodingCompleted() { DCHECK(!error_detected_); headers_decoded_ = true; - quic_header_list_.OnHeaderBlockEnd(uncompressed_header_bytes_, - compressed_header_bytes_); - if (blocked_) { - visitor_->OnHeadersDecoded(quic_header_list_); - } + quic_header_list_.OnHeaderBlockEnd( + uncompressed_header_bytes_without_overhead_, compressed_header_bytes_); + + // Might destroy |this|. + visitor_->OnHeadersDecoded(std::move(quic_header_list_)); } void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected( @@ -51,51 +71,24 @@ void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected( DCHECK(!headers_decoded_); error_detected_ = true; - // Copy error message to ensure it remains valid for the lifetime of |this|. - error_message_.assign(error_message.data(), error_message.size()); - - if (blocked_) { - visitor_->OnHeaderDecodingError(); - } + // Might destroy |this|. + visitor_->OnHeaderDecodingError(error_message); } -bool QpackDecodedHeadersAccumulator::Decode(QuicStringPiece data) { +void QpackDecodedHeadersAccumulator::Decode(QuicStringPiece data) { DCHECK(!error_detected_); compressed_header_bytes_ += data.size(); + // Might destroy |this|. decoder_->Decode(data); - - return !error_detected_; } -QpackDecodedHeadersAccumulator::Status -QpackDecodedHeadersAccumulator::EndHeaderBlock() { +void QpackDecodedHeadersAccumulator::EndHeaderBlock() { DCHECK(!error_detected_); DCHECK(!headers_decoded_); + // Might destroy |this|. decoder_->EndHeaderBlock(); - - if (error_detected_) { - DCHECK(!headers_decoded_); - return Status::kError; - } - - if (headers_decoded_) { - return Status::kSuccess; - } - - blocked_ = true; - return Status::kBlocked; -} - -const QuicHeaderList& QpackDecodedHeadersAccumulator::quic_header_list() const { - DCHECK(!error_detected_); - return quic_header_list_; -} - -QuicStringPiece QpackDecodedHeadersAccumulator::error_message() const { - DCHECK(error_detected_); - return error_message_; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h index c64932214dc..0a2db6a348d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h @@ -20,32 +20,30 @@ class QpackDecoder; // A class that creates and owns a QpackProgressiveDecoder instance, accumulates // decoded headers in a QuicHeaderList, and keeps track of uncompressed and -// compressed size so that it can be passed to QuicHeaderList::EndHeaderBlock(). +// compressed size so that it can be passed to +// QuicHeaderList::OnHeaderBlockEnd(). class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator : public QpackProgressiveDecoder::HeadersHandlerInterface { public: - // Return value for EndHeaderBlock(). - enum class Status { - // Headers have been successfully decoded. - kSuccess, - // An error has occurred. - kError, - // Decoding is blocked. - kBlocked - }; - - // Visitor interface used for blocked decoding. Exactly one visitor method - // will be called if EndHeaderBlock() returned kBlocked. No visitor method - // will be called if EndHeaderBlock() returned any other value. - class Visitor { + // Visitor interface to signal success or error. + // Exactly one method will be called. + // Methods may be called synchronously from Decode() and EndHeaderBlock(), + // or asynchronously. + // Method implementations are allowed to destroy |this|. + class QUIC_EXPORT_PRIVATE Visitor { public: virtual ~Visitor() = default; - // Called when headers are successfully decoded. + // Called when headers are successfully decoded. If header list size + // exceeds the limit specified via |max_header_list_size| in + // QpackDecodedHeadersAccumulator constructor, then |headers| will be empty, + // but will still have the correct compressed and uncompressed size + // information. However, header_list_size_limit_exceeded() is recommended + // instead of headers.empty() to check whether header size exceeds limit. virtual void OnHeadersDecoded(QuicHeaderList headers) = 0; // Called when an error has occurred. - virtual void OnHeaderDecodingError() = 0; + virtual void OnHeaderDecodingError(QuicStringPiece error_message) = 0; }; QpackDecodedHeadersAccumulator(QuicStreamId id, @@ -60,42 +58,48 @@ class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator void OnDecodingCompleted() override; void OnDecodingErrorDetected(QuicStringPiece error_message) override; - // Decode payload data. Returns true on success, false on error. + // Decode payload data. // Must not be called if an error has been detected. // Must not be called after EndHeaderBlock(). - bool Decode(QuicStringPiece data); + void Decode(QuicStringPiece data); // Signal end of HEADERS frame. // Must not be called if an error has been detected. // Must not be called more that once. - // Returns kSuccess if headers can be readily decoded. - // Returns kError if an error occurred. - // Returns kBlocked if headers cannot be decoded at the moment, in which case - // exactly one Visitor method will be called as soon as sufficient data - // is received on the QPACK decoder stream. - Status EndHeaderBlock(); - - // Returns accumulated header list. - const QuicHeaderList& quic_header_list() const; - - // Returns error message. - // Must not be called unless an error has been detected. - // TODO(b/124216424): Add accessor for error code, return HTTP_EXCESSIVE_LOAD - // or HTTP_QPACK_DECOMPRESSION_FAILED. - QuicStringPiece error_message() const; + void EndHeaderBlock(); + + // Returns true if the uncompressed size of the header list, including an + // overhead for each header field, exceeds |max_header_list_size| passed in + // the constructor. + bool header_list_size_limit_exceeded() const { + return header_list_size_limit_exceeded_; + } private: std::unique_ptr decoder_; Visitor* visitor_; + // Maximum header list size including overhead. + size_t max_header_list_size_; + // Uncompressed header list size including overhead, for enforcing the limit. + size_t uncompressed_header_bytes_including_overhead_; QuicHeaderList quic_header_list_; - size_t uncompressed_header_bytes_; + // Uncompressed header list size with overhead, + // for passing in to QuicHeaderList::OnHeaderBlockEnd(). + size_t uncompressed_header_bytes_without_overhead_; + // Compressed header list size + // for passing in to QuicHeaderList::OnHeaderBlockEnd(). size_t compressed_header_bytes_; - // Set to true when OnDecodingCompleted() is called. + + // True if the header size limit has been exceeded. + // Input data is still fed to QpackProgressiveDecoder. + bool header_list_size_limit_exceeded_; + + // The following two members are only used for DCHECKs. + + // True if headers have been completedly and successfully decoded. bool headers_decoded_; - // Set to true when EndHeaderBlock() returns kBlocked. - bool blocked_; + // True if an error has been detected during decoding. bool error_detected_; - std::string error_message_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc index 1d60660e9c4..6616517330f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc @@ -7,16 +7,17 @@ #include #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" +using ::testing::_; using ::testing::ElementsAre; using ::testing::Eq; using ::testing::Pair; +using ::testing::SaveArg; using ::testing::StrictMock; -using Status = quic::QpackDecodedHeadersAccumulator::Status; namespace quic { namespace test { @@ -37,15 +38,15 @@ const uint64_t kMaximumBlockedStreams = 1; // Header Acknowledgement decoder stream instruction with stream_id = 1. const char* const kHeaderAcknowledgement = "\x81"; -} // anonymous namespace - -class NoopVisitor : public QpackDecodedHeadersAccumulator::Visitor { +class MockVisitor : public QpackDecodedHeadersAccumulator::Visitor { public: - ~NoopVisitor() override = default; - void OnHeadersDecoded(QuicHeaderList /* headers */) override {} - void OnHeaderDecodingError() override {} + ~MockVisitor() override = default; + MOCK_METHOD1(OnHeadersDecoded, void(QuicHeaderList headers)); + MOCK_METHOD1(OnHeaderDecodingError, void(QuicStringPiece error_message)); }; +} // anonymous namespace + class QpackDecodedHeadersAccumulatorTest : public QuicTest { protected: QpackDecodedHeadersAccumulatorTest() @@ -63,91 +64,143 @@ class QpackDecodedHeadersAccumulatorTest : public QuicTest { NoopEncoderStreamErrorDelegate encoder_stream_error_delegate_; StrictMock decoder_stream_sender_delegate_; QpackDecoder qpack_decoder_; - NoopVisitor visitor_; + StrictMock visitor_; QpackDecodedHeadersAccumulator accumulator_; }; // HEADERS frame payload must have a complete Header Block Prefix. TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyPayload) { - EXPECT_EQ(Status::kError, accumulator_.EndHeaderBlock()); - EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message()); + EXPECT_CALL(visitor_, + OnHeaderDecodingError(Eq("Incomplete header data prefix."))); + accumulator_.EndHeaderBlock(); } // HEADERS frame payload must have a complete Header Block Prefix. TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedHeaderBlockPrefix) { - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00"))); - EXPECT_EQ(Status::kError, accumulator_.EndHeaderBlock()); - EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message()); + accumulator_.Decode(QuicTextUtils::HexDecode("00")); + + EXPECT_CALL(visitor_, + OnHeaderDecodingError(Eq("Incomplete header data prefix."))); + accumulator_.EndHeaderBlock(); } TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) { - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("0000"))); - EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock()); + std::string encoded_data(QuicTextUtils::HexDecode("0000")); + accumulator_.Decode(encoded_data); - EXPECT_TRUE(accumulator_.quic_header_list().empty()); + QuicHeaderList header_list; + EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list)); + accumulator_.EndHeaderBlock(); + EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded()); + + EXPECT_EQ(0u, header_list.uncompressed_header_bytes()); + EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes()); + EXPECT_TRUE(header_list.empty()); } // This payload is the prefix of a valid payload, but EndHeaderBlock() is called // before it can be completely decoded. TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedPayload) { - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00002366"))); - EXPECT_EQ(Status::kError, accumulator_.EndHeaderBlock()); - EXPECT_EQ("Incomplete header block.", accumulator_.error_message()); + accumulator_.Decode(QuicTextUtils::HexDecode("00002366")); + + EXPECT_CALL(visitor_, OnHeaderDecodingError(Eq("Incomplete header block."))); + accumulator_.EndHeaderBlock(); } // This payload is invalid because it refers to a non-existing static entry. TEST_F(QpackDecodedHeadersAccumulatorTest, InvalidPayload) { - EXPECT_FALSE(accumulator_.Decode(QuicTextUtils::HexDecode("0000ff23ff24"))); - EXPECT_EQ("Static table entry not found.", accumulator_.error_message()); + EXPECT_CALL(visitor_, + OnHeaderDecodingError(Eq("Static table entry not found."))); + accumulator_.Decode(QuicTextUtils::HexDecode("0000ff23ff24")); } TEST_F(QpackDecodedHeadersAccumulatorTest, Success) { std::string encoded_data(QuicTextUtils::HexDecode("000023666f6f03626172")); - EXPECT_TRUE(accumulator_.Decode(encoded_data)); - EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock()); + accumulator_.Decode(encoded_data); - const QuicHeaderList& header_list = accumulator_.quic_header_list(); - EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar"))); + QuicHeaderList header_list; + EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list)); + accumulator_.EndHeaderBlock(); + EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded()); + EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar"))); EXPECT_EQ(strlen("foo") + strlen("bar"), header_list.uncompressed_header_bytes()); EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes()); } -TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedingLimit) { +// Test that Decode() calls are not ignored after header list limit is exceeded, +// otherwise decoding could fail with "incomplete header block" error. +TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedLimitThenSplitInstruction) { // Total length of header list exceeds kMaxHeaderListSize. - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode( + accumulator_.Decode(QuicTextUtils::HexDecode( "0000" // header block prefix "26666f6f626172" // header key: "foobar" "7d61616161616161616161616161616161616161" // header value: 'a' 125 times "616161616161616161616161616161616161616161616161616161616161616161616161" "616161616161616161616161616161616161616161616161616161616161616161616161" - "61616161616161616161616161616161616161616161616161616161616161616161"))); - EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock()); + "61616161616161616161616161616161616161616161616161616161616161616161" + "ff")); // first byte of a two-byte long Indexed Header Field instruction + accumulator_.Decode(QuicTextUtils::HexDecode( + "0f" // second byte of a two-byte long Indexed Header Field instruction + )); + + EXPECT_CALL(visitor_, OnHeadersDecoded(_)); + accumulator_.EndHeaderBlock(); + EXPECT_TRUE(accumulator_.header_list_size_limit_exceeded()); +} - // QuicHeaderList signals header list over limit by clearing it. - EXPECT_TRUE(accumulator_.quic_header_list().empty()); +// Test that header list limit enforcement works with blocked encoding. +TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedLimitBlocked) { + // Total length of header list exceeds kMaxHeaderListSize. + accumulator_.Decode(QuicTextUtils::HexDecode( + "0200" // header block prefix + "80" // reference to dynamic table entry not yet received + "26666f6f626172" // header key: "foobar" + "7d61616161616161616161616161616161616161" // header value: 'a' 125 times + "616161616161616161616161616161616161616161616161616161616161616161616161" + "616161616161616161616161616161616161616161616161616161616161616161616161" + "61616161616161616161616161616161616161616161616161616161616161616161")); + accumulator_.EndHeaderBlock(); + + // Set dynamic table capacity. + qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity); + // Adding dynamic table entry unblocks decoding. + EXPECT_CALL(decoder_stream_sender_delegate_, + WriteStreamData(Eq(kHeaderAcknowledgement))); + + EXPECT_CALL(visitor_, OnHeadersDecoded(_)); + qpack_decoder_.OnInsertWithoutNameReference("foo", "bar"); + EXPECT_TRUE(accumulator_.header_list_size_limit_exceeded()); } TEST_F(QpackDecodedHeadersAccumulatorTest, BlockedDecoding) { // Reference to dynamic table entry not yet received. - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("020080"))); - EXPECT_EQ(Status::kBlocked, accumulator_.EndHeaderBlock()); + std::string encoded_data(QuicTextUtils::HexDecode("020080")); + accumulator_.Decode(encoded_data); + accumulator_.EndHeaderBlock(); // Set dynamic table capacity. qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity); // Adding dynamic table entry unblocks decoding. EXPECT_CALL(decoder_stream_sender_delegate_, WriteStreamData(Eq(kHeaderAcknowledgement))); + + QuicHeaderList header_list; + EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list)); qpack_decoder_.OnInsertWithoutNameReference("foo", "bar"); - EXPECT_THAT(accumulator_.quic_header_list(), ElementsAre(Pair("foo", "bar"))); + EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded()); + EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar"))); + EXPECT_EQ(strlen("foo") + strlen("bar"), + header_list.uncompressed_header_bytes()); + EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes()); } TEST_F(QpackDecodedHeadersAccumulatorTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) { // Reference to dynamic table entry not yet received. - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("020080"))); + accumulator_.Decode(QuicTextUtils::HexDecode("020080")); // Set dynamic table capacity. qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity); @@ -157,11 +210,34 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, // Rest of header block: same entry again. EXPECT_CALL(decoder_stream_sender_delegate_, WriteStreamData(Eq(kHeaderAcknowledgement))); - EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("80"))); - EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock()); + accumulator_.Decode(QuicTextUtils::HexDecode("80")); - EXPECT_THAT(accumulator_.quic_header_list(), - ElementsAre(Pair("foo", "bar"), Pair("foo", "bar"))); + QuicHeaderList header_list; + EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list)); + accumulator_.EndHeaderBlock(); + EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded()); + + EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar"), Pair("foo", "bar"))); +} + +// Regression test for https://crbug.com/1024263. +TEST_F(QpackDecodedHeadersAccumulatorTest, + BlockedDecodingUnblockedAndErrorBeforeEndOfHeaderBlock) { + // Required Insert Count higher than number of entries causes decoding to be + // blocked. + accumulator_.Decode(QuicTextUtils::HexDecode("0200")); + // Indexed Header Field instruction addressing dynamic table entry with + // relative index 0, absolute index 0. + accumulator_.Decode(QuicTextUtils::HexDecode("80")); + // Relative index larger than or equal to Base is invalid. + accumulator_.Decode(QuicTextUtils::HexDecode("81")); + + // Set dynamic table capacity. + qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity); + + // Adding dynamic table entry unblocks decoding. Error is detected. + EXPECT_CALL(visitor_, OnHeaderDecodingError(Eq("Invalid relative index."))); + qpack_decoder_.OnInsertWithoutNameReference("foo", "bar"); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc index 4f39e3b39b2..3ae6bce6e6b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc @@ -27,10 +27,10 @@ QpackDecoder::QpackDecoder( QpackDecoder::~QpackDecoder() {} void QpackDecoder::OnStreamReset(QuicStreamId stream_id) { - // TODO(bnc): SendStreamCancellation should not be called if maximum dynamic - // table capacity is zero. - decoder_stream_sender_.SendStreamCancellation(stream_id); - decoder_stream_sender_.Flush(); + if (header_table_.maximum_dynamic_table_capacity() > 0) { + decoder_stream_sender_.SendStreamCancellation(stream_id); + decoder_stream_sender_.Flush(); + } } bool QpackDecoder::OnStreamBlocked(QuicStreamId stream_id) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h index 113c6ea8e4a..4ac1e449bc6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h @@ -95,6 +95,11 @@ class QUIC_EXPORT_PRIVATE QpackDecoder return &encoder_stream_receiver_; } + // True if any dynamic table entries have been referenced from a header block. + bool dynamic_table_entry_referenced() const { + return header_table_.dynamic_table_entry_referenced(); + } + private: EncoderStreamErrorDelegate* const encoder_stream_error_delegate_; QpackEncoderStreamReceiver encoder_stream_receiver_; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc index 559ce433376..2ba89d48a82 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc @@ -6,7 +6,7 @@ #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h" #include "net/third_party/quiche/src/http2/decoder/decode_status.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h index 60719399d8b..396c6df8779 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h @@ -23,7 +23,7 @@ class QUIC_EXPORT_PRIVATE QpackDecoderStreamReceiver public: // An interface for handling instructions decoded from the decoder stream, see // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.3 - class Delegate { + class QUIC_EXPORT_PRIVATE Delegate { public: virtual ~Delegate() = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc index 68e4d67816c..72a446b420a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc @@ -8,7 +8,7 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { @@ -16,25 +16,19 @@ namespace quic { QpackDecoderStreamSender::QpackDecoderStreamSender() : delegate_(nullptr) {} void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) { - values_.varint = increment; - - instruction_encoder_.Encode(InsertCountIncrementInstruction(), values_, - &buffer_); + instruction_encoder_.Encode( + QpackInstructionWithValues::InsertCountIncrement(increment), &buffer_); } void QpackDecoderStreamSender::SendHeaderAcknowledgement( QuicStreamId stream_id) { - values_.varint = stream_id; - - instruction_encoder_.Encode(HeaderAcknowledgementInstruction(), values_, - &buffer_); + instruction_encoder_.Encode( + QpackInstructionWithValues::HeaderAcknowledgement(stream_id), &buffer_); } void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) { - values_.varint = stream_id; - - instruction_encoder_.Encode(StreamCancellationInstruction(), values_, - &buffer_); + instruction_encoder_.Encode( + QpackInstructionWithValues::StreamCancellation(stream_id), &buffer_); } void QpackDecoderStreamSender::Flush() { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h index 93d95d91476..d9033b04dee 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h @@ -44,7 +44,6 @@ class QUIC_EXPORT_PRIVATE QpackDecoderStreamSender { private: QpackStreamSenderDelegate* delegate_; QpackInstructionEncoder instruction_encoder_; - QpackInstructionEncoder::Values values_; std::string buffer_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc index 6e042590833..e3dc12497e3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc @@ -4,9 +4,9 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" using ::testing::Eq; using ::testing::StrictMock; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc index d0ff30ff679..1fc5802d83c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc @@ -6,14 +6,16 @@ #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +using ::testing::_; using ::testing::Eq; +using ::testing::Invoke; using ::testing::Mock; using ::testing::Sequence; using ::testing::StrictMock; @@ -42,6 +44,15 @@ class QpackDecoderTest : public QuicTestWithParam { ~QpackDecoderTest() override = default; + void SetUp() override { + // Destroy QpackProgressiveDecoder on error to test that it does not crash. + // See https://crbug.com/1025209. + ON_CALL(handler_, OnDecodingErrorDetected(_)) + .WillByDefault(Invoke([this](QuicStringPiece /* error_message */) { + progressive_decoder_.reset(); + })); + } + void DecodeEncoderStreamData(QuicStringPiece data) { qpack_decoder_.encoder_stream_receiver()->Decode(data); } @@ -61,7 +72,7 @@ class QpackDecoderTest : public QuicTestWithParam { void DecodeData(QuicStringPiece data) { auto fragment_size_generator = FragmentModeToFragmentSizeGenerator(fragment_mode_); - while (!data.empty()) { + while (progressive_decoder_ && !data.empty()) { size_t fragment_size = std::min(fragment_size_generator(), data.size()); progressive_decoder_->Decode(data.substr(0, fragment_size)); data = data.substr(fragment_size); @@ -70,9 +81,11 @@ class QpackDecoderTest : public QuicTestWithParam { // Signal end of header block to QpackProgressiveDecoder. void EndDecoding() { - progressive_decoder_->EndHeaderBlock(); - // |progressive_decoder_| is kept alive so that it can - // handle callbacks later in case of blocked decoding. + if (progressive_decoder_) { + progressive_decoder_->EndHeaderBlock(); + } + // If no error was detected, |*progressive_decoder_| is kept alive so that + // it can handle callbacks later in case of blocked decoding. } // Decode an entire header block. @@ -105,6 +118,18 @@ TEST_P(QpackDecoderTest, NoPrefix) { DecodeHeaderBlock(QuicTextUtils::HexDecode("00")); } +// Regression test for https://1025209: QpackProgressiveDecoder must not crash +// in Decode() if it is destroyed by handler_.OnDecodingErrorDetected(). +TEST_P(QpackDecoderTest, InvalidPrefix) { + StartDecoding(); + + EXPECT_CALL(handler_, + OnDecodingErrorDetected(Eq("Encoded integer too large."))); + + // Encoded Required Insert Count in Header Data Prefix is too large. + DecodeData(QuicTextUtils::HexDecode("ffffffffffffffffffffffffffff")); +} + TEST_P(QpackDecoderTest, EmptyHeaderBlock) { EXPECT_CALL(handler_, OnDecodingCompleted()); @@ -780,16 +805,15 @@ TEST_P(QpackDecoderTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) { // entry with relative index 0, absolute index 0. "d1")); // Static table entry with index 17. + // Set dynamic table capacity to 1024. + DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107")); + // Add literal entry with name "foo" and value "bar". Decoding is now // unblocked because dynamic table Insert Count reached the Required Insert // Count of the header block. |handler_| methods are called immediately for // the already consumed part of the header block. EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))); EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET"))); - - // Set dynamic table capacity to 1024. - DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107")); - // Add literal entry with name "foo" and value "bar". DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172")); Mock::VerifyAndClearExpectations(&handler_); @@ -809,6 +833,29 @@ TEST_P(QpackDecoderTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) { EndDecoding(); } +// Regression test for https://crbug.com/1024263. +TEST_P(QpackDecoderTest, + BlockedDecodingUnblockedAndErrorBeforeEndOfHeaderBlock) { + StartDecoding(); + DecodeData(QuicTextUtils::HexDecode( + "0200" // Required Insert Count 1 and Delta Base 0. + // Base is 1 + 0 = 1. + "80" // Indexed Header Field instruction addressing dynamic table + // entry with relative index 0, absolute index 0. + "81")); // Relative index 1 is equal to Base, therefore invalid. + + // Set dynamic table capacity to 1024. + DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107")); + + // Add literal entry with name "foo" and value "bar". Decoding is now + // unblocked because dynamic table Insert Count reached the Required Insert + // Count of the header block. |handler_| methods are called immediately for + // the already consumed part of the header block. + EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))); + EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index."))); + DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172")); +} + // Make sure that Required Insert Count is compared to Insert Count, // not size of dynamic table. TEST_P(QpackDecoderTest, BlockedDecodingAndEvictedEntries) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc deleted file mode 100644 index eaf66648cb0..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" - -#include -#include -#include - -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" - -namespace quic { -namespace test { - -void NoopEncoderStreamErrorDelegate::OnEncoderStreamError( - QuicStringPiece /*error_message*/) {} - -TestHeadersHandler::TestHeadersHandler() - : decoding_completed_(false), decoding_error_detected_(false) {} - -void TestHeadersHandler::OnHeaderDecoded(QuicStringPiece name, - QuicStringPiece value) { - ASSERT_FALSE(decoding_completed_); - ASSERT_FALSE(decoding_error_detected_); - - header_list_.AppendValueOrAddHeader(name, value); -} - -void TestHeadersHandler::OnDecodingCompleted() { - ASSERT_FALSE(decoding_completed_); - ASSERT_FALSE(decoding_error_detected_); - - decoding_completed_ = true; -} - -void TestHeadersHandler::OnDecodingErrorDetected( - QuicStringPiece error_message) { - ASSERT_FALSE(decoding_completed_); - ASSERT_FALSE(decoding_error_detected_); - - decoding_error_detected_ = true; - error_message_.assign(error_message.data(), error_message.size()); -} - -spdy::SpdyHeaderBlock TestHeadersHandler::ReleaseHeaderList() { - DCHECK(decoding_completed_); - DCHECK(!decoding_error_detected_); - - return std::move(header_list_); -} - -bool TestHeadersHandler::decoding_completed() const { - return decoding_completed_; -} - -bool TestHeadersHandler::decoding_error_detected() const { - return decoding_error_detected_; -} - -const std::string& TestHeadersHandler::error_message() const { - DCHECK(decoding_error_detected_); - return error_message_; -} - -void QpackDecode( - uint64_t maximum_dynamic_table_capacity, - uint64_t maximum_blocked_streams, - QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate, - QpackStreamSenderDelegate* decoder_stream_sender_delegate, - QpackProgressiveDecoder::HeadersHandlerInterface* handler, - const FragmentSizeGenerator& fragment_size_generator, - QuicStringPiece data) { - QpackDecoder decoder(maximum_dynamic_table_capacity, maximum_blocked_streams, - encoder_stream_error_delegate); - decoder.set_qpack_stream_sender_delegate(decoder_stream_sender_delegate); - auto progressive_decoder = - decoder.CreateProgressiveDecoder(/* stream_id = */ 1, handler); - while (!data.empty()) { - size_t fragment_size = std::min(fragment_size_generator(), data.size()); - progressive_decoder->Decode(data.substr(0, fragment_size)); - data = data.substr(fragment_size); - } - progressive_decoder->EndHeaderBlock(); -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h deleted file mode 100644 index 6505b60a1fe..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_ -#define QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_ - -#include - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" - -namespace quic { -namespace test { - -// QpackDecoder::EncoderStreamErrorDelegate implementation that does nothing. -class NoopEncoderStreamErrorDelegate - : public QpackDecoder::EncoderStreamErrorDelegate { - public: - ~NoopEncoderStreamErrorDelegate() override = default; - - void OnEncoderStreamError(QuicStringPiece error_message) override; -}; - -// Mock QpackDecoder::EncoderStreamErrorDelegate implementation. -class MockEncoderStreamErrorDelegate - : public QpackDecoder::EncoderStreamErrorDelegate { - public: - ~MockEncoderStreamErrorDelegate() override = default; - - MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message)); -}; - -// HeadersHandlerInterface implementation that collects decoded headers -// into a SpdyHeaderBlock. -class TestHeadersHandler - : public QpackProgressiveDecoder::HeadersHandlerInterface { - public: - TestHeadersHandler(); - ~TestHeadersHandler() override = default; - - // HeadersHandlerInterface implementation: - void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override; - void OnDecodingCompleted() override; - void OnDecodingErrorDetected(QuicStringPiece error_message) override; - - // Release decoded header list. Must only be called if decoding is complete - // and no errors have been detected. - spdy::SpdyHeaderBlock ReleaseHeaderList(); - - bool decoding_completed() const; - bool decoding_error_detected() const; - const std::string& error_message() const; - - private: - spdy::SpdyHeaderBlock header_list_; - bool decoding_completed_; - bool decoding_error_detected_; - std::string error_message_; -}; - -class MockHeadersHandler - : public QpackProgressiveDecoder::HeadersHandlerInterface { - public: - MockHeadersHandler() = default; - MockHeadersHandler(const MockHeadersHandler&) = delete; - MockHeadersHandler& operator=(const MockHeadersHandler&) = delete; - ~MockHeadersHandler() override = default; - - MOCK_METHOD2(OnHeaderDecoded, - void(QuicStringPiece name, QuicStringPiece value)); - MOCK_METHOD0(OnDecodingCompleted, void()); - MOCK_METHOD1(OnDecodingErrorDetected, void(QuicStringPiece error_message)); -}; - -class NoOpHeadersHandler - : public QpackProgressiveDecoder::HeadersHandlerInterface { - public: - ~NoOpHeadersHandler() override = default; - - void OnHeaderDecoded(QuicStringPiece /*name*/, - QuicStringPiece /*value*/) override {} - void OnDecodingCompleted() override {} - void OnDecodingErrorDetected(QuicStringPiece /*error_message*/) override {} -}; - -void QpackDecode( - uint64_t maximum_dynamic_table_capacity, - uint64_t maximum_blocked_streams, - QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate, - QpackStreamSenderDelegate* decoder_stream_sender_delegate, - QpackProgressiveDecoder::HeadersHandlerInterface* handler, - const FragmentSizeGenerator& fragment_size_generator, - QuicStringPiece data); - -} // namespace test -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc index 319af82115a..59e172ec75a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc @@ -7,7 +7,6 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h" @@ -42,47 +41,37 @@ QpackEncoder::QpackEncoder( QpackEncoder::~QpackEncoder() {} // static -QpackEncoder::InstructionWithValues QpackEncoder::EncodeIndexedHeaderField( +QpackInstructionWithValues QpackEncoder::EncodeIndexedHeaderField( bool is_static, uint64_t index, QpackBlockingManager::IndexSet* referred_indices) { - InstructionWithValues instruction{QpackIndexedHeaderFieldInstruction(), {}}; - instruction.values.s_bit = is_static; - instruction.values.varint = index; // Add |index| to |*referred_indices| only if entry is in the dynamic table. if (!is_static) { referred_indices->insert(index); } - return instruction; + return QpackInstructionWithValues::IndexedHeaderField(is_static, index); } // static -QpackEncoder::InstructionWithValues +QpackInstructionWithValues QpackEncoder::EncodeLiteralHeaderFieldWithNameReference( bool is_static, uint64_t index, QuicStringPiece value, QpackBlockingManager::IndexSet* referred_indices) { - InstructionWithValues instruction{ - QpackLiteralHeaderFieldNameReferenceInstruction(), {}}; - instruction.values.s_bit = is_static; - instruction.values.varint = index; - instruction.values.value = value; // Add |index| to |*referred_indices| only if entry is in the dynamic table. if (!is_static) { referred_indices->insert(index); } - return instruction; + return QpackInstructionWithValues::LiteralHeaderFieldNameReference( + is_static, index, value); } // static -QpackEncoder::InstructionWithValues QpackEncoder::EncodeLiteralHeaderField( +QpackInstructionWithValues QpackEncoder::EncodeLiteralHeaderField( QuicStringPiece name, QuicStringPiece value) { - InstructionWithValues instruction{QpackLiteralHeaderFieldInstruction(), {}}; - instruction.values.name = name; - instruction.values.value = value; - return instruction; + return QpackInstructionWithValues::LiteralHeaderField(name, value); } QpackEncoder::Instructions QpackEncoder::FirstPassEncode( @@ -142,6 +131,7 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode( instructions.push_back( EncodeIndexedHeaderField(is_static, index, referred_indices)); smallest_blocking_index = std::min(smallest_blocking_index, index); + header_table_.set_dynamic_table_entry_referenced(); break; } @@ -159,11 +149,10 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode( QpackAbsoluteIndexToEncoderStreamRelativeIndex( index, header_table_.inserted_entry_count())); auto entry = header_table_.InsertEntry(name, value); - blocking_manager_.OnReferenceSentOnEncoderStream( - entry->InsertionIndex(), index); instructions.push_back(EncodeIndexedHeaderField( is_static, entry->InsertionIndex(), referred_indices)); smallest_blocking_index = std::min(smallest_blocking_index, index); + header_table_.set_dynamic_table_entry_referenced(); break; } @@ -218,11 +207,10 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode( index, header_table_.inserted_entry_count()), value); auto entry = header_table_.InsertEntry(name, value); - blocking_manager_.OnReferenceSentOnEncoderStream( - entry->InsertionIndex(), index); instructions.push_back(EncodeIndexedHeaderField( is_static, entry->InsertionIndex(), referred_indices)); smallest_blocking_index = std::min(smallest_blocking_index, index); + header_table_.set_dynamic_table_entry_referenced(); break; } @@ -233,6 +221,7 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode( instructions.push_back(EncodeLiteralHeaderFieldWithNameReference( is_static, index, value, referred_indices)); smallest_blocking_index = std::min(smallest_blocking_index, index); + header_table_.set_dynamic_table_entry_referenced(); break; } @@ -329,29 +318,24 @@ std::string QpackEncoder::SecondPassEncode( std::string encoded_headers; // Header block prefix. - QpackInstructionEncoder::Values values; - values.varint = QpackEncodeRequiredInsertCount(required_insert_count, - header_table_.max_entries()); - values.varint2 = 0; // Delta Base. - values.s_bit = false; // Delta Base sign. - const uint64_t base = required_insert_count; + instruction_encoder.Encode( + QpackInstructionWithValues::Prefix(QpackEncodeRequiredInsertCount( + required_insert_count, header_table_.max_entries())), + &encoded_headers); - instruction_encoder.Encode(QpackPrefixInstruction(), values, - &encoded_headers); + const uint64_t base = required_insert_count; for (auto& instruction : instructions) { // Dynamic table references must be transformed from absolute to relative // indices. - if ((instruction.instruction == QpackIndexedHeaderFieldInstruction() || - instruction.instruction == + if ((instruction.instruction() == QpackIndexedHeaderFieldInstruction() || + instruction.instruction() == QpackLiteralHeaderFieldNameReferenceInstruction()) && - !instruction.values.s_bit) { - instruction.values.varint = - QpackAbsoluteIndexToRequestStreamRelativeIndex( - instruction.values.varint, base); + !instruction.s_bit()) { + instruction.set_varint(QpackAbsoluteIndexToRequestStreamRelativeIndex( + instruction.varint(), base)); } - instruction_encoder.Encode(instruction.instruction, instruction.values, - &encoded_headers); + instruction_encoder.Encode(instruction, &encoded_headers); } return encoded_headers; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h index 1ed56a82e11..e635e3bf04b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h @@ -14,6 +14,7 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.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_exported_stats.h" @@ -87,39 +88,35 @@ class QUIC_EXPORT_PRIVATE QpackEncoder return &decoder_stream_receiver_; } + // True if any dynamic table entries have been referenced from a header block. + bool dynamic_table_entry_referenced() const { + return header_table_.dynamic_table_entry_referenced(); + } + private: friend class test::QpackEncoderPeer; - // TODO(bnc): Consider moving this class to QpackInstructionEncoder or - // qpack_constants, adding factory methods, one for each instruction, and - // changing QpackInstructionEncoder::Encoder() to take an - // InstructionWithValues struct instead of separate |instruction| and |values| - // arguments. - struct InstructionWithValues { - // |instruction| is not owned. - const QpackInstruction* instruction; - QpackInstructionEncoder::Values values; - }; - using Instructions = std::vector; + using Instructions = std::vector; // Generate indexed header field instruction // and optionally update |*referred_indices|. - static InstructionWithValues EncodeIndexedHeaderField( + static QpackInstructionWithValues EncodeIndexedHeaderField( bool is_static, uint64_t index, QpackBlockingManager::IndexSet* referred_indices); // Generate literal header field with name reference instruction // and optionally update |*referred_indices|. - static InstructionWithValues EncodeLiteralHeaderFieldWithNameReference( + static QpackInstructionWithValues EncodeLiteralHeaderFieldWithNameReference( bool is_static, uint64_t index, QuicStringPiece value, QpackBlockingManager::IndexSet* referred_indices); // Generate literal header field instruction. - static InstructionWithValues EncodeLiteralHeaderField(QuicStringPiece name, - QuicStringPiece value); + static QpackInstructionWithValues EncodeLiteralHeaderField( + QuicStringPiece name, + QuicStringPiece value); // Performs first pass of two-pass encoding: represent each header field in // |*header_list| as a reference to an existing entry, the name of an existing diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc index 3f8ef08a7ee..c46cc3c0f41 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc @@ -6,7 +6,7 @@ #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h" #include "net/third_party/quiche/src/http2/decoder/decode_status.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h index 8da3147d1ea..b393b546b60 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h @@ -22,7 +22,7 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamReceiver public: // An interface for handling instructions decoded from the encoder stream, see // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.2 - class Delegate { + class QUIC_EXPORT_PRIVATE Delegate { public: virtual ~Delegate() = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc index 4a7f12cd3a3..5182864ce6d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc @@ -8,7 +8,7 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { @@ -19,35 +19,28 @@ void QpackEncoderStreamSender::SendInsertWithNameReference( bool is_static, uint64_t name_index, QuicStringPiece value) { - values_.s_bit = is_static; - values_.varint = name_index; - values_.value = value; - - instruction_encoder_.Encode(InsertWithNameReferenceInstruction(), values_, - &buffer_); + instruction_encoder_.Encode( + QpackInstructionWithValues::InsertWithNameReference(is_static, name_index, + value), + &buffer_); } void QpackEncoderStreamSender::SendInsertWithoutNameReference( QuicStringPiece name, QuicStringPiece value) { - values_.name = name; - values_.value = value; - - instruction_encoder_.Encode(InsertWithoutNameReferenceInstruction(), values_, - &buffer_); + instruction_encoder_.Encode( + QpackInstructionWithValues::InsertWithoutNameReference(name, value), + &buffer_); } void QpackEncoderStreamSender::SendDuplicate(uint64_t index) { - values_.varint = index; - - instruction_encoder_.Encode(DuplicateInstruction(), values_, &buffer_); + instruction_encoder_.Encode(QpackInstructionWithValues::Duplicate(index), + &buffer_); } void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) { - values_.varint = capacity; - - instruction_encoder_.Encode(SetDynamicTableCapacityInstruction(), values_, - &buffer_); + instruction_encoder_.Encode( + QpackInstructionWithValues::SetDynamicTableCapacity(capacity), &buffer_); } QuicByteCount QpackEncoderStreamSender::Flush() { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h index efbfbc632d5..de9e8f14839 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h @@ -50,7 +50,6 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender { private: QpackStreamSenderDelegate* delegate_; QpackInstructionEncoder instruction_encoder_; - QpackInstructionEncoder::Values values_; std::string buffer_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc index 80a6ed3c06f..0a42df220cb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc @@ -4,9 +4,9 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" using ::testing::Eq; using ::testing::StrictMock; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc index 6f2efe3aecc..6b92e4bfc95 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc @@ -7,13 +7,12 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" using ::testing::_; using ::testing::Eq; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc deleted file mode 100644 index d91d3d13d5e..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" - -#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" - -namespace quic { -namespace test { - -void NoopDecoderStreamErrorDelegate::OnDecoderStreamError( - QuicStringPiece /*error_message*/) {} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h deleted file mode 100644 index b1103dae6c3..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_ENCODER_TEST_UTILS_H_ -#define QUICHE_QUIC_CORE_QPACK_QPACK_ENCODER_TEST_UTILS_H_ - -#include - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" - -namespace quic { -namespace test { - -// QpackEncoder::DecoderStreamErrorDelegate implementation that does nothing. -class NoopDecoderStreamErrorDelegate - : public QpackEncoder::DecoderStreamErrorDelegate { - public: - ~NoopDecoderStreamErrorDelegate() override = default; - - void OnDecoderStreamError(QuicStringPiece error_message) override; -}; - -// Mock QpackEncoder::DecoderStreamErrorDelegate implementation. -class MockDecoderStreamErrorDelegate - : public QpackEncoder::DecoderStreamErrorDelegate { - public: - ~MockDecoderStreamErrorDelegate() override = default; - - MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message)); -}; - -} // namespace test -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QPACK_QPACK_ENCODER_TEST_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc index ff9be9a79fd..4cafa196815 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc @@ -17,7 +17,8 @@ QpackHeaderTable::QpackHeaderTable() dynamic_table_capacity_(0), maximum_dynamic_table_capacity_(0), max_entries_(0), - dropped_entry_count_(0) {} + dropped_entry_count_(0), + dynamic_table_entry_referenced_(false) {} QpackHeaderTable::~QpackHeaderTable() { for (auto& entry : observers_) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h index 78d85f6ae29..dd5ca3ba3e5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h @@ -40,7 +40,7 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { enum class MatchType { kNameAndValue, kName, kNoMatch }; // Observer interface for dynamic table insertion. - class Observer { + class QUIC_EXPORT_PRIVATE Observer { public: virtual ~Observer() = default; @@ -98,6 +98,11 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // This method must only be called at most once. void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity); + // Get |maximum_dynamic_table_capacity_|. + uint64_t maximum_dynamic_table_capacity() const { + return maximum_dynamic_table_capacity_; + } + // Register an observer to be notified when inserted_entry_count() reaches // |required_insert_count|. After the notification, |observer| automatically // gets unregistered. Each observer must only be registered at most once. @@ -130,6 +135,13 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // The returned index might not be the index of a valid entry. uint64_t draining_index(float draining_fraction) const; + void set_dynamic_table_entry_referenced() { + dynamic_table_entry_referenced_ = true; + } + bool dynamic_table_entry_referenced() const { + return dynamic_table_entry_referenced_; + } + private: friend class test::QpackHeaderTablePeer; @@ -192,6 +204,10 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // Observers waiting to be notified, sorted by required insert count. std::multimap observers_; + + // True if any dynamic table entries have been referenced from a header block. + // Set directly by the encoder or decoder. Used for stats. + bool dynamic_table_entry_referenced_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc index 187894d374e..fede8e307df 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc @@ -32,44 +32,48 @@ QpackInstructionDecoder::QpackInstructionDecoder(const QpackLanguage* language, error_detected_(false), state_(State::kStartInstruction) {} -void QpackInstructionDecoder::Decode(QuicStringPiece data) { +bool QpackInstructionDecoder::Decode(QuicStringPiece data) { DCHECK(!data.empty()); DCHECK(!error_detected_); while (true) { + bool success = true; size_t bytes_consumed = 0; switch (state_) { case State::kStartInstruction: - DoStartInstruction(data); + success = DoStartInstruction(data); break; case State::kStartField: - DoStartField(); + success = DoStartField(); break; case State::kReadBit: - DoReadBit(data); + success = DoReadBit(data); break; case State::kVarintStart: - bytes_consumed = DoVarintStart(data); + success = DoVarintStart(data, &bytes_consumed); break; case State::kVarintResume: - bytes_consumed = DoVarintResume(data); + success = DoVarintResume(data, &bytes_consumed); break; case State::kVarintDone: - DoVarintDone(); + success = DoVarintDone(); break; case State::kReadString: - bytes_consumed = DoReadString(data); + success = DoReadString(data, &bytes_consumed); break; case State::kReadStringDone: - DoReadStringDone(); + success = DoReadStringDone(); break; } - if (error_detected_) { - return; + if (!success) { + return false; } + // |success| must be false if an error is detected. + DCHECK(!error_detected_); + DCHECK_LE(bytes_consumed, data.size()); data = QuicStringPiece(data.data() + bytes_consumed, @@ -78,35 +82,37 @@ void QpackInstructionDecoder::Decode(QuicStringPiece data) { // Stop processing if no more data but next state would require it. if (data.empty() && (state_ != State::kStartField) && (state_ != State::kVarintDone) && (state_ != State::kReadStringDone)) { - return; + return true; } } + + return true; } bool QpackInstructionDecoder::AtInstructionBoundary() const { return state_ == State::kStartInstruction; } -void QpackInstructionDecoder::DoStartInstruction(QuicStringPiece data) { +bool QpackInstructionDecoder::DoStartInstruction(QuicStringPiece data) { DCHECK(!data.empty()); instruction_ = LookupOpcode(data[0]); field_ = instruction_->fields.begin(); state_ = State::kStartField; + return true; } -void QpackInstructionDecoder::DoStartField() { +bool QpackInstructionDecoder::DoStartField() { if (field_ == instruction_->fields.end()) { // Completed decoding this instruction. if (!delegate_->OnInstructionDecoded(instruction_)) { - error_detected_ = true; - return; + return false; } state_ = State::kStartInstruction; - return; + return true; } switch (field_->type) { @@ -114,15 +120,18 @@ void QpackInstructionDecoder::DoStartField() { case QpackInstructionFieldType::kName: case QpackInstructionFieldType::kValue: state_ = State::kReadBit; - return; + return true; case QpackInstructionFieldType::kVarint: case QpackInstructionFieldType::kVarint2: state_ = State::kVarintStart; - return; + return true; + default: + QUIC_BUG << "Invalid field type."; + return false; } } -void QpackInstructionDecoder::DoReadBit(QuicStringPiece data) { +bool QpackInstructionDecoder::DoReadBit(QuicStringPiece data) { DCHECK(!data.empty()); switch (field_->type) { @@ -133,7 +142,7 @@ void QpackInstructionDecoder::DoReadBit(QuicStringPiece data) { ++field_; state_ = State::kStartField; - return; + return true; } case QpackInstructionFieldType::kName: case QpackInstructionFieldType::kValue: { @@ -144,14 +153,16 @@ void QpackInstructionDecoder::DoReadBit(QuicStringPiece data) { state_ = State::kVarintStart; - return; + return true; } default: - DCHECK(false); + QUIC_BUG << "Invalid field type."; + return false; } } -size_t QpackInstructionDecoder::DoVarintStart(QuicStringPiece data) { +bool QpackInstructionDecoder::DoVarintStart(QuicStringPiece data, + size_t* bytes_consumed) { DCHECK(!data.empty()); DCHECK(field_->type == QpackInstructionFieldType::kVarint || field_->type == QpackInstructionFieldType::kVarint2 || @@ -162,24 +173,25 @@ size_t QpackInstructionDecoder::DoVarintStart(QuicStringPiece data) { http2::DecodeStatus status = varint_decoder_.Start(data[0], field_->param, &buffer); - size_t bytes_consumed = 1 + buffer.Offset(); + *bytes_consumed = 1 + buffer.Offset(); switch (status) { case http2::DecodeStatus::kDecodeDone: state_ = State::kVarintDone; - return bytes_consumed; + return true; case http2::DecodeStatus::kDecodeInProgress: state_ = State::kVarintResume; - return bytes_consumed; + return true; case http2::DecodeStatus::kDecodeError: OnError("Encoded integer too large."); - return bytes_consumed; + return false; default: QUIC_BUG << "Unknown decode status " << status; - return bytes_consumed; + return false; } } -size_t QpackInstructionDecoder::DoVarintResume(QuicStringPiece data) { +bool QpackInstructionDecoder::DoVarintResume(QuicStringPiece data, + size_t* bytes_consumed) { DCHECK(!data.empty()); DCHECK(field_->type == QpackInstructionFieldType::kVarint || field_->type == QpackInstructionFieldType::kVarint2 || @@ -189,25 +201,25 @@ size_t QpackInstructionDecoder::DoVarintResume(QuicStringPiece data) { http2::DecodeBuffer buffer(data); http2::DecodeStatus status = varint_decoder_.Resume(&buffer); - size_t bytes_consumed = buffer.Offset(); + *bytes_consumed = buffer.Offset(); switch (status) { case http2::DecodeStatus::kDecodeDone: state_ = State::kVarintDone; - return bytes_consumed; + return true; case http2::DecodeStatus::kDecodeInProgress: - DCHECK_EQ(bytes_consumed, data.size()); + DCHECK_EQ(*bytes_consumed, data.size()); DCHECK(buffer.Empty()); - return bytes_consumed; + return true; case http2::DecodeStatus::kDecodeError: OnError("Encoded integer too large."); - return bytes_consumed; + return false; default: QUIC_BUG << "Unknown decode status " << status; - return bytes_consumed; + return false; } } -void QpackInstructionDecoder::DoVarintDone() { +bool QpackInstructionDecoder::DoVarintDone() { DCHECK(field_->type == QpackInstructionFieldType::kVarint || field_->type == QpackInstructionFieldType::kVarint2 || field_->type == QpackInstructionFieldType::kName || @@ -218,7 +230,7 @@ void QpackInstructionDecoder::DoVarintDone() { ++field_; state_ = State::kStartField; - return; + return true; } if (field_->type == QpackInstructionFieldType::kVarint2) { @@ -226,13 +238,13 @@ void QpackInstructionDecoder::DoVarintDone() { ++field_; state_ = State::kStartField; - return; + return true; } string_length_ = varint_decoder_.value(); if (string_length_ > kStringLiteralLengthLimit) { OnError("String literal too long."); - return; + return false; } std::string* const string = @@ -242,15 +254,17 @@ void QpackInstructionDecoder::DoVarintDone() { if (string_length_ == 0) { ++field_; state_ = State::kStartField; - return; + return true; } string->reserve(string_length_); state_ = State::kReadString; + return true; } -size_t QpackInstructionDecoder::DoReadString(QuicStringPiece data) { +bool QpackInstructionDecoder::DoReadString(QuicStringPiece data, + size_t* bytes_consumed) { DCHECK(!data.empty()); DCHECK(field_->type == QpackInstructionFieldType::kName || field_->type == QpackInstructionFieldType::kValue); @@ -259,18 +273,17 @@ size_t QpackInstructionDecoder::DoReadString(QuicStringPiece data) { (field_->type == QpackInstructionFieldType::kName) ? &name_ : &value_; DCHECK_LT(string->size(), string_length_); - size_t bytes_consumed = - std::min(string_length_ - string->size(), data.size()); - string->append(data.data(), bytes_consumed); + *bytes_consumed = std::min(string_length_ - string->size(), data.size()); + string->append(data.data(), *bytes_consumed); DCHECK_LE(string->size(), string_length_); if (string->size() == string_length_) { state_ = State::kReadStringDone; } - return bytes_consumed; + return true; } -void QpackInstructionDecoder::DoReadStringDone() { +bool QpackInstructionDecoder::DoReadStringDone() { DCHECK(field_->type == QpackInstructionFieldType::kName || field_->type == QpackInstructionFieldType::kValue); @@ -285,13 +298,14 @@ void QpackInstructionDecoder::DoReadStringDone() { huffman_decoder_.Decode(*string, &decoded_value); if (!huffman_decoder_.InputProperlyTerminated()) { OnError("Error in Huffman-encoded string."); - return; + return false; } *string = std::move(decoded_value); } ++field_; state_ = State::kStartField; + return true; } const QpackInstruction* QpackInstructionDecoder::LookupOpcode( diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h index f478c249b07..4c217731a92 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h @@ -11,7 +11,7 @@ #include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h" #include "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -33,11 +33,15 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder { // Returns true if decoded fields are valid. // Returns false otherwise, in which case QpackInstructionDecoder stops // decoding: Delegate methods will not be called, and Decode() must not be - // called. + // called. Implementations are allowed to destroy the + // QpackInstructionDecoder instance synchronously if OnInstructionDecoded() + // returns false. virtual bool OnInstructionDecoded(const QpackInstruction* instruction) = 0; // Called by QpackInstructionDecoder if an error has occurred. // No more data is processed afterwards. + // Implementations are allowed to destroy the QpackInstructionDecoder + // instance synchronously. virtual void OnError(QuicStringPiece error_message) = 0; }; @@ -48,8 +52,9 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder { QpackInstructionDecoder& operator=(const QpackInstructionDecoder&) = delete; // Provide a data fragment to decode. Must not be called after an error has - // occurred. Must not be called with empty |data|. - void Decode(QuicStringPiece data); + // occurred. Must not be called with empty |data|. Return true on success, + // false on error (in which case Delegate::OnError() is called synchronously). + bool Decode(QuicStringPiece data); // Returns true if no decoding has taken place yet or if the last instruction // has been entirely parsed. @@ -84,18 +89,19 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder { kReadStringDone }; - // One method for each state. Some take input data and return the number of - // octets processed. Some take input data but do have void return type - // because they not consume any bytes. Some do not take any arguments because - // they only change internal state. - void DoStartInstruction(QuicStringPiece data); - void DoStartField(); - void DoReadBit(QuicStringPiece data); - size_t DoVarintStart(QuicStringPiece data); - size_t DoVarintResume(QuicStringPiece data); - void DoVarintDone(); - size_t DoReadString(QuicStringPiece data); - void DoReadStringDone(); + // One method for each state. They each return true on success, false on + // error (in which case |this| might already be destroyed). Some take input + // data and set |*bytes_consumed| to the number of octets processed. Some + // take input data but do not consume any bytes. Some do not take any + // arguments because they only change internal state. + bool DoStartInstruction(QuicStringPiece data); + bool DoStartField(); + bool DoReadBit(QuicStringPiece data); + bool DoVarintStart(QuicStringPiece data, size_t* bytes_consumed); + bool DoVarintResume(QuicStringPiece data, size_t* bytes_consumed); + bool DoVarintDone(); + bool DoReadString(QuicStringPiece data, size_t* bytes_consumed); + bool DoReadStringDone(); // Identify instruction based on opcode encoded in |byte|. // Returns a pointer to an element of |*language_|. @@ -127,8 +133,8 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder { // Decoder instance for decoding Huffman encoded strings. http2::HpackHuffmanDecoder huffman_decoder_; - // True if a decoding error has been detected either by - // QpackInstructionDecoder or by Delegate. + // True if a decoding error has been detected by QpackInstructionDecoder. + // Only used in DCHECKs. bool error_detected_; // Decoding state. diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc index 2d57f5c5320..c066827d295 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc @@ -6,15 +6,16 @@ #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" using ::testing::_; using ::testing::Eq; using ::testing::Expectation; +using ::testing::Invoke; using ::testing::Return; using ::testing::StrictMock; using ::testing::Values; @@ -64,36 +65,52 @@ class MockDelegate : public QpackInstructionDecoder::Delegate { }; class QpackInstructionDecoderTest : public QuicTestWithParam { - public: + protected: QpackInstructionDecoderTest() - : decoder_(TestLanguage(), &delegate_), fragment_mode_(GetParam()) {} + : decoder_(std::make_unique(TestLanguage(), + &delegate_)), + fragment_mode_(GetParam()) {} ~QpackInstructionDecoderTest() override = default; - protected: + void SetUp() override { + // Destroy QpackInstructionDecoder on error to test that it does not crash. + // See https://crbug.com/1025209. + ON_CALL(delegate_, OnError(_)) + .WillByDefault(Invoke( + [this](QuicStringPiece /* error_message */) { decoder_.reset(); })); + } + // Decode one full instruction with fragment sizes dictated by // |fragment_mode_|. - // Verifies that AtInstructionBoundary() returns true before and after the + // Assumes that |data| is a single complete instruction, and accordingly + // verifies that AtInstructionBoundary() returns true before and after the // instruction, and returns false while decoding is in progress. + // Assumes that delegate methods destroy |decoder_| if they return false. void DecodeInstruction(QuicStringPiece data) { - EXPECT_TRUE(decoder_.AtInstructionBoundary()); + EXPECT_TRUE(decoder_->AtInstructionBoundary()); FragmentSizeGenerator fragment_size_generator = FragmentModeToFragmentSizeGenerator(fragment_mode_); while (!data.empty()) { size_t fragment_size = std::min(fragment_size_generator(), data.size()); - decoder_.Decode(data.substr(0, fragment_size)); + bool success = decoder_->Decode(data.substr(0, fragment_size)); + if (!decoder_) { + EXPECT_FALSE(success); + return; + } + EXPECT_TRUE(success); data = data.substr(fragment_size); if (!data.empty()) { - EXPECT_FALSE(decoder_.AtInstructionBoundary()); + EXPECT_FALSE(decoder_->AtInstructionBoundary()); } } - EXPECT_TRUE(decoder_.AtInstructionBoundary()); + EXPECT_TRUE(decoder_->AtInstructionBoundary()); } StrictMock delegate_; - QpackInstructionDecoder decoder_; + std::unique_ptr decoder_; private: const FragmentMode fragment_mode_; @@ -108,60 +125,82 @@ TEST_P(QpackInstructionDecoderTest, SBitAndVarint2) { EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1())); DecodeInstruction(QuicTextUtils::HexDecode("7f01ff65")); - EXPECT_TRUE(decoder_.s_bit()); - EXPECT_EQ(64u, decoder_.varint()); - EXPECT_EQ(356u, decoder_.varint2()); + EXPECT_TRUE(decoder_->s_bit()); + EXPECT_EQ(64u, decoder_->varint()); + EXPECT_EQ(356u, decoder_->varint2()); EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1())); DecodeInstruction(QuicTextUtils::HexDecode("05c8")); - EXPECT_FALSE(decoder_.s_bit()); - EXPECT_EQ(5u, decoder_.varint()); - EXPECT_EQ(200u, decoder_.varint2()); + EXPECT_FALSE(decoder_->s_bit()); + EXPECT_EQ(5u, decoder_->varint()); + EXPECT_EQ(200u, decoder_->varint2()); } TEST_P(QpackInstructionDecoderTest, NameAndValue) { EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2())); DecodeInstruction(QuicTextUtils::HexDecode("83666f6f03626172")); - EXPECT_EQ("foo", decoder_.name()); - EXPECT_EQ("bar", decoder_.value()); + EXPECT_EQ("foo", decoder_->name()); + EXPECT_EQ("bar", decoder_->value()); EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2())); DecodeInstruction(QuicTextUtils::HexDecode("8000")); - EXPECT_EQ("", decoder_.name()); - EXPECT_EQ("", decoder_.value()); + EXPECT_EQ("", decoder_->name()); + EXPECT_EQ("", decoder_->value()); EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2())); DecodeInstruction(QuicTextUtils::HexDecode("c294e7838c767f")); - EXPECT_EQ("foo", decoder_.name()); - EXPECT_EQ("bar", decoder_.value()); + EXPECT_EQ("foo", decoder_->name()); + EXPECT_EQ("bar", decoder_->value()); } TEST_P(QpackInstructionDecoderTest, InvalidHuffmanEncoding) { EXPECT_CALL(delegate_, OnError(Eq("Error in Huffman-encoded string."))); - decoder_.Decode(QuicTextUtils::HexDecode("c1ff")); + DecodeInstruction(QuicTextUtils::HexDecode("c1ff")); } TEST_P(QpackInstructionDecoderTest, InvalidVarintEncoding) { EXPECT_CALL(delegate_, OnError(Eq("Encoded integer too large."))); - decoder_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff")); + DecodeInstruction(QuicTextUtils::HexDecode("ffffffffffffffffffffff")); } TEST_P(QpackInstructionDecoderTest, DelegateSignalsError) { // First instruction is valid. Expectation first_call = EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1())) - .WillOnce(Return(true)); + .WillOnce(Invoke( + [this](const QpackInstruction * /* instruction */) -> bool { + EXPECT_EQ(1u, decoder_->varint()); + return true; + })); + // Second instruction is invalid. Decoding must halt. EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1())) .After(first_call) - .WillOnce(Return(false)); - decoder_.Decode(QuicTextUtils::HexDecode("01000200030004000500")); + .WillOnce( + Invoke([this](const QpackInstruction * /* instruction */) -> bool { + EXPECT_EQ(2u, decoder_->varint()); + return false; + })); + + EXPECT_FALSE( + decoder_->Decode(QuicTextUtils::HexDecode("01000200030004000500"))); +} - EXPECT_EQ(2u, decoder_.varint()); +// QpackInstructionDecoder must not crash if it is destroyed from a +// Delegate::OnInstructionDecoded() call as long as it returns false. +TEST_P(QpackInstructionDecoderTest, DelegateSignalsErrorAndDestroysDecoder) { + EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1())) + .WillOnce( + Invoke([this](const QpackInstruction * /* instruction */) -> bool { + EXPECT_EQ(1u, decoder_->varint()); + decoder_.reset(); + return false; + })); + DecodeInstruction(QuicTextUtils::HexDecode("0100")); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc index 5845a748ffc..a87489d9e67 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc @@ -16,13 +16,13 @@ namespace quic { QpackInstructionEncoder::QpackInstructionEncoder() : byte_(0), state_(State::kOpcode), instruction_(nullptr) {} -void QpackInstructionEncoder::Encode(const QpackInstruction* instruction, - const Values& values, - std::string* output) { - DCHECK(instruction); +void QpackInstructionEncoder::Encode( + const QpackInstructionWithValues& instruction_with_values, + std::string* output) { + DCHECK(instruction_with_values.instruction()); state_ = State::kOpcode; - instruction_ = instruction; + instruction_ = instruction_with_values.instruction(); field_ = instruction_->fields.begin(); // Field list must not be empty. @@ -37,13 +37,15 @@ void QpackInstructionEncoder::Encode(const QpackInstruction* instruction, DoStartField(); break; case State::kSbit: - DoSBit(values.s_bit); + DoSBit(instruction_with_values.s_bit()); break; case State::kVarintEncode: - DoVarintEncode(values.varint, values.varint2, output); + DoVarintEncode(instruction_with_values.varint(), + instruction_with_values.varint2(), output); break; case State::kStartString: - DoStartString(values.name, values.value); + DoStartString(instruction_with_values.name(), + instruction_with_values.value()); break; case State::kWriteString: DoWriteString(output); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h index 1ca52e667ec..04b2888172e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h @@ -8,7 +8,7 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -19,23 +19,12 @@ namespace quic { // fields that follow each instruction. class QUIC_EXPORT_PRIVATE QpackInstructionEncoder { public: - // Storage for field values to be encoded. - // The encoded instruction determines which values are actually used. - struct Values { - bool s_bit; - uint64_t varint; - uint64_t varint2; - QuicStringPiece name; - QuicStringPiece value; - }; - QpackInstructionEncoder(); QpackInstructionEncoder(const QpackInstructionEncoder&) = delete; QpackInstructionEncoder& operator=(const QpackInstructionEncoder&) = delete; // Append encoded instruction to |output|. - void Encode(const QpackInstruction* instruction, - const Values& values, + void Encode(const QpackInstructionWithValues& instruction_with_values, std::string* output); private: diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc index 0d172cd6847..79dfe2af379 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc @@ -8,10 +8,44 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" -using ::testing::Values; - namespace quic { namespace test { + +class QpackInstructionWithValuesPeer { + public: + static QpackInstructionWithValues CreateQpackInstructionWithValues( + const QpackInstruction* instruction) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = instruction; + return instruction_with_values; + } + + static void set_s_bit(QpackInstructionWithValues* instruction_with_values, + bool s_bit) { + instruction_with_values->s_bit_ = s_bit; + } + + static void set_varint(QpackInstructionWithValues* instruction_with_values, + uint64_t varint) { + instruction_with_values->varint_ = varint; + } + + static void set_varint2(QpackInstructionWithValues* instruction_with_values, + uint64_t varint2) { + instruction_with_values->varint2_ = varint2; + } + + static void set_name(QpackInstructionWithValues* instruction_with_values, + QuicStringPiece name) { + instruction_with_values->name_ = name; + } + + static void set_value(QpackInstructionWithValues* instruction_with_values, + QuicStringPiece value) { + instruction_with_values->value_ = value; + } +}; + namespace { class QpackInstructionEncoderTest : public QuicTest { @@ -20,9 +54,9 @@ class QpackInstructionEncoderTest : public QuicTest { ~QpackInstructionEncoderTest() override = default; // Append encoded |instruction| to |output_|. - void EncodeInstruction(const QpackInstruction* instruction, - const QpackInstructionEncoder::Values& values) { - encoder_.Encode(instruction, values, &output_); + void EncodeInstruction( + const QpackInstructionWithValues& instruction_with_values) { + encoder_.Encode(instruction_with_values, &output_); } // Compare substring appended to |output_| since last EncodedSegmentMatches() @@ -44,13 +78,15 @@ TEST_F(QpackInstructionEncoderTest, Varint) { const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80}, {{QpackInstructionFieldType::kVarint, 7}}}; - QpackInstructionEncoder::Values values; - values.varint = 5; - EncodeInstruction(&instruction, values); + auto instruction_with_values = + QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues( + &instruction); + QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("05")); - values.varint = 127; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 127); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("7f00")); } @@ -61,17 +97,19 @@ TEST_F(QpackInstructionEncoderTest, SBitAndTwoVarint2) { {QpackInstructionFieldType::kVarint, 5}, {QpackInstructionFieldType::kVarint2, 8}}}; - QpackInstructionEncoder::Values values; - values.s_bit = true; - values.varint = 5; - values.varint2 = 200; - EncodeInstruction(&instruction, values); + auto instruction_with_values = + QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues( + &instruction); + QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true); + QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5); + QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 200); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("a5c8")); - values.s_bit = false; - values.varint = 31; - values.varint2 = 356; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false); + QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 31); + QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 356); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("9f00ff65")); } @@ -81,17 +119,19 @@ TEST_F(QpackInstructionEncoderTest, SBitAndVarintAndValue) { {QpackInstructionFieldType::kVarint, 5}, {QpackInstructionFieldType::kValue, 7}}}; - QpackInstructionEncoder::Values values; - values.s_bit = true; - values.varint = 100; - values.value = "foo"; - EncodeInstruction(&instruction, values); + auto instruction_with_values = + QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues( + &instruction); + QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true); + QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 100); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("ff458294e7")); - values.s_bit = false; - values.varint = 3; - values.value = "bar"; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false); + QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 3); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("c303626172")); } @@ -99,17 +139,19 @@ TEST_F(QpackInstructionEncoderTest, Name) { const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0}, {{QpackInstructionFieldType::kName, 4}}}; - QpackInstructionEncoder::Values values; - values.name = ""; - EncodeInstruction(&instruction, values); + auto instruction_with_values = + QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues( + &instruction); + QpackInstructionWithValuesPeer::set_name(&instruction_with_values, ""); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("e0")); - values.name = "foo"; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("f294e7")); - values.name = "bar"; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "bar"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("e3626172")); } @@ -117,17 +159,19 @@ TEST_F(QpackInstructionEncoderTest, Value) { const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0}, {{QpackInstructionFieldType::kValue, 3}}}; - QpackInstructionEncoder::Values values; - values.value = ""; - EncodeInstruction(&instruction, values); + auto instruction_with_values = + QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues( + &instruction); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, ""); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("f0")); - values.value = "foo"; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("fa94e7")); - values.value = "bar"; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("f3626172")); } @@ -137,17 +181,19 @@ TEST_F(QpackInstructionEncoderTest, SBitAndNameAndValue) { {QpackInstructionFieldType::kName, 2}, {QpackInstructionFieldType::kValue, 7}}}; - QpackInstructionEncoder::Values values; - values.s_bit = false; - values.name = ""; - values.value = ""; - EncodeInstruction(&instruction, values); + auto instruction_with_values = + QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues( + &instruction); + QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false); + QpackInstructionWithValuesPeer::set_name(&instruction_with_values, ""); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, ""); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("f000")); - values.s_bit = true; - values.name = "foo"; - values.value = "bar"; - EncodeInstruction(&instruction, values); + QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true); + QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo"); + QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar"); + EncodeInstruction(instruction_with_values); EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172")); } diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc new file mode 100644 index 00000000000..a6a7529bf09 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc @@ -0,0 +1,331 @@ +// Copyright 2018 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 "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" + +#include + +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +namespace { + +// Validate that +// * in each instruction, the bits of |value| that are zero in |mask| are zero; +// * every byte matches exactly one opcode. +void ValidateLangague(const QpackLanguage* language) { +#ifndef NDEBUG + for (const auto* instruction : *language) { + DCHECK_EQ(0, instruction->opcode.value & ~instruction->opcode.mask); + } + + for (uint8_t byte = 0; byte < std::numeric_limits::max(); ++byte) { + size_t match_count = 0; + for (const auto* instruction : *language) { + if ((byte & instruction->opcode.mask) == instruction->opcode.value) { + ++match_count; + } + } + DCHECK_EQ(1u, match_count) << static_cast(byte); + } +#else + (void)language; +#endif +} + +} // namespace + +bool operator==(const QpackInstructionOpcode& a, + const QpackInstructionOpcode& b) { + return std::tie(a.value, a.mask) == std::tie(b.value, b.mask); +} + +const QpackInstruction* InsertWithNameReferenceInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b10000000, 0b10000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kSbit, 0b01000000}, + {QpackInstructionFieldType::kVarint, 6}, + {QpackInstructionFieldType::kValue, 7}}}; + return instruction; +} + +const QpackInstruction* InsertWithoutNameReferenceInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b01000000, 0b11000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kName, 5}, + {QpackInstructionFieldType::kValue, 7}}}; + return instruction; +} + +const QpackInstruction* DuplicateInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00000000, 0b11100000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}}; + return instruction; +} + +const QpackInstruction* SetDynamicTableCapacityInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00100000, 0b11100000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}}; + return instruction; +} + +const QpackLanguage* QpackEncoderStreamLanguage() { + static const QpackLanguage* const language = new QpackLanguage{ + InsertWithNameReferenceInstruction(), + InsertWithoutNameReferenceInstruction(), DuplicateInstruction(), + SetDynamicTableCapacityInstruction()}; + ValidateLangague(language); + return language; +} + +const QpackInstruction* InsertCountIncrementInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00000000, 0b11000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}}; + return instruction; +} + +const QpackInstruction* HeaderAcknowledgementInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b10000000, 0b10000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 7}}}; + return instruction; +} + +const QpackInstruction* StreamCancellationInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b01000000, 0b11000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}}; + return instruction; +} + +const QpackLanguage* QpackDecoderStreamLanguage() { + static const QpackLanguage* const language = new QpackLanguage{ + InsertCountIncrementInstruction(), HeaderAcknowledgementInstruction(), + StreamCancellationInstruction()}; + ValidateLangague(language); + return language; +} + +const QpackInstruction* QpackPrefixInstruction() { + // This opcode matches every input. + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00000000, 0b00000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kVarint, 8}, + {QpackInstructionFieldType::kSbit, 0b10000000}, + {QpackInstructionFieldType::kVarint2, 7}}}; + return instruction; +} + +const QpackLanguage* QpackPrefixLanguage() { + static const QpackLanguage* const language = + new QpackLanguage{QpackPrefixInstruction()}; + ValidateLangague(language); + return language; +} + +const QpackInstruction* QpackIndexedHeaderFieldInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b10000000, 0b10000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kSbit, 0b01000000}, + {QpackInstructionFieldType::kVarint, 6}}}; + return instruction; +} + +const QpackInstruction* QpackIndexedHeaderFieldPostBaseInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00010000, 0b11110000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 4}}}; + return instruction; +} + +const QpackInstruction* QpackLiteralHeaderFieldNameReferenceInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b01000000, 0b11000000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kSbit, 0b00010000}, + {QpackInstructionFieldType::kVarint, 4}, + {QpackInstructionFieldType::kValue, 7}}}; + return instruction; +} + +const QpackInstruction* QpackLiteralHeaderFieldPostBaseInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00000000, 0b11110000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kVarint, 3}, + {QpackInstructionFieldType::kValue, 7}}}; + return instruction; +} + +const QpackInstruction* QpackLiteralHeaderFieldInstruction() { + static const QpackInstructionOpcode* const opcode = + new QpackInstructionOpcode{0b00100000, 0b11100000}; + static const QpackInstruction* const instruction = + new QpackInstruction{*opcode, + {{QpackInstructionFieldType::kName, 3}, + {QpackInstructionFieldType::kValue, 7}}}; + return instruction; +} + +const QpackLanguage* QpackRequestStreamLanguage() { + static const QpackLanguage* const language = + new QpackLanguage{QpackIndexedHeaderFieldInstruction(), + QpackIndexedHeaderFieldPostBaseInstruction(), + QpackLiteralHeaderFieldNameReferenceInstruction(), + QpackLiteralHeaderFieldPostBaseInstruction(), + QpackLiteralHeaderFieldInstruction()}; + ValidateLangague(language); + return language; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::InsertWithNameReference( + bool is_static, + uint64_t name_index, + QuicStringPiece value) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = InsertWithNameReferenceInstruction(); + instruction_with_values.s_bit_ = is_static; + instruction_with_values.varint_ = name_index; + instruction_with_values.value_ = value; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues +QpackInstructionWithValues::InsertWithoutNameReference(QuicStringPiece name, + QuicStringPiece value) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = + InsertWithoutNameReferenceInstruction(); + instruction_with_values.name_ = name; + instruction_with_values.value_ = value; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::Duplicate( + uint64_t index) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = DuplicateInstruction(); + instruction_with_values.varint_ = index; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::SetDynamicTableCapacity( + uint64_t capacity) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = SetDynamicTableCapacityInstruction(); + instruction_with_values.varint_ = capacity; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::InsertCountIncrement( + uint64_t increment) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = InsertCountIncrementInstruction(); + instruction_with_values.varint_ = increment; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::HeaderAcknowledgement( + uint64_t stream_id) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = HeaderAcknowledgementInstruction(); + instruction_with_values.varint_ = stream_id; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::StreamCancellation( + uint64_t stream_id) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = StreamCancellationInstruction(); + instruction_with_values.varint_ = stream_id; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::Prefix( + uint64_t required_insert_count) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = QpackPrefixInstruction(); + instruction_with_values.varint_ = required_insert_count; + instruction_with_values.varint2_ = 0; // Delta Base. + instruction_with_values.s_bit_ = false; // Delta Base sign. + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::IndexedHeaderField( + bool is_static, + uint64_t index) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = QpackIndexedHeaderFieldInstruction(); + instruction_with_values.s_bit_ = is_static; + instruction_with_values.varint_ = index; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues +QpackInstructionWithValues::LiteralHeaderFieldNameReference( + bool is_static, + uint64_t index, + QuicStringPiece value) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = + QpackLiteralHeaderFieldNameReferenceInstruction(); + instruction_with_values.s_bit_ = is_static; + instruction_with_values.varint_ = index; + instruction_with_values.value_ = value; + + return instruction_with_values; +} + +// static +QpackInstructionWithValues QpackInstructionWithValues::LiteralHeaderField( + QuicStringPiece name, + QuicStringPiece value) { + QpackInstructionWithValues instruction_with_values; + instruction_with_values.instruction_ = QpackLiteralHeaderFieldInstruction(); + instruction_with_values.name_ = name; + instruction_with_values.value_ = value; + + return instruction_with_values; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h new file mode 100644 index 00000000000..0ff18bff254 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h @@ -0,0 +1,207 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTIONS_H_ +#define QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTIONS_H_ + +#include +#include +#include +#include + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +namespace test { +class QpackInstructionWithValuesPeer; +} // namespace test + +// Each instruction is identified with an opcode in the first byte. +// |mask| determines which bits are part of the opcode. +// |value| is the value of these bits. (Other bits in value must be zero.) +struct QUIC_EXPORT_PRIVATE QpackInstructionOpcode { + uint8_t value; + uint8_t mask; +}; + +bool operator==(const QpackInstructionOpcode& a, + const QpackInstructionOpcode& b); + +// Possible types of an instruction field. Decoding a static bit does not +// consume the current byte. Decoding an integer or a length-prefixed string +// literal consumes all bytes containing the field value. +enum class QpackInstructionFieldType { + // A single bit indicating whether the index refers to the static table, or + // indicating the sign of Delta Base. Called "S" bit because both "static" + // and "sign" start with the letter "S". + kSbit, + // An integer encoded with variable length encoding. This could be an index, + // stream ID, maximum size, or Encoded Required Insert Count. + kVarint, + // A second integer encoded with variable length encoding. This could be + // Delta Base. + kVarint2, + // A header name or header value encoded as: + // a bit indicating whether it is Huffman encoded; + // the encoded length of the string; + // the header name or value optionally Huffman encoded. + kName, + kValue +}; + +// Each instruction field has a type and a parameter. +// The meaning of the parameter depends on the field type. +struct QUIC_EXPORT_PRIVATE QpackInstructionField { + QpackInstructionFieldType type; + // For a kSbit field, |param| is a mask with exactly one bit set. + // For kVarint fields, |param| is the prefix length of the integer encoding. + // For kName and kValue fields, |param| is the prefix length of the length of + // the string, and the bit immediately preceding the prefix is interpreted as + // the Huffman bit. + uint8_t param; +}; + +using QpackInstructionFields = std::vector; + +// A QPACK instruction consists of an opcode identifying the instruction, +// followed by a non-empty list of fields. The last field must be integer or +// string literal type to guarantee that all bytes of the instruction are +// consumed. +struct QUIC_EXPORT_PRIVATE QpackInstruction { + QpackInstruction(const QpackInstruction&) = delete; + const QpackInstruction& operator=(const QpackInstruction&) = delete; + + QpackInstructionOpcode opcode; + QpackInstructionFields fields; +}; + +// A language is a collection of instructions. The order does not matter. +// Every possible input must match exactly one instruction. +using QpackLanguage = std::vector; + +// Wire format defined in +// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5 + +// 5.2 Encoder stream instructions + +// 5.2.1 Insert With Name Reference +const QpackInstruction* InsertWithNameReferenceInstruction(); + +// 5.2.2 Insert Without Name Reference +const QpackInstruction* InsertWithoutNameReferenceInstruction(); + +// 5.2.3 Duplicate +const QpackInstruction* DuplicateInstruction(); + +// 5.2.4 Dynamic Table Size Update +const QpackInstruction* SetDynamicTableCapacityInstruction(); + +// Encoder stream language. +const QpackLanguage* QpackEncoderStreamLanguage(); + +// 5.3 Decoder stream instructions + +// 5.3.1 Insert Count Increment +const QpackInstruction* InsertCountIncrementInstruction(); + +// 5.3.2 Header Acknowledgement +const QpackInstruction* HeaderAcknowledgementInstruction(); + +// 5.3.3 Stream Cancellation +const QpackInstruction* StreamCancellationInstruction(); + +// Decoder stream language. +const QpackLanguage* QpackDecoderStreamLanguage(); + +// 5.4.1. Header data prefix instructions + +const QpackInstruction* QpackPrefixInstruction(); + +const QpackLanguage* QpackPrefixLanguage(); + +// 5.4.2. Request and push stream instructions + +// 5.4.2.1. Indexed Header Field +const QpackInstruction* QpackIndexedHeaderFieldInstruction(); + +// 5.4.2.2. Indexed Header Field With Post-Base Index +const QpackInstruction* QpackIndexedHeaderFieldPostBaseInstruction(); + +// 5.4.2.3. Literal Header Field With Name Reference +const QpackInstruction* QpackLiteralHeaderFieldNameReferenceInstruction(); + +// 5.4.2.4. Literal Header Field With Post-Base Name Reference +const QpackInstruction* QpackLiteralHeaderFieldPostBaseInstruction(); + +// 5.4.2.5. Literal Header Field Without Name Reference +const QpackInstruction* QpackLiteralHeaderFieldInstruction(); + +// Request and push stream language. +const QpackLanguage* QpackRequestStreamLanguage(); + +// Storage for instruction and field values to be encoded. +// This class can only be instantiated using factory methods that take exactly +// the arguments that the corresponding instruction needs. +class QUIC_EXPORT_PRIVATE QpackInstructionWithValues { + public: + // 5.2 Encoder stream instructions + static QpackInstructionWithValues InsertWithNameReference( + bool is_static, + uint64_t name_index, + QuicStringPiece value); + static QpackInstructionWithValues InsertWithoutNameReference( + QuicStringPiece name, + QuicStringPiece value); + static QpackInstructionWithValues Duplicate(uint64_t index); + static QpackInstructionWithValues SetDynamicTableCapacity(uint64_t capacity); + + // 5.3 Decoder stream instructions + static QpackInstructionWithValues InsertCountIncrement(uint64_t increment); + static QpackInstructionWithValues HeaderAcknowledgement(uint64_t stream_id); + static QpackInstructionWithValues StreamCancellation(uint64_t stream_id); + + // 5.4.1. Header data prefix. Delta Base is hardcoded to be zero. + static QpackInstructionWithValues Prefix(uint64_t required_insert_count); + + // 5.4.2. Request and push stream instructions + static QpackInstructionWithValues IndexedHeaderField(bool is_static, + uint64_t index); + static QpackInstructionWithValues LiteralHeaderFieldNameReference( + bool is_static, + uint64_t index, + QuicStringPiece value); + static QpackInstructionWithValues LiteralHeaderField(QuicStringPiece name, + QuicStringPiece value); + + const QpackInstruction* instruction() const { return instruction_; } + bool s_bit() const { return s_bit_; } + uint64_t varint() const { return varint_; } + uint64_t varint2() const { return varint2_; } + QuicStringPiece name() const { return name_; } + QuicStringPiece value() const { return value_; } + + // Used by QpackEncoder, because in the first pass it stores absolute indices, + // which are converted into relative indices in the second pass after base is + // determined. + void set_varint(uint64_t varint) { varint_ = varint; } + + private: + friend test::QpackInstructionWithValuesPeer; + + QpackInstructionWithValues() = default; + + // |*instruction| is not owned. + const QpackInstruction* instruction_; + bool s_bit_; + uint64_t varint_; + uint64_t varint2_; + QuicStringPiece name_; + QuicStringPiece value_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTIONS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc new file mode 100644 index 00000000000..327816e8cb2 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2018 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 +#include + +#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/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h" + +int main(int argc, char* argv[]) { + const char* usage = + "Usage: qpack_offline_decoder input_filename expected_headers_filename " + "...."; + std::vector args = + quic::QuicParseCommandLineFlags(usage, argc, argv); + + if (args.size() < 2 || args.size() % 2 != 0) { + quic::QuicPrintCommandLineFlagHelp(usage); + return 1; + } + + size_t i; + size_t success_count = 0; + for (i = 0; 2 * i < args.size(); ++i) { + const quic::QuicStringPiece input_filename(args[2 * i]); + const quic::QuicStringPiece expected_headers_filename(args[2 * i + 1]); + + // Every file represents a different connection, + // therefore every file needs a fresh decoding context. + quic::QpackOfflineDecoder decoder; + if (decoder.DecodeAndVerifyOfflineData(input_filename, + expected_headers_filename)) { + ++success_count; + } + } + + std::cout << "Processed " << i << " pairs of input files, " << success_count + << " passed, " << (i - success_count) << " failed." << std::endl; + + // Return success if all input files pass. + return (success_count == i) ? 0 : 1; +} diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc index 3c0b0f546fa..c9e19d2d013 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc @@ -8,8 +8,8 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" @@ -57,11 +57,13 @@ void QpackProgressiveDecoder::Decode(QuicStringPiece data) { while (!prefix_decoded_) { DCHECK(!blocked_); - prefix_decoder_->Decode(data.substr(0, 1)); - if (error_detected_) { + if (!prefix_decoder_->Decode(data.substr(0, 1))) { return; } + // |prefix_decoder_->Decode()| must return false if an error is detected. + DCHECK(!error_detected_); + data = data.substr(1); if (data.empty()) { return; @@ -115,20 +117,28 @@ void QpackProgressiveDecoder::OnError(QuicStringPiece error_message) { DCHECK(!error_detected_); error_detected_ = true; + // Might destroy |this|. handler_->OnDecodingErrorDetected(error_message); } void QpackProgressiveDecoder::OnInsertCountReachedThreshold() { DCHECK(blocked_); + // Clear |blocked_| before calling instruction_decoder_.Decode() below, + // because that might destroy |this| and ~QpackProgressiveDecoder() needs to + // know not to call UnregisterObserver(). + blocked_ = false; + enforcer_->OnStreamUnblocked(stream_id_); + if (!buffer_.empty()) { - instruction_decoder_.Decode(buffer_); + std::string buffer(std::move(buffer_)); buffer_.clear(); + if (!instruction_decoder_.Decode(buffer)) { + // |this| might be destroyed. + return; + } } - blocked_ = false; - enforcer_->OnStreamUnblocked(stream_id_); - if (!decoding_) { FinishDecoding(); } @@ -163,6 +173,7 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() { return false; } + header_table_->set_dynamic_table_entry_referenced(); handler_->OnHeaderDecoded(entry->name(), entry->value()); return true; } @@ -202,6 +213,7 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() { return false; } + header_table_->set_dynamic_table_entry_referenced(); handler_->OnHeaderDecoded(entry->name(), entry->value()); return true; } @@ -231,6 +243,7 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() { return false; } + header_table_->set_dynamic_table_entry_referenced(); handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value()); return true; } @@ -270,6 +283,7 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldPostBaseInstruction() { return false; } + header_table_->set_dynamic_table_entry_referenced(); handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value()); return true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h index 2f306c8e19c..6599c1a3ff8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h @@ -44,7 +44,8 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder virtual void OnDecodingCompleted() = 0; // Called when a decoding error has occurred. No other methods will be - // called afterwards. + // called afterwards. Implementations are allowed to destroy + // the QpackProgressiveDecoder instance synchronously. virtual void OnDecodingErrorDetected(QuicStringPiece error_message) = 0; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc index 567676c75d2..f0dc797fa3b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc @@ -5,15 +5,13 @@ #include #include -#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" -#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" -using ::testing::Combine; using ::testing::Values; namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc deleted file mode 100644 index 2d4a72e71b0..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" - -#include - -namespace quic { -namespace test { - -FragmentSizeGenerator FragmentModeToFragmentSizeGenerator( - FragmentMode fragment_mode) { - switch (fragment_mode) { - case FragmentMode::kSingleChunk: - return []() { return std::numeric_limits::max(); }; - case FragmentMode::kOctetByOctet: - return []() { return 1; }; - } -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h deleted file mode 100644 index 42fa383a3ea..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_TEST_UTILS_H_ -#define QUICHE_QUIC_CORE_QPACK_QPACK_TEST_UTILS_H_ - -#include -#include - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" - -namespace quic { -namespace test { - -// Called repeatedly to determine the size of each fragment when encoding or -// decoding. Must return a positive value. -using FragmentSizeGenerator = std::function; - -enum class FragmentMode { - kSingleChunk, - kOctetByOctet, -}; - -FragmentSizeGenerator FragmentModeToFragmentSizeGenerator( - FragmentMode fragment_mode); - -// Mock QpackUnidirectionalStreamSenderDelegate implementation. -class MockQpackStreamSenderDelegate : public QpackStreamSenderDelegate { - public: - ~MockQpackStreamSenderDelegate() override = default; - - MOCK_METHOD1(WriteStreamData, void(QuicStringPiece data)); -}; - -} // namespace test -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QPACK_QPACK_TEST_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h deleted file mode 100644 index 1b63422d4ac..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_ -#define QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_ - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h" - -namespace quic { -// TODO(renjietang): Move this class to qpack_test_utils.h once it is not needed -// in QuicSpdySession. -class QUIC_EXPORT_PRIVATE NoopQpackStreamSenderDelegate - : public QpackStreamSenderDelegate { - public: - ~NoopQpackStreamSenderDelegate() override = default; - - void WriteStreamData(QuicStringPiece /*data*/) override {} -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc index 03a5eb03def..bab52386512 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc @@ -60,10 +60,16 @@ TEST(ValueSplittingHeaderListTest, Comparison) { EXPECT_FALSE(it1 == it2); EXPECT_TRUE(it1 != it2); } - ++it2; + if (j < kEnd - 1) { + ASSERT_NE(it2, headers.end()); + ++it2; + } } - ++it1; + if (i < kEnd - 1) { + ASSERT_NE(it1, headers.end()); + ++it1; + } } } @@ -75,37 +81,37 @@ TEST(ValueSplittingHeaderListTest, Empty) { EXPECT_EQ(headers.begin(), headers.end()); } -struct { - const char* name; - QuicStringPiece value; - std::vector expected_values; -} kTestData[]{ - // Empty value. - {"foo", "", {""}}, - // Trivial case. - {"foo", "bar", {"bar"}}, - // Simple split. - {"foo", {"bar\0baz", 7}, {"bar", "baz"}}, - {"cookie", "foo;bar", {"foo", "bar"}}, - {"cookie", "foo; bar", {"foo", "bar"}}, - // Empty fragments with \0 separator. - {"foo", {"\0", 1}, {"", ""}}, - {"bar", {"foo\0", 4}, {"foo", ""}}, - {"baz", {"\0bar", 4}, {"", "bar"}}, - {"qux", {"\0foobar\0", 8}, {"", "foobar", ""}}, - // Empty fragments with ";" separator. - {"cookie", ";", {"", ""}}, - {"cookie", "foo;", {"foo", ""}}, - {"cookie", ";bar", {"", "bar"}}, - {"cookie", ";foobar;", {"", "foobar", ""}}, - // Empty fragments with "; " separator. - {"cookie", "; ", {"", ""}}, - {"cookie", "foo; ", {"foo", ""}}, - {"cookie", "; bar", {"", "bar"}}, - {"cookie", "; foobar; ", {"", "foobar", ""}}, -}; - TEST(ValueSplittingHeaderListTest, Split) { + struct { + const char* name; + QuicStringPiece value; + std::vector expected_values; + } kTestData[]{ + // Empty value. + {"foo", "", {""}}, + // Trivial case. + {"foo", "bar", {"bar"}}, + // Simple split. + {"foo", {"bar\0baz", 7}, {"bar", "baz"}}, + {"cookie", "foo;bar", {"foo", "bar"}}, + {"cookie", "foo; bar", {"foo", "bar"}}, + // Empty fragments with \0 separator. + {"foo", {"\0", 1}, {"", ""}}, + {"bar", {"foo\0", 4}, {"foo", ""}}, + {"baz", {"\0bar", 4}, {"", "bar"}}, + {"qux", {"\0foobar\0", 8}, {"", "foobar", ""}}, + // Empty fragments with ";" separator. + {"cookie", ";", {"", ""}}, + {"cookie", "foo;", {"foo", ""}}, + {"cookie", ";bar", {"", "bar"}}, + {"cookie", ";foobar;", {"", "foobar", ""}}, + // Empty fragments with "; " separator. + {"cookie", "; ", {"", ""}}, + {"cookie", "foo; ", {"foo", ""}}, + {"cookie", "; bar", {"", "bar"}}, + {"cookie", "; foobar; ", {"", "foobar", ""}}, + }; + for (size_t i = 0; i < QUIC_ARRAYSIZE(kTestData); ++i) { spdy::SpdyHeaderBlock block; block[kTestData[i].name] = kTestData[i].value; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr.h b/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr.h index 7c20fc7af4c..92da3dbc9de 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr.h @@ -14,12 +14,13 @@ #include // for uintptr_t #include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { template -class QuicArenaScopedPtr { +class QUIC_NO_EXPORT QuicArenaScopedPtr { static_assert(QUIC_ALIGN_OF(T*) > 1, "QuicArenaScopedPtr can only store objects that are aligned to " "greater than 1 byte."); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h new file mode 100644 index 00000000000..39eed8e6768 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h @@ -0,0 +1,744 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_ +#define QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_ + +#include +#include +#include +#include +#include +#include + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +// QuicCircularDeque is a STL-style container that is similar to std deque in +// API and std::vector in capacity management. The goal is to optimize a common +// QUIC use case where we keep adding new elements to the end and removing old +// elements from the beginning, under such scenarios, if the container's size() +// remain relatively stable, QuicCircularDeque requires little to no memory +// allocations or deallocations. +// +// The implementation, as the name suggests, uses a flat circular buffer to hold +// all elements. At any point in time, either +// a) All elements are placed in a contiguous portion of this buffer, like a +// c-array, or +// b) Elements are phycially divided into two parts: the first part occupies the +// end of the buffer and the second part occupies the beginning of the +// buffer. +// +// Currently, elements can only be pushed or poped from either ends, it can't be +// inserted or erased in the middle. +// +// TODO(wub): Make memory grow/shrink strategies customizable. +template > +class QUIC_NO_EXPORT QuicCircularDeque { + using AllocatorTraits = std::allocator_traits; + + // Pointee is either T or const T. + template + class QUIC_NO_EXPORT basic_iterator { + using size_type = typename AllocatorTraits::size_type; + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = typename AllocatorTraits::value_type; + using difference_type = typename AllocatorTraits::difference_type; + using pointer = Pointee*; + using reference = Pointee&; + + basic_iterator() = default; + + // A copy constructor if Pointee is T. + // A conversion from iterator to const_iterator if Pointee is const T. + basic_iterator( + const basic_iterator& it) // NOLINT(runtime/explicit) + : deque_(it.deque_), index_(it.index_) {} + + reference operator*() const { return *deque_->index_to_address(index_); } + pointer operator->() const { return deque_->index_to_address(index_); } + reference operator[](difference_type i) { return *(*this + i); } + + basic_iterator& operator++() { + Increment(); + return *this; + } + + basic_iterator operator++(int) { + basic_iterator result = *this; + Increment(); + return result; + } + + basic_iterator operator--() { + Decrement(); + return *this; + } + + basic_iterator operator--(int) { + basic_iterator result = *this; + Decrement(); + return result; + } + + friend basic_iterator operator+(const basic_iterator& it, + difference_type delta) { + basic_iterator result = it; + result.IncrementBy(delta); + return result; + } + + basic_iterator& operator+=(difference_type delta) { + IncrementBy(delta); + return *this; + } + + friend basic_iterator operator-(const basic_iterator& it, + difference_type delta) { + basic_iterator result = it; + result.IncrementBy(-delta); + return result; + } + + basic_iterator& operator-=(difference_type delta) { + IncrementBy(-delta); + return *this; + } + + friend difference_type operator-(const basic_iterator& lhs, + const basic_iterator& rhs) { + return lhs.ExternalPosition() - rhs.ExternalPosition(); + } + + friend bool operator==(const basic_iterator& lhs, + const basic_iterator& rhs) { + return lhs.index_ == rhs.index_; + } + + friend bool operator!=(const basic_iterator& lhs, + const basic_iterator& rhs) { + return !(lhs == rhs); + } + + friend bool operator<(const basic_iterator& lhs, + const basic_iterator& rhs) { + return lhs.ExternalPosition() < rhs.ExternalPosition(); + } + + friend bool operator<=(const basic_iterator& lhs, + const basic_iterator& rhs) { + return !(lhs > rhs); + } + + friend bool operator>(const basic_iterator& lhs, + const basic_iterator& rhs) { + return lhs.ExternalPosition() > rhs.ExternalPosition(); + } + + friend bool operator>=(const basic_iterator& lhs, + const basic_iterator& rhs) { + return !(lhs < rhs); + } + + private: + basic_iterator(const QuicCircularDeque* deque, size_type index) + : deque_(deque), index_(index) {} + + void Increment() { + DCHECK_LE(ExternalPosition() + 1, deque_->size()); + index_ = deque_->index_next(index_); + } + + void Decrement() { + DCHECK_GE(ExternalPosition(), 1u); + index_ = deque_->index_prev(index_); + } + + void IncrementBy(difference_type delta) { + if (delta >= 0) { + // After increment we are before or at end(). + DCHECK_LE(static_cast(ExternalPosition() + delta), + deque_->size()); + } else { + // After decrement we are after or at begin(). + DCHECK_GE(ExternalPosition(), static_cast(-delta)); + } + index_ = deque_->index_increment_by(index_, delta); + } + + size_type ExternalPosition() const { + if (index_ >= deque_->begin_) { + return index_ - deque_->begin_; + } + return index_ + deque_->data_capacity() - deque_->begin_; + } + + friend class QuicCircularDeque; + const QuicCircularDeque* deque_ = nullptr; + size_type index_ = 0; + }; + + public: + using allocator_type = typename AllocatorTraits::allocator_type; + using value_type = typename AllocatorTraits::value_type; + using size_type = typename AllocatorTraits::size_type; + using difference_type = typename AllocatorTraits::difference_type; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename AllocatorTraits::pointer; + using const_pointer = typename AllocatorTraits::const_pointer; + using iterator = basic_iterator; + using const_iterator = basic_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + QuicCircularDeque() : QuicCircularDeque(allocator_type()) {} + explicit QuicCircularDeque(const allocator_type& alloc) + : allocator_and_data_(alloc) {} + + QuicCircularDeque(size_type count, + const T& value, + const Allocator& alloc = allocator_type()) + : allocator_and_data_(alloc) { + resize(count, value); + } + + explicit QuicCircularDeque(size_type count, + const Allocator& alloc = allocator_type()) + : allocator_and_data_(alloc) { + resize(count); + } + + template < + class InputIt, + typename = std::enable_if_t::iterator_category>::value>> + QuicCircularDeque(InputIt first, + InputIt last, + const Allocator& alloc = allocator_type()) + : allocator_and_data_(alloc) { + AssignRange(first, last); + } + + QuicCircularDeque(const QuicCircularDeque& other) + : QuicCircularDeque( + other, + AllocatorTraits::select_on_container_copy_construction( + other.allocator_and_data_.allocator())) {} + + QuicCircularDeque(const QuicCircularDeque& other, const allocator_type& alloc) + : allocator_and_data_(alloc) { + assign(other.begin(), other.end()); + } + + QuicCircularDeque(QuicCircularDeque&& other) + : begin_(other.begin_), + end_(other.end_), + allocator_and_data_(std::move(other.allocator_and_data_)) { + other.begin_ = other.end_ = 0; + other.allocator_and_data_.data = nullptr; + other.allocator_and_data_.data_capacity = 0; + } + + QuicCircularDeque(QuicCircularDeque&& other, const allocator_type& alloc) + : allocator_and_data_(alloc) { + MoveRetainAllocator(std::move(other)); + } + + QuicCircularDeque(std::initializer_list init, + const allocator_type& alloc = allocator_type()) + : QuicCircularDeque(init.begin(), init.end(), alloc) {} + + QuicCircularDeque& operator=(const QuicCircularDeque& other) { + if (this == &other) { + return *this; + } + if (AllocatorTraits::propagate_on_container_copy_assignment::value && + (allocator_and_data_.allocator() != + other.allocator_and_data_.allocator())) { + // Destroy all current elements and blocks with the current allocator, + // before switching this to use the allocator propagated from "other". + DestroyAndDeallocateAll(); + begin_ = end_ = 0; + allocator_and_data_ = + AllocatorAndData(other.allocator_and_data_.allocator()); + } + assign(other.begin(), other.end()); + return *this; + } + + QuicCircularDeque& operator=(QuicCircularDeque&& other) { + if (this == &other) { + return *this; + } + if (AllocatorTraits::propagate_on_container_move_assignment::value) { + // Take over the storage of "other", along with its allocator. + this->~QuicCircularDeque(); + new (this) QuicCircularDeque(std::move(other)); + } else { + MoveRetainAllocator(std::move(other)); + } + return *this; + } + + ~QuicCircularDeque() { DestroyAndDeallocateAll(); } + + void assign(size_type count, const T& value) { + ClearRetainCapacity(); + reserve(count); + for (size_t i = 0; i < count; ++i) { + emplace_back(value); + } + } + + template < + class InputIt, + typename = std::enable_if_t::iterator_category>::value>> + void assign(InputIt first, InputIt last) { + AssignRange(first, last); + } + + void assign(std::initializer_list ilist) { + assign(ilist.begin(), ilist.end()); + } + + reference at(size_type pos) { + DCHECK(pos < size()) << "pos:" << pos << ", size():" << size(); + size_type index = begin_ + pos; + if (index < data_capacity()) { + return *index_to_address(index); + } + return *index_to_address(index - data_capacity()); + } + + const_reference at(size_type pos) const { + return const_cast(this)->at(pos); + } + + reference operator[](size_type pos) { return at(pos); } + + const_reference operator[](size_type pos) const { return at(pos); } + + reference front() { + DCHECK(!empty()); + return *index_to_address(begin_); + } + + const_reference front() const { + return const_cast(this)->front(); + } + + reference back() { + DCHECK(!empty()); + return *(index_to_address(end_ == 0 ? data_capacity() - 1 : end_ - 1)); + } + + const_reference back() const { + return const_cast(this)->back(); + } + + iterator begin() { return iterator(this, begin_); } + const_iterator begin() const { return const_iterator(this, begin_); } + const_iterator cbegin() const { return const_iterator(this, begin_); } + + iterator end() { return iterator(this, end_); } + const_iterator end() const { return const_iterator(this, end_); } + const_iterator cend() const { return const_iterator(this, end_); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { return rbegin(); } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { return rend(); } + + size_type capacity() const { + return data_capacity() == 0 ? 0 : data_capacity() - 1; + } + + void reserve(size_type new_cap) { + if (new_cap > capacity()) { + Relocate(new_cap); + } + } + + // Remove all elements. Leave capacity unchanged. + void clear() { ClearRetainCapacity(); } + + bool empty() const { return begin_ == end_; } + + size_type size() const { + if (begin_ <= end_) { + return end_ - begin_; + } + return data_capacity() + end_ - begin_; + } + + void resize(size_type count) { ResizeInternal(count); } + + void resize(size_type count, const value_type& value) { + ResizeInternal(count, value); + } + + void push_front(const T& value) { emplace_front(value); } + void push_front(T&& value) { emplace_front(std::move(value)); } + + template + reference emplace_front(Args&&... args) { + MaybeExpandCapacity(1); + begin_ = index_prev(begin_); + new (index_to_address(begin_)) T(std::forward(args)...); + return front(); + } + + void push_back(const T& value) { emplace_back(value); } + void push_back(T&& value) { emplace_back(std::move(value)); } + + template + reference emplace_back(Args&&... args) { + MaybeExpandCapacity(1); + new (index_to_address(end_)) T(std::forward(args)...); + end_ = index_next(end_); + return back(); + } + + void pop_front() { + DCHECK(!empty()); + DestroyByIndex(begin_); + begin_ = index_next(begin_); + MaybeShrinkCapacity(); + } + + size_type pop_front_n(size_type count) { + size_type num_elements_to_pop = std::min(count, size()); + size_type new_begin = index_increment_by(begin_, num_elements_to_pop); + DestroyRange(begin_, new_begin); + begin_ = new_begin; + MaybeShrinkCapacity(); + return num_elements_to_pop; + } + + void pop_back() { + DCHECK(!empty()); + end_ = index_prev(end_); + DestroyByIndex(end_); + MaybeShrinkCapacity(); + } + + size_type pop_back_n(size_type count) { + size_type num_elements_to_pop = std::min(count, size()); + size_type new_end = index_increment_by(end_, -num_elements_to_pop); + DestroyRange(new_end, end_); + end_ = new_end; + MaybeShrinkCapacity(); + return num_elements_to_pop; + } + + void swap(QuicCircularDeque& other) { + using std::swap; + swap(begin_, other.begin_); + swap(end_, other.end_); + + if (AllocatorTraits::propagate_on_container_swap::value) { + swap(allocator_and_data_, other.allocator_and_data_); + } else { + // When propagate_on_container_swap is false, it is undefined behavior, by + // c++ standard, to swap between two AllocatorAwareContainer(s) with + // unequal allocators. + DCHECK(get_allocator() == other.get_allocator()) + << "Undefined swap behavior"; + swap(allocator_and_data_.data, other.allocator_and_data_.data); + swap(allocator_and_data_.data_capacity, + other.allocator_and_data_.data_capacity); + } + } + + friend void swap(QuicCircularDeque& lhs, QuicCircularDeque& rhs) { + lhs.swap(rhs); + } + + allocator_type get_allocator() const { + return allocator_and_data_.allocator(); + } + + friend bool operator==(const QuicCircularDeque& lhs, + const QuicCircularDeque& rhs) { + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + friend bool operator!=(const QuicCircularDeque& lhs, + const QuicCircularDeque& rhs) { + return !(lhs == rhs); + } + + friend QUIC_NO_EXPORT std::ostream& operator<<(std::ostream& os, + const QuicCircularDeque& dq) { + os << "{"; + for (size_type pos = 0; pos != dq.size(); ++pos) { + if (pos != 0) { + os << ","; + } + os << " " << dq[pos]; + } + os << " }"; + return os; + } + + private: + void MoveRetainAllocator(QuicCircularDeque&& other) { + if (get_allocator() == other.get_allocator()) { + // Take over the storage of "other", with which we share an allocator. + DestroyAndDeallocateAll(); + + begin_ = other.begin_; + end_ = other.end_; + allocator_and_data_.data = other.allocator_and_data_.data; + allocator_and_data_.data_capacity = + other.allocator_and_data_.data_capacity; + + other.begin_ = other.end_ = 0; + other.allocator_and_data_.data = nullptr; + other.allocator_and_data_.data_capacity = 0; + } else { + // We cannot take over of the storage from "other", since it has a + // different allocator; we're stuck move-assigning elements individually. + ClearRetainCapacity(); + for (auto& elem : other) { + push_back(std::move(elem)); + } + other.clear(); + } + } + + template < + typename InputIt, + typename = std::enable_if_t::iterator_category>::value>> + void AssignRange(InputIt first, InputIt last) { + ClearRetainCapacity(); + if (std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits::iterator_category>::value) { + reserve(std::distance(first, last)); + } + for (; first != last; ++first) { + emplace_back(*first); + } + } + + // WARNING: begin_, end_ and allocator_and_data_ are not modified. + void DestroyAndDeallocateAll() { + DestroyRange(begin_, end_); + + if (data_capacity() > 0) { + DCHECK_NE(nullptr, allocator_and_data_.data); + AllocatorTraits::deallocate(allocator_and_data_.allocator(), + allocator_and_data_.data, data_capacity()); + } + } + + void ClearRetainCapacity() { + DestroyRange(begin_, end_); + begin_ = end_ = 0; + } + + void MaybeShrinkCapacity() { + // TODO(wub): Implement a storage policy that actually shrinks. + } + + void MaybeExpandCapacity(size_t num_additional_elements) { + size_t new_size = size() + num_additional_elements; + if (capacity() >= new_size) { + return; + } + + // The minimum amount of additional capacity to grow. + size_t min_additional_capacity = + std::max(MinCapacityIncrement, capacity() / 4); + size_t new_capacity = + std::max(new_size, capacity() + min_additional_capacity); + + Relocate(new_capacity); + } + + void Relocate(size_t new_capacity) { + const size_t num_elements = size(); + DCHECK_GT(new_capacity, num_elements) + << "new_capacity:" << new_capacity << ", num_elements:" << num_elements; + + size_t new_data_capacity = new_capacity + 1; + pointer new_data = AllocatorTraits::allocate( + allocator_and_data_.allocator(), new_data_capacity); + + if (begin_ <= end_) { + // Not wrapped. + RelocateUnwrappedRange(begin_, end_, new_data); + } else { + // Wrapped. + const size_t num_elements_before_wrap = data_capacity() - begin_; + RelocateUnwrappedRange(begin_, data_capacity(), new_data); + RelocateUnwrappedRange(0, end_, new_data + num_elements_before_wrap); + } + + if (data_capacity()) { + AllocatorTraits::deallocate(allocator_and_data_.allocator(), + allocator_and_data_.data, data_capacity()); + } + + allocator_and_data_.data = new_data; + allocator_and_data_.data_capacity = new_data_capacity; + begin_ = 0; + end_ = num_elements; + } + + template + typename std::enable_if::value, void>::type + RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const { + DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end; + memcpy(dest, index_to_address(begin), sizeof(T) * (end - begin)); + DestroyRange(begin, end); + } + + template + typename std::enable_if::value && + std::is_move_constructible::value, + void>::type + RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const { + DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end; + pointer src = index_to_address(begin); + pointer src_end = index_to_address(end); + while (src != src_end) { + new (dest) T(std::move(*src)); + DestroyByAddress(src); + ++dest; + ++src; + } + } + + template + typename std::enable_if::value && + !std::is_move_constructible::value, + void>::type + RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const { + DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end; + pointer src = index_to_address(begin); + pointer src_end = index_to_address(end); + while (src != src_end) { + new (dest) T(*src); + DestroyByAddress(src); + ++dest; + ++src; + } + } + + template + void ResizeInternal(size_type count, U&&... u) { + if (count > size()) { + // Expanding. + MaybeExpandCapacity(count - size()); + while (size() < count) { + emplace_back(std::forward(u)...); + } + } else { + // Most likely shrinking. No-op if count == size(). + size_type new_end = (begin_ + count) % data_capacity(); + DestroyRange(new_end, end_); + end_ = new_end; + + MaybeShrinkCapacity(); + } + } + + void DestroyRange(size_type begin, size_type end) const { + if (std::is_trivially_destructible::value) { + return; + } + if (end >= begin) { + DestroyUnwrappedRange(begin, end); + } else { + DestroyUnwrappedRange(begin, data_capacity()); + DestroyUnwrappedRange(0, end); + } + } + + // Should only be called from DestroyRange. + void DestroyUnwrappedRange(size_type begin, size_type end) const { + DCHECK_LE(begin, end) << "begin:" << begin << ", end:" << end; + for (; begin != end; ++begin) { + DestroyByIndex(begin); + } + } + + void DestroyByIndex(size_type index) const { + DestroyByAddress(index_to_address(index)); + } + + void DestroyByAddress(pointer address) const { + if (std::is_trivially_destructible::value) { + return; + } + address->~T(); + } + + size_type data_capacity() const { return allocator_and_data_.data_capacity; } + + pointer index_to_address(size_type index) const { + return allocator_and_data_.data + index; + } + + size_type index_prev(size_type index) const { + return index == 0 ? data_capacity() - 1 : index - 1; + } + + size_type index_next(size_type index) const { + return index == data_capacity() - 1 ? 0 : index + 1; + } + + size_type index_increment_by(size_type index, difference_type delta) const { + if (delta == 0) { + return index; + } + + DCHECK_LT(static_cast(std::abs(delta)), data_capacity()); + return (index + data_capacity() + delta) % data_capacity(); + } + + // Empty base-class optimization: bundle storage for our allocator together + // with the fields we had to store anyway, via inheriting from the allocator, + // so this allocator instance doesn't consume any storage when its type has no + // data members. + struct AllocatorAndData : private allocator_type { + explicit AllocatorAndData(const allocator_type& alloc) + : allocator_type(alloc) {} + + const allocator_type& allocator() const { return *this; } + allocator_type& allocator() { return *this; } + + pointer data = nullptr; + size_type data_capacity = 0; + }; + + size_type begin_ = 0; + size_type end_ = 0; + AllocatorAndData allocator_and_data_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc new file mode 100644 index 00000000000..c1658985a48 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc @@ -0,0 +1,790 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h" + +#include +#include +#include +#include + +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +using testing::ElementsAre; + +namespace quic { +namespace test { + +template class BaseAllocator = std::allocator> +class CountingAllocator : public BaseAllocator { + typedef BaseAllocator BaseType; + + public: + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; + + T* allocate(std::size_t n) { + ++shared_counts_->allocate_count; + return BaseType::allocate(n); + } + + void deallocate(T* ptr, std::size_t n) { + ++shared_counts_->deallocate_count; + return BaseType::deallocate(ptr, n); + } + + size_t allocate_count() const { return shared_counts_->allocate_count; } + + size_t deallocate_count() const { return shared_counts_->deallocate_count; } + + friend bool operator==(const CountingAllocator& lhs, + const CountingAllocator& rhs) { + return lhs.shared_counts_ == rhs.shared_counts_; + } + + friend bool operator!=(const CountingAllocator& lhs, + const CountingAllocator& rhs) { + return !(lhs == rhs); + } + + private: + struct Counts { + size_t allocate_count = 0; + size_t deallocate_count = 0; + }; + + std::shared_ptr shared_counts_ = std::make_shared(); +}; + +template class BaseAllocator = std::allocator> +struct ConfigurableAllocator : public BaseAllocator { + using propagate_on_container_copy_assignment = propagate_on_copy_assignment; + using propagate_on_container_move_assignment = propagate_on_move_assignment; + using propagate_on_container_swap = propagate_on_swap; + + friend bool operator==(const ConfigurableAllocator& /*lhs*/, + const ConfigurableAllocator& /*rhs*/) { + return equality_result; + } + + friend bool operator!=(const ConfigurableAllocator& lhs, + const ConfigurableAllocator& rhs) { + return !(lhs == rhs); + } +}; + +// [1, 2, 3, 4] ==> [4, 1, 2, 3] +template +void ShiftRight(Deque* dq, bool emplace) { + auto back = *(&dq->back()); + dq->pop_back(); + if (emplace) { + dq->emplace_front(back); + } else { + dq->push_front(back); + } +} + +// [1, 2, 3, 4] ==> [2, 3, 4, 1] +template +void ShiftLeft(Deque* dq, bool emplace) { + auto front = *(&dq->front()); + dq->pop_front(); + if (emplace) { + dq->emplace_back(front); + } else { + dq->push_back(front); + } +} + +TEST(QuicCircularDeque, Empty) { + QuicCircularDeque dq; + EXPECT_TRUE(dq.empty()); + EXPECT_EQ(0u, dq.size()); + dq.clear(); + dq.push_back(10); + EXPECT_FALSE(dq.empty()); + EXPECT_EQ(1u, dq.size()); + EXPECT_EQ(10, dq.front()); + EXPECT_EQ(10, dq.back()); + dq.pop_front(); + EXPECT_TRUE(dq.empty()); + EXPECT_EQ(0u, dq.size()); + + EXPECT_QUIC_DEBUG_DEATH(dq.front(), ""); + EXPECT_QUIC_DEBUG_DEATH(dq.back(), ""); + EXPECT_QUIC_DEBUG_DEATH(dq.at(0), ""); + EXPECT_QUIC_DEBUG_DEATH(dq[0], ""); +} + +TEST(QuicCircularDeque, Constructor) { + QuicCircularDeque dq; + EXPECT_TRUE(dq.empty()); + + std::allocator alloc; + QuicCircularDeque dq1(alloc); + EXPECT_TRUE(dq1.empty()); + + QuicCircularDeque dq2(8, 100, alloc); + EXPECT_THAT(dq2, ElementsAre(100, 100, 100, 100, 100, 100, 100, 100)); + + QuicCircularDeque dq3(5, alloc); + EXPECT_THAT(dq3, ElementsAre(0, 0, 0, 0, 0)); + + QuicCircularDeque dq4_rand_iter(dq3.begin(), dq3.end(), alloc); + EXPECT_THAT(dq4_rand_iter, ElementsAre(0, 0, 0, 0, 0)); + EXPECT_EQ(dq4_rand_iter, dq3); + + std::list dq4_src = {4, 4, 4, 4}; + QuicCircularDeque dq4_bidi_iter(dq4_src.begin(), dq4_src.end()); + EXPECT_THAT(dq4_bidi_iter, ElementsAre(4, 4, 4, 4)); + + QuicCircularDeque dq5(dq4_bidi_iter); + EXPECT_THAT(dq5, ElementsAre(4, 4, 4, 4)); + EXPECT_EQ(dq5, dq4_bidi_iter); + + QuicCircularDeque dq6(dq5, alloc); + EXPECT_THAT(dq6, ElementsAre(4, 4, 4, 4)); + EXPECT_EQ(dq6, dq5); + + QuicCircularDeque dq7(std::move(*&dq6)); + EXPECT_THAT(dq7, ElementsAre(4, 4, 4, 4)); + EXPECT_TRUE(dq6.empty()); + + QuicCircularDeque dq8_equal_allocator(std::move(*&dq7), alloc); + EXPECT_THAT(dq8_equal_allocator, ElementsAre(4, 4, 4, 4)); + EXPECT_TRUE(dq7.empty()); + + QuicCircularDeque> dq8_temp = {5, 6, 7, 8, 9}; + QuicCircularDeque> dq8_unequal_allocator( + std::move(*&dq8_temp), CountingAllocator()); + EXPECT_THAT(dq8_unequal_allocator, ElementsAre(5, 6, 7, 8, 9)); + EXPECT_TRUE(dq8_temp.empty()); + + QuicCircularDeque dq9({3, 4, 5, 6, 7}, alloc); + EXPECT_THAT(dq9, ElementsAre(3, 4, 5, 6, 7)); +} + +TEST(QuicCircularDeque, Assign) { + // assign() + QuicCircularDeque> dq; + dq.assign(7, 1); + EXPECT_THAT(dq, ElementsAre(1, 1, 1, 1, 1, 1, 1)); + EXPECT_EQ(1u, dq.get_allocator().allocate_count()); + + QuicCircularDeque> dq2; + dq2.assign(dq.begin(), dq.end()); + EXPECT_THAT(dq2, ElementsAre(1, 1, 1, 1, 1, 1, 1)); + EXPECT_EQ(1u, dq2.get_allocator().allocate_count()); + EXPECT_TRUE(std::equal(dq.begin(), dq.end(), dq2.begin(), dq2.end())); + + dq2.assign({2, 2, 2, 2, 2, 2}); + EXPECT_THAT(dq2, ElementsAre(2, 2, 2, 2, 2, 2)); + + // Assign from a non random access iterator. + std::list dq3_src = {3, 3, 3, 3, 3}; + QuicCircularDeque> dq3; + dq3.assign(dq3_src.begin(), dq3_src.end()); + EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3)); + EXPECT_LT(1u, dq3.get_allocator().allocate_count()); + + // Copy assignment + dq3 = *&dq3; + EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3)); + + QuicCircularDeque< + int, 3, + ConfigurableAllocator> + dq4, dq5; + dq4.assign(dq3.begin(), dq3.end()); + dq5 = dq4; + EXPECT_THAT(dq5, ElementsAre(3, 3, 3, 3, 3)); + + QuicCircularDeque< + int, 3, + ConfigurableAllocator> + dq6, dq7; + dq6.assign(dq3.begin(), dq3.end()); + dq7 = dq6; + EXPECT_THAT(dq7, ElementsAre(3, 3, 3, 3, 3)); + + // Move assignment + dq3 = std::move(*&dq3); + EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3)); + + ASSERT_TRUE(decltype( + dq3.get_allocator())::propagate_on_container_move_assignment::value); + decltype(dq3) dq8; + dq8 = std::move(*&dq3); + EXPECT_THAT(dq8, ElementsAre(3, 3, 3, 3, 3)); + EXPECT_TRUE(dq3.empty()); + + QuicCircularDeque< + int, 3, + ConfigurableAllocator> + dq9, dq10; + dq9.assign(dq8.begin(), dq8.end()); + dq10.assign(dq2.begin(), dq2.end()); + dq9 = std::move(*&dq10); + EXPECT_THAT(dq9, ElementsAre(2, 2, 2, 2, 2, 2)); + EXPECT_TRUE(dq10.empty()); + + QuicCircularDeque< + int, 3, + ConfigurableAllocator> + dq11, dq12; + dq11.assign(dq8.begin(), dq8.end()); + dq12.assign(dq2.begin(), dq2.end()); + dq11 = std::move(*&dq12); + EXPECT_THAT(dq11, ElementsAre(2, 2, 2, 2, 2, 2)); + EXPECT_TRUE(dq12.empty()); +} + +TEST(QuicCircularDeque, Access) { + // at() + // operator[] + // front() + // back() + + QuicCircularDeque> dq; + dq.push_back(10); + EXPECT_EQ(dq.front(), 10); + EXPECT_EQ(dq.back(), 10); + EXPECT_EQ(dq.at(0), 10); + EXPECT_EQ(dq[0], 10); + dq.front() = 12; + EXPECT_EQ(dq.front(), 12); + EXPECT_EQ(dq.back(), 12); + EXPECT_EQ(dq.at(0), 12); + EXPECT_EQ(dq[0], 12); + + const auto& dqref = dq; + EXPECT_EQ(dqref.front(), 12); + EXPECT_EQ(dqref.back(), 12); + EXPECT_EQ(dqref.at(0), 12); + EXPECT_EQ(dqref[0], 12); + + dq.pop_front(); + EXPECT_TRUE(dqref.empty()); + + // Push to capacity. + dq.push_back(15); + dq.push_front(5); + dq.push_back(25); + EXPECT_EQ(dq.size(), dq.capacity()); + EXPECT_THAT(dq, ElementsAre(5, 15, 25)); + EXPECT_LT(&dq.front(), &dq.back()); + EXPECT_EQ(dq.front(), 5); + EXPECT_EQ(dq.back(), 25); + EXPECT_EQ(dq.at(0), 5); + EXPECT_EQ(dq.at(1), 15); + EXPECT_EQ(dq.at(2), 25); + EXPECT_EQ(dq[0], 5); + EXPECT_EQ(dq[1], 15); + EXPECT_EQ(dq[2], 25); + + // Shift right such that begin=1 and end=0. Data is still not wrapped. + dq.pop_front(); + dq.push_back(35); + EXPECT_THAT(dq, ElementsAre(15, 25, 35)); + EXPECT_LT(&dq.front(), &dq.back()); + EXPECT_EQ(dq.front(), 15); + EXPECT_EQ(dq.back(), 35); + EXPECT_EQ(dq.at(0), 15); + EXPECT_EQ(dq.at(1), 25); + EXPECT_EQ(dq.at(2), 35); + EXPECT_EQ(dq[0], 15); + EXPECT_EQ(dq[1], 25); + EXPECT_EQ(dq[2], 35); + + // Shift right such that data is wrapped. + dq.pop_front(); + dq.push_back(45); + EXPECT_THAT(dq, ElementsAre(25, 35, 45)); + EXPECT_GT(&dq.front(), &dq.back()); + EXPECT_EQ(dq.front(), 25); + EXPECT_EQ(dq.back(), 45); + EXPECT_EQ(dq.at(0), 25); + EXPECT_EQ(dq.at(1), 35); + EXPECT_EQ(dq.at(2), 45); + EXPECT_EQ(dq[0], 25); + EXPECT_EQ(dq[1], 35); + EXPECT_EQ(dq[2], 45); + + // Shift right again, data is still wrapped. + dq.pop_front(); + dq.push_back(55); + EXPECT_THAT(dq, ElementsAre(35, 45, 55)); + EXPECT_GT(&dq.front(), &dq.back()); + EXPECT_EQ(dq.front(), 35); + EXPECT_EQ(dq.back(), 55); + EXPECT_EQ(dq.at(0), 35); + EXPECT_EQ(dq.at(1), 45); + EXPECT_EQ(dq.at(2), 55); + EXPECT_EQ(dq[0], 35); + EXPECT_EQ(dq[1], 45); + EXPECT_EQ(dq[2], 55); + + // Shift right one last time. begin returns to 0. Data is no longer wrapped. + dq.pop_front(); + dq.push_back(65); + EXPECT_THAT(dq, ElementsAre(45, 55, 65)); + EXPECT_LT(&dq.front(), &dq.back()); + EXPECT_EQ(dq.front(), 45); + EXPECT_EQ(dq.back(), 65); + EXPECT_EQ(dq.at(0), 45); + EXPECT_EQ(dq.at(1), 55); + EXPECT_EQ(dq.at(2), 65); + EXPECT_EQ(dq[0], 45); + EXPECT_EQ(dq[1], 55); + EXPECT_EQ(dq[2], 65); + + EXPECT_EQ(1u, dq.get_allocator().allocate_count()); +} + +TEST(QuicCircularDeque, Iterate) { + QuicCircularDeque dq; + EXPECT_EQ(dq.begin(), dq.end()); + EXPECT_EQ(dq.cbegin(), dq.cend()); + EXPECT_EQ(dq.rbegin(), dq.rend()); + EXPECT_EQ(dq.crbegin(), dq.crend()); + + dq.emplace_back(2); + QuicCircularDeque::const_iterator citer = dq.begin(); + EXPECT_NE(citer, dq.end()); + EXPECT_EQ(*citer, 2); + ++citer; + EXPECT_EQ(citer, dq.end()); + + EXPECT_EQ(*dq.begin(), 2); + EXPECT_EQ(*dq.cbegin(), 2); + EXPECT_EQ(*dq.rbegin(), 2); + EXPECT_EQ(*dq.crbegin(), 2); + + dq.emplace_front(1); + QuicCircularDeque::const_reverse_iterator criter = dq.rbegin(); + EXPECT_NE(criter, dq.rend()); + EXPECT_EQ(*criter, 2); + ++criter; + EXPECT_NE(criter, dq.rend()); + EXPECT_EQ(*criter, 1); + ++criter; + EXPECT_EQ(criter, dq.rend()); + + EXPECT_EQ(*dq.begin(), 1); + EXPECT_EQ(*dq.cbegin(), 1); + EXPECT_EQ(*dq.rbegin(), 2); + EXPECT_EQ(*dq.crbegin(), 2); + + dq.push_back(3); + + // Forward iterate. + int expected_value = 1; + for (QuicCircularDeque::iterator it = dq.begin(); it != dq.end(); ++it) { + EXPECT_EQ(expected_value++, *it); + } + + expected_value = 1; + for (QuicCircularDeque::const_iterator it = dq.cbegin(); it != dq.cend(); + ++it) { + EXPECT_EQ(expected_value++, *it); + } + + // Reverse iterate. + expected_value = 3; + for (QuicCircularDeque::reverse_iterator it = dq.rbegin(); + it != dq.rend(); ++it) { + EXPECT_EQ(expected_value--, *it); + } + + expected_value = 3; + for (QuicCircularDeque::const_reverse_iterator it = dq.crbegin(); + it != dq.crend(); ++it) { + EXPECT_EQ(expected_value--, *it); + } +} + +TEST(QuicCircularDeque, Iterator) { + // Default constructed iterators of the same type compare equal. + EXPECT_EQ(QuicCircularDeque::iterator(), + QuicCircularDeque::iterator()); + EXPECT_EQ(QuicCircularDeque::const_iterator(), + QuicCircularDeque::const_iterator()); + EXPECT_EQ(QuicCircularDeque::reverse_iterator(), + QuicCircularDeque::reverse_iterator()); + EXPECT_EQ(QuicCircularDeque::const_reverse_iterator(), + QuicCircularDeque::const_reverse_iterator()); + + QuicCircularDeque, 3> dqdq = { + {1, 2}, {10, 20, 30}, {100, 200, 300, 400}}; + + // iter points to {1, 2} + decltype(dqdq)::iterator iter = dqdq.begin(); + EXPECT_EQ(iter->size(), 2u); + EXPECT_THAT(*iter, ElementsAre(1, 2)); + + // citer points to {10, 20, 30} + decltype(dqdq)::const_iterator citer = dqdq.cbegin() + 1; + EXPECT_NE(*iter, *citer); + EXPECT_EQ(citer->size(), 3u); + int x = 10; + for (auto it = citer->begin(); it != citer->end(); ++it) { + EXPECT_EQ(*it, x); + x += 10; + } + + EXPECT_LT(iter, citer); + EXPECT_LE(iter, iter); + EXPECT_GT(citer, iter); + EXPECT_GE(citer, citer); + + // iter points to {100, 200, 300, 400} + iter += 2; + EXPECT_NE(*iter, *citer); + EXPECT_EQ(iter->size(), 4u); + for (int i = 1; i <= 4; ++i) { + EXPECT_EQ(iter->begin()[i - 1], i * 100); + } + + EXPECT_LT(citer, iter); + EXPECT_LE(iter, iter); + EXPECT_GT(iter, citer); + EXPECT_GE(citer, citer); + + // iter points to {10, 20, 30}. (same as citer) + iter -= 1; + EXPECT_EQ(*iter, *citer); + EXPECT_EQ(iter->size(), 3u); + x = 10; + for (auto it = iter->begin(); it != iter->end();) { + EXPECT_EQ(*(it++), x); + x += 10; + } + x = 30; + for (auto it = iter->begin() + 2; it != iter->begin();) { + EXPECT_EQ(*(it--), x); + x -= 10; + } +} + +TEST(QuicCircularDeque, Resize) { + QuicCircularDeque> dq; + dq.resize(8); + EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0)); + EXPECT_EQ(1u, dq.get_allocator().allocate_count()); + + dq.resize(10, 5); + EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0, 5, 5)); + + QuicCircularDeque> dq2 = dq; + + for (size_t new_size = dq.size(); new_size != 0; --new_size) { + dq.resize(new_size); + EXPECT_TRUE( + std::equal(dq.begin(), dq.end(), dq2.begin(), dq2.begin() + new_size)); + } + + dq.resize(0); + EXPECT_TRUE(dq.empty()); + + // Resize when data is wrapped. + ASSERT_EQ(dq2.size(), dq2.capacity()); + while (dq2.size() < dq2.capacity()) { + dq2.push_back(5); + } + + // Shift left once such that data is wrapped. + ASSERT_LT(&dq2.front(), &dq2.back()); + dq2.pop_back(); + dq2.push_front(-5); + ASSERT_GT(&dq2.front(), &dq2.back()); + + EXPECT_EQ(-5, dq2.front()); + EXPECT_EQ(5, dq2.back()); + dq2.resize(dq2.size() + 1, 10); + + // Data should be unwrapped after the resize. + ASSERT_LT(&dq2.front(), &dq2.back()); + EXPECT_EQ(-5, dq2.front()); + EXPECT_EQ(10, dq2.back()); + EXPECT_EQ(5, *(dq2.rbegin() + 1)); +} + +namespace { +class Foo { + public: + Foo() : Foo(0xF00) {} + + explicit Foo(int i) : i_(new int(i)) {} + + ~Foo() { + if (i_ != nullptr) { + delete i_; + // Do not set i_ to nullptr such that if the container calls destructor + // multiple times, asan can detect it. + } + } + + Foo(const Foo& other) : i_(new int(*other.i_)) {} + + Foo(Foo&& other) = delete; + + void Set(int i) { *i_ = i; } + + int i() const { return *i_; } + + friend bool operator==(const Foo& lhs, const Foo& rhs) { + return lhs.i() == rhs.i(); + } + + friend std::ostream& operator<<(std::ostream& os, const Foo& foo) { + return os << "Foo(" << foo.i() << ")"; + } + + private: + // By pointing i_ to a dynamically allocated integer, a memory leak will be + // reported if the container forget to properly destruct this object. + int* i_ = nullptr; +}; +} // namespace + +TEST(QuicCircularDeque, RelocateNonTriviallyCopyable) { + // When relocating non-trivially-copyable objects: + // - Move constructor is preferred, if available. + // - Copy constructor is used otherwise. + + { + // Move construct in Relocate. + typedef std::unique_ptr MoveConstructible; + ASSERT_FALSE(std::is_trivially_copyable::value); + ASSERT_TRUE(std::is_move_constructible::value); + QuicCircularDeque> + dq1; + dq1.resize(3); + EXPECT_EQ(dq1.size(), dq1.capacity()); + EXPECT_EQ(1u, dq1.get_allocator().allocate_count()); + + dq1.emplace_back(new Foo(0xF1)); // Cause existing elements to relocate. + EXPECT_EQ(4u, dq1.size()); + EXPECT_EQ(2u, dq1.get_allocator().allocate_count()); + EXPECT_EQ(dq1[0], nullptr); + EXPECT_EQ(dq1[1], nullptr); + EXPECT_EQ(dq1[2], nullptr); + EXPECT_EQ(dq1[3]->i(), 0xF1); + } + + { + // Copy construct in Relocate. + typedef Foo NonMoveConstructible; + ASSERT_FALSE(std::is_trivially_copyable::value); + ASSERT_FALSE(std::is_move_constructible::value); + QuicCircularDeque> + dq2; + dq2.resize(3); + EXPECT_EQ(dq2.size(), dq2.capacity()); + EXPECT_EQ(1u, dq2.get_allocator().allocate_count()); + + dq2.emplace_back(0xF1); // Cause existing elements to relocate. + EXPECT_EQ(4u, dq2.size()); + EXPECT_EQ(2u, dq2.get_allocator().allocate_count()); + EXPECT_EQ(dq2[0].i(), 0xF00); + EXPECT_EQ(dq2[1].i(), 0xF00); + EXPECT_EQ(dq2[2].i(), 0xF00); + EXPECT_EQ(dq2[3].i(), 0xF1); + } +} + +TEST(QuicCircularDeque, PushPop) { + // (push|pop|emplace)_(back|front) + + { + QuicCircularDeque> dq(4); + for (size_t i = 0; i < dq.size(); ++i) { + dq[i].Set(i + 1); + } + QUIC_LOG(INFO) << "dq initialized to " << dq; + EXPECT_THAT(dq, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4))); + + ShiftLeft(&dq, false); + QUIC_LOG(INFO) << "shift left once : " << dq; + EXPECT_THAT(dq, ElementsAre(Foo(2), Foo(3), Foo(4), Foo(1))); + + ShiftLeft(&dq, true); + QUIC_LOG(INFO) << "shift left twice: " << dq; + EXPECT_THAT(dq, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2))); + ASSERT_GT(&dq.front(), &dq.back()); + // dq destructs with wrapped data. + } + + { + QuicCircularDeque> dq1(4); + for (size_t i = 0; i < dq1.size(); ++i) { + dq1[i].Set(i + 1); + } + QUIC_LOG(INFO) << "dq1 initialized to " << dq1; + EXPECT_THAT(dq1, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4))); + + ShiftRight(&dq1, false); + QUIC_LOG(INFO) << "shift right once : " << dq1; + EXPECT_THAT(dq1, ElementsAre(Foo(4), Foo(1), Foo(2), Foo(3))); + + ShiftRight(&dq1, true); + QUIC_LOG(INFO) << "shift right twice: " << dq1; + EXPECT_THAT(dq1, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2))); + ASSERT_GT(&dq1.front(), &dq1.back()); + // dq1 destructs with wrapped data. + } + + { // Pop n elements from front. + QuicCircularDeque> dq2(5); + for (size_t i = 0; i < dq2.size(); ++i) { + dq2[i].Set(i + 1); + } + EXPECT_THAT(dq2, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4), Foo(5))); + + EXPECT_EQ(2u, dq2.pop_front_n(2)); + EXPECT_THAT(dq2, ElementsAre(Foo(3), Foo(4), Foo(5))); + + EXPECT_EQ(3u, dq2.pop_front_n(100)); + EXPECT_TRUE(dq2.empty()); + } + + { // Pop n elements from back. + QuicCircularDeque> dq3(6); + for (size_t i = 0; i < dq3.size(); ++i) { + dq3[i].Set(i + 1); + } + EXPECT_THAT(dq3, + ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4), Foo(5), Foo(6))); + + ShiftRight(&dq3, true); + ShiftRight(&dq3, true); + ShiftRight(&dq3, true); + EXPECT_THAT(dq3, + ElementsAre(Foo(4), Foo(5), Foo(6), Foo(1), Foo(2), Foo(3))); + + EXPECT_EQ(2u, dq3.pop_back_n(2)); + EXPECT_THAT(dq3, ElementsAre(Foo(4), Foo(5), Foo(6), Foo(1))); + + EXPECT_EQ(2u, dq3.pop_back_n(2)); + EXPECT_THAT(dq3, ElementsAre(Foo(4), Foo(5))); + } +} + +TEST(QuicCircularDeque, Allocation) { + CountingAllocator alloc; + + { + QuicCircularDeque> dq(alloc); + EXPECT_EQ(alloc, dq.get_allocator()); + EXPECT_EQ(0u, dq.size()); + EXPECT_EQ(0u, dq.capacity()); + EXPECT_EQ(0u, alloc.allocate_count()); + EXPECT_EQ(0u, alloc.deallocate_count()); + + for (int i = 1; i <= 18; ++i) { + SCOPED_TRACE(testing::Message() + << "i=" << i << ", capacity_b4_push=" << dq.capacity()); + dq.push_back(i); + EXPECT_EQ(i, static_cast(dq.size())); + + const size_t capacity = 3 + (i - 1) / 3 * 3; + EXPECT_EQ(capacity, dq.capacity()); + EXPECT_EQ(capacity / 3, alloc.allocate_count()); + EXPECT_EQ(capacity / 3 - 1, alloc.deallocate_count()); + } + + dq.push_back(19); + EXPECT_EQ(22u, dq.capacity()); // 18 + 18 / 4 + EXPECT_EQ(7u, alloc.allocate_count()); + EXPECT_EQ(6u, alloc.deallocate_count()); + } + + EXPECT_EQ(7u, alloc.deallocate_count()); +} + +} // namespace test +} // namespace quic + +// Use a non-quic namespace to make sure swap can be used via ADL. +namespace { + +template +using SwappableAllocator = quic::test::ConfigurableAllocator< + T, + /*propagate_on_copy_assignment=*/std::true_type, + /*propagate_on_move_assignment=*/std::true_type, + /*propagate_on_swap=*/std::true_type, + /*equality_result=*/true>; + +template +using UnswappableEqualAllocator = quic::test::ConfigurableAllocator< + T, + /*propagate_on_copy_assignment=*/std::true_type, + /*propagate_on_move_assignment=*/std::true_type, + /*propagate_on_swap=*/std::false_type, + /*equality_result=*/true>; + +template +using UnswappableUnequalAllocator = quic::test::ConfigurableAllocator< + T, + /*propagate_on_copy_assignment=*/std::true_type, + /*propagate_on_move_assignment=*/std::true_type, + /*propagate_on_swap=*/std::false_type, + /*equality_result=*/false>; + +TEST(QuicCircularDeque, Swap) { + using std::swap; + + quic::QuicCircularDeque> dq1, dq2; + dq1.push_back(10); + dq1.push_back(11); + dq2.push_back(20); + swap(dq1, dq2); + EXPECT_THAT(dq1, ElementsAre(20)); + EXPECT_THAT(dq2, ElementsAre(10, 11)); + + quic::QuicCircularDeque> dq3, dq4; + dq3 = {1, 2, 3, 4, 5}; + dq4 = {6, 7, 8, 9, 0}; + swap(dq3, dq4); + EXPECT_THAT(dq3, ElementsAre(6, 7, 8, 9, 0)); + EXPECT_THAT(dq4, ElementsAre(1, 2, 3, 4, 5)); + + quic::QuicCircularDeque> dq5, dq6; + dq6.push_front(4); + + // Using UnswappableUnequalAllocator is ok as long as swap is not called. + dq5.assign(dq6.begin(), dq6.end()); + EXPECT_THAT(dq5, ElementsAre(4)); + + // Undefined behavior to swap between two containers with unequal allocators. + EXPECT_QUIC_DEBUG_DEATH(swap(dq5, dq6), "Undefined swap behavior"); +} +} // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc new file mode 100644 index 00000000000..3dd9b24a4a4 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc @@ -0,0 +1,119 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_coalesced_packet.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" + +namespace quic { + +QuicCoalescedPacket::QuicCoalescedPacket() + : length_(0), max_packet_length_(0) {} + +QuicCoalescedPacket::~QuicCoalescedPacket() { + Clear(); +} + +bool QuicCoalescedPacket::MaybeCoalescePacket( + const SerializedPacket& packet, + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + QuicBufferAllocator* allocator, + QuicPacketLength current_max_packet_length) { + if (packet.encrypted_length == 0) { + QUIC_BUG << "Trying to coalesce an empty packet"; + return true; + } + if (length_ == 0) { +#ifndef NDEBUG + for (const auto& buffer : encrypted_buffers_) { + DCHECK(buffer.empty()); + } +#endif + DCHECK(initial_packet_ == nullptr); + // This is the first packet, set max_packet_length and self/peer + // addresses. + max_packet_length_ = current_max_packet_length; + self_address_ = self_address; + peer_address_ = peer_address; + } else { + if (self_address_ != self_address || peer_address_ != peer_address) { + // Do not coalesce packet with different self/peer addresses. + QUIC_DLOG(INFO) + << "Cannot coalesce packet because self/peer address changed"; + return false; + } + if (max_packet_length_ != current_max_packet_length) { + QUIC_BUG << "Max packet length changes in the middle of the write path"; + return false; + } + if (!encrypted_buffers_[packet.encryption_level].empty() || + (packet.encryption_level == ENCRYPTION_INITIAL && + initial_packet_ != nullptr)) { + // Do not coalesce packets of the same encryption level. + return false; + } + } + + if (length_ + packet.encrypted_length > max_packet_length_) { + // Packet does not fit. + return false; + } + QUIC_DVLOG(1) << "Successfully coalesced packet: encryption_level: " + << EncryptionLevelToString(packet.encryption_level) + << ", encrypted_length: " << packet.encrypted_length + << ", current length: " << length_ + << ", max_packet_length: " << max_packet_length_; + if (length_ > 0) { + QUIC_CODE_COUNT(QUIC_SUCCESSFULLY_COALESCED_MULTIPLE_PACKETS); + } + length_ += packet.encrypted_length; + if (packet.encryption_level == ENCRYPTION_INITIAL) { + // Save a copy of ENCRYPTION_INITIAL packet (excluding encrypted buffer, as + // the packet will be re-serialized later). + initial_packet_ = QuicWrapUnique( + CopySerializedPacket(packet, allocator, /*copy_buffer=*/false)); + return true; + } + // Copy encrypted buffer of packets with other encryption levels. + encrypted_buffers_[packet.encryption_level] = + std::string(packet.encrypted_buffer, packet.encrypted_length); + return true; +} + +void QuicCoalescedPacket::Clear() { + self_address_ = QuicSocketAddress(); + peer_address_ = QuicSocketAddress(); + length_ = 0; + max_packet_length_ = 0; + for (auto& packet : encrypted_buffers_) { + packet.clear(); + } + if (initial_packet_ != nullptr) { + ClearSerializedPacket(initial_packet_.get()); + } + initial_packet_ = nullptr; +} + +bool QuicCoalescedPacket::CopyEncryptedBuffers(char* buffer, + size_t buffer_len, + size_t* length_copied) const { + *length_copied = 0; + for (const auto& packet : encrypted_buffers_) { + if (packet.empty()) { + continue; + } + if (packet.length() > buffer_len) { + return false; + } + memcpy(buffer, packet.data(), packet.length()); + buffer += packet.length(); + buffer_len -= packet.length(); + *length_copied += packet.length(); + } + return true; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h new file mode 100644 index 00000000000..f03f87544b9 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h @@ -0,0 +1,72 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QUIC_COALESCED_PACKET_H_ +#define QUICHE_QUIC_CORE_QUIC_COALESCED_PACKET_H_ + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" + +namespace quic { + +// QuicCoalescedPacket is used to buffer multiple packets which can be coalesced +// into the same UDP datagram. +class QUIC_EXPORT_PRIVATE QuicCoalescedPacket { + public: + QuicCoalescedPacket(); + ~QuicCoalescedPacket(); + + // Returns true if |packet| is successfully coalesced with existing packets. + // Returns false otherwise. + bool MaybeCoalescePacket(const SerializedPacket& packet, + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + QuicBufferAllocator* allocator, + QuicPacketLength current_max_packet_length); + + // Clears this coalesced packet. + void Clear(); + + // Copies encrypted_buffers_ to |buffer| and sets |length_copied| to the + // copied amount. Returns false if copy fails (i.e., |buffer_len| is not + // enough). + bool CopyEncryptedBuffers(char* buffer, + size_t buffer_len, + size_t* length_copied) const; + + const SerializedPacket* initial_packet() const { + return initial_packet_.get(); + } + + const QuicSocketAddress& self_address() const { return self_address_; } + + const QuicSocketAddress& peer_address() const { return peer_address_; } + + QuicPacketLength length() const { return length_; } + + QuicPacketLength max_packet_length() const { return max_packet_length_; } + + private: + // self/peer addresses are set when trying to coalesce the first packet. + // Packets with different self/peer addresses cannot be coalesced. + QuicSocketAddress self_address_; + QuicSocketAddress peer_address_; + // Length of this coalesced packet. + QuicPacketLength length_; + // Max packet length. Do not try to coalesce packet when max packet length + // changes (e.g., with MTU discovery). + QuicPacketLength max_packet_length_; + // Copies of packets' encrypted buffers according to different encryption + // levels. + std::string encrypted_buffers_[NUM_ENCRYPTION_LEVELS]; + + // A copy of ENCRYPTION_INITIAL packet if this coalesced packet contains one. + // Null otherwise. Please note, the encrypted_buffer field is not copied. The + // frames are copied to allow it be re-serialized when this coalesced packet + // gets sent. + std::unique_ptr initial_packet_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_COALESCED_PACKET_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet_test.cc new file mode 100644 index 00000000000..8213480bf91 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet_test.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_coalesced_packet.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +TEST(QuicCoalescedPacketTest, MaybeCoalescePacket) { + QuicCoalescedPacket coalesced; + SimpleBufferAllocator allocator; + EXPECT_EQ(0u, coalesced.length()); + char buffer[1000]; + QuicSocketAddress self_address(QuicIpAddress::Loopback4(), 1); + QuicSocketAddress peer_address(QuicIpAddress::Loopback4(), 2); + SerializedPacket packet1(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, + buffer, 500, false, false); + QuicAckFrame ack_frame(InitAckFrame(1)); + packet1.nonretransmittable_frames.push_back(QuicFrame(&ack_frame)); + packet1.retransmittable_frames.push_back( + QuicFrame(QuicStreamFrame(1, true, 0, 100))); + ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, + &allocator, 1500)); + EXPECT_EQ(1500u, coalesced.max_packet_length()); + EXPECT_EQ(500u, coalesced.length()); + + // Cannot coalesce packet of the same encryption level. + SerializedPacket packet2(QuicPacketNumber(2), PACKET_4BYTE_PACKET_NUMBER, + buffer, 500, false, false); + EXPECT_FALSE(coalesced.MaybeCoalescePacket(packet2, self_address, + peer_address, &allocator, 1500)); + + SerializedPacket packet3(QuicPacketNumber(3), PACKET_4BYTE_PACKET_NUMBER, + buffer, 500, false, false); + packet3.nonretransmittable_frames.push_back(QuicFrame(QuicPaddingFrame(100))); + packet3.encryption_level = ENCRYPTION_ZERO_RTT; + ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet3, self_address, peer_address, + &allocator, 1500)); + EXPECT_EQ(1500u, coalesced.max_packet_length()); + EXPECT_EQ(1000u, coalesced.length()); + + SerializedPacket packet4(QuicPacketNumber(4), PACKET_4BYTE_PACKET_NUMBER, + buffer, 500, false, false); + packet4.encryption_level = ENCRYPTION_FORWARD_SECURE; + // Cannot coalesce packet of changed self/peer address. + EXPECT_FALSE(coalesced.MaybeCoalescePacket( + packet4, QuicSocketAddress(QuicIpAddress::Loopback4(), 3), peer_address, + &allocator, 1500)); + + // Packet does not fit. + SerializedPacket packet5(QuicPacketNumber(5), PACKET_4BYTE_PACKET_NUMBER, + buffer, 501, false, false); + packet5.encryption_level = ENCRYPTION_FORWARD_SECURE; + EXPECT_FALSE(coalesced.MaybeCoalescePacket(packet5, self_address, + peer_address, &allocator, 1500)); + EXPECT_EQ(1500u, coalesced.max_packet_length()); + EXPECT_EQ(1000u, coalesced.length()); + + // Max packet number length changed. + SerializedPacket packet6(QuicPacketNumber(6), PACKET_4BYTE_PACKET_NUMBER, + buffer, 100, false, false); + packet6.encryption_level = ENCRYPTION_FORWARD_SECURE; + EXPECT_QUIC_BUG(coalesced.MaybeCoalescePacket(packet6, self_address, + peer_address, &allocator, 1000), + "Max packet length changes in the middle of the write path"); + EXPECT_EQ(1500u, coalesced.max_packet_length()); + EXPECT_EQ(1000u, coalesced.length()); +} + +TEST(QuicCoalescedPacketTest, CopyEncryptedBuffers) { + QuicCoalescedPacket coalesced; + SimpleBufferAllocator allocator; + QuicSocketAddress self_address(QuicIpAddress::Loopback4(), 1); + QuicSocketAddress peer_address(QuicIpAddress::Loopback4(), 2); + std::string buffer(500, 'a'); + std::string buffer2(500, 'b'); + SerializedPacket packet1(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, + buffer.data(), 500, + /*has_ack=*/false, /*has_stop_waiting=*/false); + packet1.encryption_level = ENCRYPTION_ZERO_RTT; + SerializedPacket packet2(QuicPacketNumber(2), PACKET_4BYTE_PACKET_NUMBER, + buffer2.data(), 500, + /*has_ack=*/false, /*has_stop_waiting=*/false); + packet2.encryption_level = ENCRYPTION_FORWARD_SECURE; + + ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, + &allocator, 1500)); + ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet2, self_address, peer_address, + &allocator, 1500)); + EXPECT_EQ(1000u, coalesced.length()); + + char copy_buffer[1000]; + size_t length_copied = 0; + EXPECT_FALSE( + coalesced.CopyEncryptedBuffers(copy_buffer, 900, &length_copied)); + ASSERT_TRUE( + coalesced.CopyEncryptedBuffers(copy_buffer, 1000, &length_copied)); + EXPECT_EQ(1000u, length_copied); + char expected[1000]; + memset(expected, 'a', 500); + memset(expected + 500, 'b', 500); + test::CompareCharArraysWithHexError("copied buffers", copy_buffer, + length_copied, expected, 1000); +} + +} // namespace +} // namespace test +} // namespace quic 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 a3840ec8e9b..3d8fe3fa318 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 @@ -420,7 +420,9 @@ QuicConfig::QuicConfig() stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL), max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL), - ack_delay_exponent_(kADE, PRESENCE_OPTIONAL) { + ack_delay_exponent_(kADE, PRESENCE_OPTIONAL), + max_packet_size_(0, PRESENCE_OPTIONAL), + max_datagram_frame_size_(0, PRESENCE_OPTIONAL) { SetDefaults(); } @@ -579,6 +581,39 @@ uint32_t QuicConfig::ReceivedAckDelayExponent() const { return ack_delay_exponent_.GetReceivedValue(); } +void QuicConfig::SetMaxPacketSizeToSend(uint32_t max_packet_size) { + max_packet_size_.SetSendValue(max_packet_size); +} + +uint32_t QuicConfig::GetMaxPacketSizeToSend() const { + return max_packet_size_.GetSendValue(); +} + +bool QuicConfig::HasReceivedMaxPacketSize() const { + return max_packet_size_.HasReceivedValue(); +} + +uint32_t QuicConfig::ReceivedMaxPacketSize() const { + return max_packet_size_.GetReceivedValue(); +} + +void QuicConfig::SetMaxDatagramFrameSizeToSend( + uint32_t max_datagram_frame_size) { + max_datagram_frame_size_.SetSendValue(max_datagram_frame_size); +} + +uint32_t QuicConfig::GetMaxDatagramFrameSizeToSend() const { + return max_datagram_frame_size_.GetSendValue(); +} + +bool QuicConfig::HasReceivedMaxDatagramFrameSize() const { + return max_datagram_frame_size_.HasReceivedValue(); +} + +uint32_t QuicConfig::ReceivedMaxDatagramFrameSize() const { + return max_datagram_frame_size_.GetReceivedValue(); +} + bool QuicConfig::HasSetBytesForConnectionIdToSend() const { return bytes_for_connection_id_.HasSendValue(); } @@ -806,6 +841,8 @@ void QuicConfig::SetDefaults() { SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs); SetSupportMaxHeaderListSize(); SetAckDelayExponentToSend(kDefaultAckDelayExponent); + SetMaxPacketSizeToSend(kMaxIncomingPacketSize); + SetMaxDatagramFrameSizeToSend(kMaxAcceptedDatagramFrameSize); } void QuicConfig::ToHandshakeMessage( @@ -921,7 +958,8 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { sizeof(stateless_reset_token)); } - params->max_packet_size.set_value(kMaxIncomingPacketSize); + params->max_packet_size.set_value(GetMaxPacketSizeToSend()); + params->max_datagram_frame_size.set_value(GetMaxDatagramFrameSizeToSend()); params->initial_max_data.set_value( GetInitialSessionFlowControlWindowToSend()); // The max stream data bidirectional transport parameters can be either local @@ -1008,10 +1046,19 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( stateless_reset_token_.SetReceivedValue(stateless_reset_token); } - if (params.max_packet_size.value() < kMaxOutgoingPacketSize) { + if (params.max_packet_size.IsValid()) { + max_packet_size_.SetReceivedValue(params.max_packet_size.value()); + if (ReceivedMaxPacketSize() < kMaxOutgoingPacketSize) { + // TODO(dschinazi) act on this. + QUIC_DLOG(ERROR) << "Ignoring peer's requested max packet size of " + << ReceivedMaxPacketSize(); + } + } + + if (params.max_datagram_frame_size.IsValid()) { + max_datagram_frame_size_.SetReceivedValue( + params.max_datagram_frame_size.value()); // TODO(dschinazi) act on this. - QUIC_DLOG(ERROR) << "Ignoring peer's requested max packet size of " - << params.max_packet_size.value(); } initial_session_flow_control_window_bytes_.SetReceivedValue( @@ -1048,8 +1095,9 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( if (params.ack_delay_exponent.IsValid()) { ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); } - connection_migration_disabled_.SetReceivedValue( - params.disable_migration ? 1u : 0u); + if (params.disable_migration) { + connection_migration_disabled_.SetReceivedValue(1u); + } if (params.preferred_address != nullptr) { if (params.preferred_address->ipv6_socket_address.port() != 0) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.h b/chromium/net/third_party/quiche/src/quic/core/quic_config.h index ecece2ae49f..de78d40144a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.h @@ -456,6 +456,18 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool HasReceivedAckDelayExponent() const; uint32_t ReceivedAckDelayExponent() const; + // IETF QUIC max_packet_size transport parameter. + void SetMaxPacketSizeToSend(uint32_t max_packet_size); + uint32_t GetMaxPacketSizeToSend() const; + bool HasReceivedMaxPacketSize() const; + uint32_t ReceivedMaxPacketSize() const; + + // IETF QUIC max_datagram_frame_size transport parameter. + void SetMaxDatagramFrameSizeToSend(uint32_t max_datagram_frame_size); + uint32_t GetMaxDatagramFrameSizeToSend() const; + bool HasReceivedMaxDatagramFrameSize() const; + uint32_t ReceivedMaxDatagramFrameSize() const; + bool negotiated() const; void SetCreateSessionTagIndicators(QuicTagVector tags); @@ -573,6 +585,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // to serialize frames and this node uses to deserialize them. QuicFixedUint32 ack_delay_exponent_; + // max_packet_size IETF QUIC transport parameter. + QuicFixedUint32 max_packet_size_; + + // max_datagram_frame_size IETF QUIC transport parameter. + QuicFixedUint32 max_datagram_frame_size_; + // Custom transport parameters that can be sent and received in the TLS // handshake. TransportParameters::ParameterMap custom_transport_parameters_to_send_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc index e0eb304a945..69ce78de0fd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc @@ -21,6 +21,9 @@ namespace quic { namespace test { namespace { +const uint32_t kMaxPacketSizeForTest = 1234; +const uint32_t kMaxDatagramFrameSizeForTest = 1333; + class QuicConfigTest : public QuicTestWithParam { protected: QuicConfig config_; @@ -47,6 +50,8 @@ TEST_P(QuicConfigTest, SetDefaults) { EXPECT_FALSE( config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); EXPECT_FALSE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); + EXPECT_EQ(kMaxIncomingPacketSize, config_.GetMaxPacketSizeToSend()); + EXPECT_FALSE(config_.HasReceivedMaxPacketSize()); } TEST_P(QuicConfigTest, AutoSetIetfFlowControl) { @@ -91,15 +96,15 @@ TEST_P(QuicConfigTest, ToHandshakeMessage) { uint32_t value; QuicErrorCode error = msg.GetUint32(kICSL, &value); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_EQ(5u, value); error = msg.GetUint32(kSFCW, &value); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_EQ(kInitialStreamFlowControlWindowForTest, value); error = msg.GetUint32(kCFCW, &value); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value); } @@ -137,7 +142,7 @@ TEST_P(QuicConfigTest, ProcessClientHello) { EXPECT_FALSE( config_.SetInitialReceivedConnectionOptions(initial_received_options)) << "You cannot set initial options after the hello."; - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs), config_.IdleNetworkTimeout()); @@ -191,7 +196,7 @@ TEST_P(QuicConfigTest, ProcessServerHello) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2), config_.IdleNetworkTimeout()); @@ -231,7 +236,7 @@ TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); } @@ -246,7 +251,7 @@ TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); } @@ -256,7 +261,7 @@ TEST_P(QuicConfigTest, MissingValueInCHLO) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); + EXPECT_THAT(error, IsError(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)); } TEST_P(QuicConfigTest, MissingValueInSHLO) { @@ -265,7 +270,7 @@ TEST_P(QuicConfigTest, MissingValueInSHLO) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); - EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); + EXPECT_THAT(error, IsError(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)); } TEST_P(QuicConfigTest, OutOfBoundSHLO) { @@ -279,7 +284,7 @@ TEST_P(QuicConfigTest, OutOfBoundSHLO) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); - EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error); + EXPECT_THAT(error, IsError(QUIC_INVALID_NEGOTIATED_VALUE)); } TEST_P(QuicConfigTest, InvalidFlowControlWindow) { @@ -309,7 +314,7 @@ TEST_P(QuicConfigTest, HasClientSentConnectionOption) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); EXPECT_TRUE(config_.HasReceivedConnectionOptions()); @@ -330,7 +335,7 @@ TEST_P(QuicConfigTest, DontSendClientConnectionOptions) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); EXPECT_FALSE(config_.HasReceivedConnectionOptions()); @@ -357,7 +362,7 @@ TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); EXPECT_TRUE(config_.negotiated()); EXPECT_TRUE(config_.HasReceivedConnectionOptions()); @@ -377,8 +382,9 @@ TEST_P(QuicConfigTest, IncomingLargeIdleTimeoutTransportParameter) { params.idle_timeout_milliseconds.set_value(120000); std::string error_details = "foobar"; - EXPECT_EQ(QUIC_NO_ERROR, - config_.ProcessTransportParameters(params, SERVER, &error_details)); + EXPECT_THAT( + config_.ProcessTransportParameters(params, SERVER, &error_details), + IsQuicNoError()); EXPECT_EQ("", error_details); EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(60), config_.IdleNetworkTimeout()); @@ -391,6 +397,8 @@ TEST_P(QuicConfigTest, FillTransportParams) { 3 * kMinimumFlowControlSendWindow); config_.SetInitialMaxStreamDataBytesUnidirectionalToSend( 4 * kMinimumFlowControlSendWindow); + config_.SetMaxPacketSizeToSend(kMaxPacketSizeForTest); + config_.SetMaxDatagramFrameSizeToSend(kMaxDatagramFrameSizeForTest); TransportParameters params; config_.FillTransportParameters(¶ms); @@ -404,6 +412,10 @@ TEST_P(QuicConfigTest, FillTransportParams) { EXPECT_EQ(static_cast(kMaximumIdleTimeoutSecs * 1000), params.idle_timeout_milliseconds.value()); + + EXPECT_EQ(kMaxPacketSizeForTest, params.max_packet_size.value()); + EXPECT_EQ(kMaxDatagramFrameSizeForTest, + params.max_datagram_frame_size.value()); } TEST_P(QuicConfigTest, ProcessTransportParametersServer) { @@ -415,10 +427,13 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { 3 * kMinimumFlowControlSendWindow); params.initial_max_stream_data_uni.set_value(4 * kMinimumFlowControlSendWindow); + params.max_packet_size.set_value(kMaxPacketSizeForTest); + params.max_datagram_frame_size.set_value(kMaxDatagramFrameSizeForTest); std::string error_details; - EXPECT_EQ(QUIC_NO_ERROR, - config_.ProcessTransportParameters(params, SERVER, &error_details)); + EXPECT_THAT( + config_.ProcessTransportParameters(params, SERVER, &error_details), + IsQuicNoError()); ASSERT_TRUE( config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); @@ -433,6 +448,25 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { ASSERT_TRUE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); EXPECT_EQ(4 * kMinimumFlowControlSendWindow, config_.ReceivedInitialMaxStreamDataBytesUnidirectional()); + + ASSERT_TRUE(config_.HasReceivedMaxPacketSize()); + EXPECT_EQ(kMaxPacketSizeForTest, config_.ReceivedMaxPacketSize()); + + ASSERT_TRUE(config_.HasReceivedMaxDatagramFrameSize()); + EXPECT_EQ(kMaxDatagramFrameSizeForTest, + config_.ReceivedMaxDatagramFrameSize()); + + EXPECT_FALSE(config_.DisableConnectionMigration()); +} + +TEST_P(QuicConfigTest, DisableMigrationTransportParameter) { + TransportParameters params; + params.disable_migration = true; + std::string error_details; + EXPECT_THAT( + config_.ProcessTransportParameters(params, SERVER, &error_details), + IsQuicNoError()); + EXPECT_TRUE(config_.DisableConnectionMigration()); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc index cb2409592a0..9349bf234fd 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 @@ -24,8 +24,6 @@ #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/core/quic_packet_generator.h" -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.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" @@ -180,6 +178,17 @@ class ProcessUndecryptablePacketsAlarmDelegate : public QuicAlarm::Delegate { QuicConnection* connection_; }; +// When the clearer goes out of scope, the coalesced packet gets cleared. +class ScopedCoalescedPacketClearer { + public: + explicit ScopedCoalescedPacketClearer(QuicCoalescedPacket* coalesced) + : coalesced_(coalesced) {} + ~ScopedCoalescedPacketClearer() { coalesced_->Clear(); } + + private: + QuicCoalescedPacket* coalesced_; // Unowned. +}; + // Whether this incoming packet is allowed to replace our connection ID. bool PacketCanReplaceConnectionId(const QuicPacketHeader& header, Perspective perspective) { @@ -256,7 +265,8 @@ QuicConnection::QuicConnection( pending_retransmission_alarm_(false), defer_send_in_response_to_packets_(false), ping_timeout_(QuicTime::Delta::FromSeconds(kPingTimeoutSecs)), - retransmittable_on_wire_timeout_(QuicTime::Delta::Infinite()), + initial_retransmittable_on_wire_timeout_(QuicTime::Delta::Infinite()), + consecutive_retransmittable_on_wire_ping_count_(0), arena_(), ack_alarm_(alarm_factory_->CreateAlarm(arena_.New(this), &arena_)), @@ -283,10 +293,7 @@ QuicConnection::QuicConnection( &arena_)), visitor_(nullptr), debug_visitor_(nullptr), - packet_generator_(server_connection_id_, - &framer_, - random_generator_, - this), + packet_creator_(server_connection_id_, &framer_, random_generator_, this), idle_network_timeout_(QuicTime::Delta::Infinite()), handshake_timeout_(QuicTime::Delta::Infinite()), time_of_first_packet_sent_after_receiving_(QuicTime::Zero()), @@ -301,10 +308,7 @@ QuicConnection::QuicConnection( perspective_(perspective), connected_(true), can_truncate_connection_ids_(perspective == Perspective::IS_SERVER), - mtu_discovery_target_(0), mtu_probe_count_(0), - packets_between_mtu_probes_(kPacketsBetweenMtuProbesBase), - next_mtu_probe_at_(kPacketsBetweenMtuProbesBase), largest_received_packet_size_(0), write_error_occurred_(false), no_stop_waiting_frames_( @@ -326,10 +330,11 @@ QuicConnection::QuicConnection( bytes_received_before_address_validation_(0), bytes_sent_before_address_validation_(0), address_validated_(false), - skip_packet_number_for_pto_(false), - treat_queued_packets_as_sent_( - GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)), - mtu_discovery_v2_(GetQuicReloadableFlag(quic_mtu_discovery_v2)) { + quic_version_negotiated_by_default_at_server_( + GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)), + use_handshake_delegate_( + GetQuicReloadableFlag(quic_use_handshaker_delegate) || + version().handshake_protocol == PROTOCOL_TLS1_3) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " << server_connection_id << " and version: " << ParsedQuicVersionToString(version()); @@ -339,6 +344,9 @@ QuicConnection::QuicConnection( << "QuicConnection: attempted to use server connection ID " << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); + if (use_handshake_delegate_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_handshaker_delegate); + } framer_.set_visitor(this); stats_.connection_creation_time = clock_->ApproximateNow(); @@ -356,20 +364,23 @@ QuicConnection::QuicConnection( ? kDefaultServerMaxPacketSize : kDefaultMaxPacketSize); uber_received_packet_manager_.set_max_ack_ranges(255); - MaybeEnableSessionDecidesWhatToWrite(); + if (version().SupportsAntiAmplificationLimit()) { + sent_packet_manager_.EnableIetfPtoAndLossDetection(); + } MaybeEnableMultiplePacketNumberSpacesSupport(); DCHECK(perspective_ == Perspective::IS_CLIENT || supported_versions.size() == 1); InstallInitialCrypters(server_connection_id_); + + if (quic_version_negotiated_by_default_at_server() && + perspective_ == Perspective::IS_SERVER) { + QUIC_RELOADABLE_FLAG_COUNT(quic_version_negotiated_by_default_at_server); + version_negotiated_ = true; + framer_.InferPacketHeaderTypeFromVersion(); + } } void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) { - if (!framer_.framer_doesnt_create_initial_encrypter() && - !version().UsesInitialObfuscators() && - version().handshake_protocol != PROTOCOL_TLS1_3) { - // Initial crypters are currently only supported with TLS. - return; - } CrypterPair crypters; CryptoUtils::CreateInitialObfuscators(perspective_, version(), connection_id, &crypters); @@ -389,15 +400,6 @@ QuicConnection::~QuicConnection() { } void QuicConnection::ClearQueuedPackets() { - for (auto it = queued_packets_.begin(); it != queued_packets_.end(); ++it) { - // Delete the buffer before calling ClearSerializedPacket, which sets - // encrypted_buffer to nullptr. - DCHECK(!treat_queued_packets_as_sent_); - delete[] it->encrypted_buffer; - ClearSerializedPacket(&(*it)); - } - queued_packets_.clear(); - buffered_packets_.clear(); } @@ -418,17 +420,18 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { sent_packet_manager_.SetFromConfig(config); if (config.HasReceivedBytesForConnectionId() && can_truncate_connection_ids_) { - packet_generator_.SetServerConnectionIdLength( + packet_creator_.SetServerConnectionIdLength( config.ReceivedBytesForConnectionId()); } max_undecryptable_packets_ = config.max_undecryptable_packets(); - if (config.HasClientSentConnectionOption(kMTUH, perspective_)) { + if (config.HasClientRequestedIndependentOption(kMTUH, perspective_)) { SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeHigh); } - if (config.HasClientSentConnectionOption(kMTUL, perspective_)) { + if (config.HasClientRequestedIndependentOption(kMTUL, perspective_)) { SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeLow); } + if (debug_visitor_ != nullptr) { debug_visitor_->OnSetFromConfig(config); } @@ -443,16 +446,11 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { } if (config.HasClientSentConnectionOption(k7PTO, perspective_)) { max_consecutive_ptos_ = 6; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 3, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 3, 8); } if (config.HasClientSentConnectionOption(k8PTO, perspective_)) { max_consecutive_ptos_ = 7; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 4, 4); - } - if (GetQuicReloadableFlag(quic_skip_packet_number_for_pto) && - config.HasClientSentConnectionOption(kPTOS, perspective_)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_skip_packet_number_for_pto); - skip_packet_number_for_pto_ = true; + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 4, 8); } } if (config.HasClientSentConnectionOption(kNSTP, perspective_)) { @@ -506,11 +504,9 @@ void QuicConnection::SetMaxPacingRate(QuicBandwidth max_pacing_rate) { sent_packet_manager_.SetMaxPacingRate(max_pacing_rate); } -void QuicConnection::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) { - sent_packet_manager_.AdjustNetworkParameters(bandwidth, rtt, - allow_cwnd_to_decrease); +void QuicConnection::AdjustNetworkParameters( + const SendAlgorithmInterface::NetworkParams& params) { + sent_packet_manager_.AdjustNetworkParameters(params); } QuicBandwidth QuicConnection::MaxPacingRate() const { @@ -657,8 +653,8 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id, << ", received token " << QuicTextUtils::HexEncode(retry_token); server_connection_id_ = new_connection_id; - packet_generator_.SetServerConnectionId(server_connection_id_); - packet_generator_.SetRetryToken(retry_token); + packet_creator_.SetServerConnectionId(server_connection_id_); + packet_creator_.SetRetryToken(retry_token); // Reinstall initial crypters because the connection ID changed. InstallInitialCrypters(server_connection_id_); @@ -751,7 +747,7 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) { GetServerConnectionIdAsRecipient(header, perspective_)) || PacketCanReplaceConnectionId(header, perspective_)); - if (packet_generator_.HasPendingFrames()) { + if (packet_creator_.HasPendingFrames()) { // Incoming packets may change a queued ACK frame. const std::string error_details = "Pending frames must be serialized before incoming packets are " @@ -762,32 +758,41 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) { return false; } - if (!version_negotiated_ && perspective_ == Perspective::IS_SERVER) { - if (!header.version_flag) { - // Packets should have the version flag till version negotiation is - // done. - std::string error_details = - QuicStrCat(ENDPOINT, "Packet ", header.packet_number.ToUint64(), - " without version flag before version negotiated."); - QUIC_DLOG(WARNING) << error_details; - CloseConnection(QUIC_INVALID_VERSION, error_details, - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; - } else { - DCHECK_EQ(header.version, version()); - version_negotiated_ = true; - framer_.InferPacketHeaderTypeFromVersion(); - visitor_->OnSuccessfulVersionNegotiation(version()); - if (debug_visitor_ != nullptr) { - debug_visitor_->OnSuccessfulVersionNegotiation(version()); + if (!quic_version_negotiated_by_default_at_server()) { + if (!version_negotiated_ && perspective_ == Perspective::IS_SERVER) { + if (!header.version_flag) { + // Packets should have the version flag till version negotiation is + // done. + std::string error_details = + QuicStrCat(ENDPOINT, "Packet ", header.packet_number.ToUint64(), + " without version flag before version negotiated."); + QUIC_DLOG(WARNING) << error_details; + CloseConnection(QUIC_INVALID_VERSION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } else { + DCHECK_EQ(header.version, version()); + version_negotiated_ = true; + framer_.InferPacketHeaderTypeFromVersion(); + visitor_->OnSuccessfulVersionNegotiation(version()); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnSuccessfulVersionNegotiation(version()); + } } + DCHECK(version_negotiated_); } - DCHECK(version_negotiated_); } return true; } +void QuicConnection::OnSuccessfulVersionNegotiation() { + visitor_->OnSuccessfulVersionNegotiation(version()); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnSuccessfulVersionNegotiation(version()); + } +} + void QuicConnection::OnDecryptedPacket(EncryptionLevel level) { last_decrypted_packet_level_ = level; last_packet_decrypted_ = true; @@ -797,6 +802,11 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) { address_validated_ = true; } + if (use_handshake_delegate_) { + visitor_->OnPacketDecrypted(level); + return; + } + // Once the server receives a forward secure packet, the handshake is // confirmed. if (level == ENCRYPTION_FORWARD_SECURE && @@ -909,6 +919,7 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) { visitor_->OnStreamFrame(frame); stats_.stream_bytes_received += frame.data_length; should_last_packet_instigate_acks_ = true; + consecutive_retransmittable_on_wire_ping_count_ = 0; return connected_; } @@ -955,7 +966,11 @@ bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked, largest_acked > GetLargestSentPacket()) { QUIC_DLOG(WARNING) << ENDPOINT << "Peer's observed unsent packet:" << largest_acked - << " vs " << GetLargestSentPacket(); + << " vs " << GetLargestSentPacket() + << ". SupportsMultiplePacketNumberSpaces():" + << SupportsMultiplePacketNumberSpaces() + << ", last_decrypted_packet_level_:" + << last_decrypted_packet_level_; // We got an ack for data we have not sent. CloseConnection(QUIC_INVALID_ACK_DATA, "Largest observed too high.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -1040,12 +1055,8 @@ bool QuicConnection::OnAckFrameEnd(QuicPacketNumber start) { // If the incoming ack's packets set expresses received packets: peer is still // acking packets which we never care about. // Send an ack to raise the high water mark. - bool send_stop_waiting = GetLeastUnacked() > start; - if (GetQuicReloadableFlag(quic_simplify_stop_waiting) && - no_stop_waiting_frames_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_simplify_stop_waiting); - send_stop_waiting = false; - } + const bool send_stop_waiting = + no_stop_waiting_frames_ ? false : GetLeastUnacked() > start; PostProcessAfterAckFrame(send_stop_waiting, ack_result == PACKETS_NEWLY_ACKED); processing_ack_frame_ = false; @@ -1298,9 +1309,7 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnWindowUpdateFrame(frame, time_of_last_received_packet_); } - QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received for stream: " - << frame.stream_id - << " with byte offset: " << frame.byte_offset; + QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received " << frame; visitor_->OnWindowUpdateFrame(frame); should_last_packet_instigate_acks_ = true; return connected_; @@ -1562,7 +1571,7 @@ void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic, framer_.supported_versions()) << "}, " << (ietf_quic ? "" : "!") << "ietf_quic"; std::unique_ptr version_packet( - packet_generator_.SerializeVersionNegotiationPacket( + packet_creator_.SerializeVersionNegotiationPacket( ietf_quic, has_length_prefix, framer_.supported_versions())); QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {" << ParsedQuicVersionVectorToString(framer_.supported_versions()) @@ -1599,7 +1608,7 @@ size_t QuicConnection::SendCryptoData(EncryptionLevel level, return 0; } ScopedPacketFlusher flusher(this); - return packet_generator_.ConsumeCryptoData(level, write_length, offset); + return packet_creator_.ConsumeCryptoData(level, write_length, offset); } QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, @@ -1617,7 +1626,7 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, // packet (a handshake packet from client to server could result in a REJ or a // SHLO from the server, leading to two different decrypters at the server.) ScopedPacketFlusher flusher(this); - return packet_generator_.ConsumeData(id, write_length, offset, state); + return packet_creator_.ConsumeData(id, write_length, offset, state); } bool QuicConnection::SendControlFrame(const QuicFrame& frame) { @@ -1635,14 +1644,14 @@ bool QuicConnection::SendControlFrame(const QuicFrame& frame) { } ScopedPacketFlusher flusher(this); const bool consumed = - packet_generator_.ConsumeRetransmittableControlFrame(frame); + packet_creator_.ConsumeRetransmittableControlFrame(frame); if (!consumed) { QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame; return false; } if (frame.type == PING_FRAME) { // Flush PING frame immediately. - packet_generator_.FlushAllQueuedFrames(); + packet_creator_.FlushCurrentPacket(); if (debug_visitor_ != nullptr) { debug_visitor_->OnPingSent(); } @@ -1661,32 +1670,9 @@ void QuicConnection::OnStreamReset(QuicStreamId id, return; } // Flush stream frames of reset stream. - if (packet_generator_.HasPendingStreamFramesOfStream(id)) { + if (packet_creator_.HasPendingStreamFramesOfStream(id)) { ScopedPacketFlusher flusher(this); - packet_generator_.FlushAllQueuedFrames(); - } - - sent_packet_manager_.CancelRetransmissionsForStream(id); - // Remove all queued packets which only contain data for the reset stream. - // TODO(fayang): consider removing this because it should be rarely executed. - auto packet_iterator = queued_packets_.begin(); - while (packet_iterator != queued_packets_.end()) { - QuicFrames* retransmittable_frames = - &packet_iterator->retransmittable_frames; - if (retransmittable_frames->empty()) { - ++packet_iterator; - continue; - } - // NOTE THAT RemoveFramesForStream removes only STREAM frames - // for the specified stream. - RemoveFramesForStream(retransmittable_frames, id); - if (!retransmittable_frames->empty()) { - ++packet_iterator; - continue; - } - delete[] packet_iterator->encrypted_buffer; - ClearSerializedPacket(&(*packet_iterator)); - packet_iterator = queued_packets_.erase(packet_iterator); + packet_creator_.FlushCurrentPacket(); } // TODO(ianswett): Consider checking for 3 RTOs when the last stream is // cancelled as well. @@ -1707,7 +1693,11 @@ const QuicConnectionStats& QuicConnection::GetStats() { stats_.srtt_us = srtt.ToMicroseconds(); stats_.estimated_bandwidth = sent_packet_manager_.BandwidthEstimate(); - stats_.max_packet_size = packet_generator_.GetCurrentMaxPacketLength(); + if (GetQuicReloadableFlag(quic_log_ack_aggregation_stats)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_log_ack_aggregation_stats); + sent_packet_manager_.GetSendAlgorithm()->PopulateConnectionStats(&stats_); + } + stats_.max_packet_size = packet_creator_.max_packet_length(); stats_.max_received_packet_size = largest_received_packet_size_; return stats_; } @@ -1879,9 +1869,6 @@ void QuicConnection::OnCanWrite() { SendAck(); } } - if (!session_decides_what_to_write()) { - WritePendingRetransmissions(); - } WriteNewData(); } @@ -1949,7 +1936,7 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { << server_connection_id_ << " with " << header.source_connection_id; server_connection_id_ = header.source_connection_id; - packet_generator_.SetServerConnectionId(server_connection_id_); + packet_creator_.SetServerConnectionId(server_connection_id_); } if (!ValidateReceivedPacketNumber(header.packet_number)) { @@ -1964,13 +1951,10 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { // it should stop sending version since the version negotiation is done. // IETF QUIC stops sending version once encryption level switches to // forward secure. - packet_generator_.StopSendingVersion(); + packet_creator_.StopSendingVersion(); } version_negotiated_ = true; - visitor_->OnSuccessfulVersionNegotiation(version()); - if (debug_visitor_ != nullptr) { - debug_visitor_->OnSuccessfulVersionNegotiation(version()); - } + OnSuccessfulVersionNegotiation(); } } @@ -1980,7 +1964,7 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { if (perspective_ == Perspective::IS_SERVER && encryption_level_ == ENCRYPTION_INITIAL && - last_size_ > packet_generator_.GetCurrentMaxPacketLength()) { + last_size_ > packet_creator_.max_packet_length()) { SetMaxPacketLength(last_size_); } return true; @@ -2015,37 +1999,9 @@ void QuicConnection::WriteQueuedPackets() { } QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite", - queued_packets_.size(), 1, 1000, 50, ""); - while (!queued_packets_.empty()) { - DCHECK(!treat_queued_packets_as_sent_); - // WritePacket() can potentially clear all queued packets, so we need to - // save the first queued packet to a local variable before calling it. - SerializedPacket packet(std::move(queued_packets_.front())); - queued_packets_.pop_front(); - - const bool write_result = WritePacket(&packet); - - if (connected_ && !write_result) { - // Write failed but connection is open, re-insert |packet| into the - // front of the queue, it will be retried later. - queued_packets_.emplace_front(std::move(packet)); - break; - } - - delete[] packet.encrypted_buffer; - ClearSerializedPacket(&packet); - if (!connected_) { - DCHECK(queued_packets_.empty()) << "Queued packets should have been " - "cleared while closing connection"; - break; - } - - // Continue to send the next packet in queue. - } + buffered_packets_.size(), 1, 1000, 50, ""); while (!buffered_packets_.empty()) { - DCHECK(treat_queued_packets_as_sent_); - QUIC_RELOADABLE_FLAG_COUNT_N(quic_treat_queued_packets_as_sent, 1, 3); if (HandleWriteBlocked()) { break; } @@ -2054,7 +2010,7 @@ void QuicConnection::WriteQueuedPackets() { packet.encrypted_buffer.data(), packet.encrypted_buffer.length(), packet.self_address.host(), packet.peer_address, per_packet_options_); QUIC_DVLOG(1) << ENDPOINT << "Sending buffered packet, result: " << result; - if (mtu_discovery_v2_ && IsMsgTooBig(result) && + if (IsMsgTooBig(result) && packet.encrypted_buffer.length() > long_term_mtu_) { // When MSG_TOO_BIG is returned, the system typically knows what the // actual MTU is, so there is no need to probe further. @@ -2078,35 +2034,6 @@ void QuicConnection::WriteQueuedPackets() { } } -void QuicConnection::WritePendingRetransmissions() { - DCHECK(!session_decides_what_to_write()); - // Keep writing as long as there's a pending retransmission which can be - // written. - while (sent_packet_manager_.HasPendingRetransmissions() && - CanWrite(HAS_RETRANSMITTABLE_DATA)) { - const QuicPendingRetransmission pending = - sent_packet_manager_.NextPendingRetransmission(); - - // Re-packetize the frames with a new packet number for retransmission. - // Retransmitted packets use the same packet number length as the - // original. - // Flush the packet generator before making a new packet. - // TODO(ianswett): Implement ReserializeAllFrames as a separate path that - // does not require the creator to be flushed. - // TODO(fayang): FlushAllQueuedFrames should only be called once, and should - // be moved outside of the loop. Also, CanWrite is not checked after the - // generator is flushed. - { - ScopedPacketFlusher flusher(this); - packet_generator_.FlushAllQueuedFrames(); - } - DCHECK(!packet_generator_.HasPendingFrames()); - char buffer[kMaxOutgoingPacketSize]; - packet_generator_.ReserializeAllFrames(pending, buffer, - kMaxOutgoingPacketSize); - } -} - void QuicConnection::SendProbingRetransmissions() { while (sent_packet_manager_.GetSendAlgorithm()->ShouldSendProbingPacket() && CanWrite(HAS_RETRANSMITTABLE_DATA)) { @@ -2115,11 +2042,6 @@ void QuicConnection::SendProbingRetransmissions() { << "Cannot send probing retransmissions: nothing to retransmit."; break; } - - if (!session_decides_what_to_write()) { - DCHECK(sent_packet_manager_.HasPendingRetransmissions()); - WritePendingRetransmissions(); - } } } @@ -2187,8 +2109,7 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) { return false; } - if (session_decides_what_to_write() && - sent_packet_manager_.pending_timer_transmission_count() > 0) { + if (sent_packet_manager_.pending_timer_transmission_count() > 0) { // Force sending the retransmissions for HANDSHAKE, TLP, RTO, PROBING cases. return true; } @@ -2238,21 +2159,16 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { QUIC_BUG << "Attempt to write packet:" << packet->packet_number << " after:" << sent_packet_manager_.GetLargestSentPacket(); QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsAtOutOfOrder", - queued_packets_.size(), 1, 1000, 50, ""); + buffered_packets_.size(), 1, 1000, 50, ""); CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return true; } - SerializedPacketFate fate = DeterminePacketFate(); + SerializedPacketFate fate = DeterminePacketFate( + /*is_mtu_discovery=*/packet->encrypted_length > long_term_mtu_); // Termination packets are encrypted and saved, so don't exit early. const bool is_termination_packet = IsTerminationPacket(*packet); - if (!treat_queued_packets_as_sent_ && HandleWriteBlocked() && - !is_termination_packet) { - return false; - } - QuicPacketNumber packet_number = packet->packet_number; - QuicPacketLength encrypted_length = packet->encrypted_length; // Termination packets are eventually owned by TimeWaitListManager. // Others are deleted at the end of this call. @@ -2265,18 +2181,13 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { char* buffer_copy = CopyBuffer(*packet); termination_packets_->emplace_back( new QuicEncryptedPacket(buffer_copy, encrypted_length, true)); - // This assures we won't try to write *forced* packets when blocked. - // Return true to stop processing. - if (!treat_queued_packets_as_sent_ && HandleWriteBlocked()) { - return true; - } } const bool looks_like_mtu_probe = packet->retransmittable_frames.empty() && packet->encrypted_length > long_term_mtu_; DCHECK_LE(encrypted_length, kMaxOutgoingPacketSize); if (!looks_like_mtu_probe) { - DCHECK_LE(encrypted_length, packet_generator_.GetCurrentMaxPacketLength()); + DCHECK_LE(encrypted_length, packet_creator_.max_packet_length()); } QUIC_DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : " << (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA @@ -2284,7 +2195,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { : " ack only ") << ", encryption level: " << EncryptionLevelToString(packet->encryption_level) - << ", encrypted length:" << encrypted_length; + << ", encrypted length:" << encrypted_length + << ", fate: " << SerializedPacketFateToString(fate); QUIC_DVLOG(2) << ENDPOINT << "packet(" << packet_number << "): " << std::endl << QuicTextUtils::HexDump(QuicStringPiece( packet->encrypted_buffer, encrypted_length)); @@ -2307,11 +2219,36 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { WriteResult result(WRITE_STATUS_OK, encrypted_length); switch (fate) { case COALESCE: - DCHECK(false); + QUIC_BUG_IF(!version().CanSendCoalescedPackets()); + if (!coalesced_packet_.MaybeCoalescePacket( + *packet, self_address(), peer_address(), + helper_->GetStreamSendBufferAllocator(), + packet_creator_.max_packet_length())) { + // Failed to coalesce packet, flush current coalesced packet. + if (!FlushCoalescedPacket()) { + // Failed to flush coalesced packet, write error has been handled. + return false; + } + if (!coalesced_packet_.MaybeCoalescePacket( + *packet, self_address(), peer_address(), + helper_->GetStreamSendBufferAllocator(), + packet_creator_.max_packet_length())) { + // Failed to coalesce packet even it is the only packet, raise a write + // error. + QUIC_DLOG(ERROR) << ENDPOINT << "Failed to coalesce packet"; + result.error_code = WRITE_STATUS_FAILED_TO_COALESCE_PACKET; + break; + } + } + if (coalesced_packet_.length() < coalesced_packet_.max_packet_length()) { + QUIC_DVLOG(1) << ENDPOINT << "Trying to set soft max packet length to " + << coalesced_packet_.max_packet_length() - + coalesced_packet_.length(); + packet_creator_.SetSoftMaxPacketLength( + coalesced_packet_.max_packet_length() - coalesced_packet_.length()); + } break; case BUFFER: - DCHECK(treat_queued_packets_as_sent_); - QUIC_RELOADABLE_FLAG_COUNT_N(quic_treat_queued_packets_as_sent, 2, 3); QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number << " to buffered packets"; buffered_packets_.emplace_back(*packet, self_address(), peer_address()); @@ -2321,6 +2258,11 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { self_address().host(), peer_address(), per_packet_options_); 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; default: DCHECK(false); break; @@ -2341,31 +2283,22 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // duplicate packet being sent. The helper must call OnCanWrite // when the write completes, and OnWriteError if an error occurs. if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) { - if (treat_queued_packets_as_sent_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_treat_queued_packets_as_sent, 3, 3); - QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number - << " to buffered packets"; - buffered_packets_.emplace_back(*packet, self_address(), peer_address()); - } else { - return false; - } + QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number + << " to buffered packets"; + buffered_packets_.emplace_back(*packet, self_address(), peer_address()); } } // In some cases, an MTU probe can cause EMSGSIZE. This indicates that the // MTU discovery is permanently unsuccessful. if (IsMsgTooBig(result) && looks_like_mtu_probe) { - if (mtu_discovery_v2_) { - // When MSG_TOO_BIG is returned, the system typically knows what the - // actual MTU is, so there is no need to probe further. - // TODO(wub): Reduce max packet size to a safe default, or the actual MTU. - QUIC_DVLOG(1) << ENDPOINT << " MTU probe packet too big, size:" - << packet->encrypted_length - << ", long_term_mtu_:" << long_term_mtu_; - mtu_discoverer_.Disable(); - } else { - mtu_discovery_target_ = 0; - } + // When MSG_TOO_BIG is returned, the system typically knows what the + // actual MTU is, so there is no need to probe further. + // TODO(wub): Reduce max packet size to a safe default, or the actual MTU. + QUIC_DVLOG(1) << ENDPOINT << " MTU probe packet too big, size:" + << packet->encrypted_length + << ", long_term_mtu_:" << long_term_mtu_; + mtu_discoverer_.Disable(); mtu_discovery_alarm_->Cancel(); // The write failed, but the writer is not blocked, so return true. return true; @@ -2382,8 +2315,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { if (debug_visitor_ != nullptr) { // Pass the write result to the visitor. - debug_visitor_->OnPacketSent(*packet, packet->original_packet_number, - packet->transmission_type, packet_send_time); + debug_visitor_->OnPacketSent(*packet, packet->transmission_type, + packet_send_time); } if (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA) { if (!is_path_degrading_ && !path_degrading_alarm_->IsSet()) { @@ -2412,8 +2345,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { } const bool in_flight = sent_packet_manager_.OnPacketSent( - packet, packet->original_packet_number, packet_send_time, - packet->transmission_type, IsRetransmittable(*packet)); + packet, packet_send_time, packet->transmission_type, + IsRetransmittable(*packet)); if (in_flight || !retransmission_alarm_->IsSet()) { SetRetransmissionAlarm(); @@ -2422,7 +2355,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // The packet number length must be updated after OnPacketSent, because it // may change the packet number length in packet. - packet_generator_.UpdatePacketNumberLength( + packet_creator_.UpdatePacketNumberLength( sent_packet_manager_.GetLeastUnacked(), sent_packet_manager_.EstimateMaxPacketsInFlight(max_packet_length())); @@ -2519,6 +2452,13 @@ void QuicConnection::OnWriteError(int error_code) { } char* QuicConnection::GetPacketBuffer() { + if (version().CanSendCoalescedPackets() && + sent_packet_manager_.handshake_state() < + QuicSentPacketManager::HANDSHAKE_CONFIRMED) { + // Do not use writer's packet buffer for coalesced packets which may contain + // multiple QUIC packets. + return nullptr; + } return writer_->GetNextWriteLocation(self_address().host(), peer_address()); } @@ -2542,8 +2482,7 @@ void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { return; } - if (serialized_packet->retransmittable_frames.empty() && - !serialized_packet->original_packet_number.IsInitialized()) { + if (serialized_packet->retransmittable_frames.empty()) { // Increment consecutive_num_packets_with_no_retransmittable_frames_ if // this packet is a new transmission with no retransmittable frames. ++consecutive_num_packets_with_no_retransmittable_frames_; @@ -2585,10 +2524,8 @@ void QuicConnection::OnPathMtuIncreased(QuicPacketLength packet_size) { if (packet_size > max_packet_length()) { const QuicByteCount old_max_packet_length = max_packet_length(); SetMaxPacketLength(packet_size); - if (mtu_discovery_v2_) { - mtu_discoverer_.OnMaxPacketLengthUpdated(old_max_packet_length, - max_packet_length()); - } + mtu_discoverer_.OnMaxPacketLengthUpdated(old_max_packet_length, + max_packet_length()); } } @@ -2609,17 +2546,7 @@ void QuicConnection::SendOrQueuePacket(SerializedPacket* packet) { QUIC_BUG << "packet.encrypted_buffer == nullptr in to SendOrQueuePacket"; return; } - // If there are already queued packets, queue this one immediately to ensure - // it's written in sequence number order. - if (!queued_packets_.empty() || !WritePacket(packet)) { - if (!treat_queued_packets_as_sent_) { - // Take ownership of the underlying encrypted packet. - packet->encrypted_buffer = CopyBuffer(*packet); - queued_packets_.push_back(*packet); - packet->retransmittable_frames.clear(); - } - } - + WritePacket(packet); ClearSerializedPacket(packet); } @@ -2639,7 +2566,7 @@ void QuicConnection::SendAck() { PopulateStopWaitingFrame(&stop_waiting); frames.push_back(QuicFrame(stop_waiting)); } - if (!packet_generator_.FlushAckFrame(frames)) { + if (!packet_creator_.FlushAckFrame(frames)) { return; } ResetAckStates(); @@ -2648,7 +2575,7 @@ void QuicConnection::SendAck() { return; } consecutive_num_packets_with_no_retransmittable_frames_ = 0; - if (packet_generator_.HasRetransmittableFrames() || + if (packet_creator_.HasPendingRetransmittableFrames() || visitor_->WillingAndAbleToWrite()) { // There are pending retransmittable frames. return; @@ -2665,9 +2592,9 @@ void QuicConnection::OnPathDegradingTimeout() { void QuicConnection::OnRetransmissionTimeout() { DCHECK(!sent_packet_manager_.unacked_packets().empty() || (sent_packet_manager_.handshake_mode_disabled() && - !sent_packet_manager_.handshake_confirmed())); + !IsHandshakeComplete())); const QuicPacketNumber previous_created_packet_number = - packet_generator_.packet_number(); + packet_creator_.packet_number(); if (close_connection_after_five_rtos_ && sent_packet_manager_.GetConsecutiveRtoCount() >= 4) { // Close on the 5th consecutive RTO, so after 4 previous RTOs have occurred. @@ -2686,14 +2613,20 @@ void QuicConnection::OnRetransmissionTimeout() { const auto retransmission_mode = sent_packet_manager_.OnRetransmissionTimeout(); - if (skip_packet_number_for_pto_ && + if (sent_packet_manager_.skip_packet_number_for_pto() && retransmission_mode == QuicSentPacketManager::PTO_MODE && sent_packet_manager_.pending_timer_transmission_count() == 1) { // Skip a packet number when a single PTO packet is sent to elicit an // immediate ACK. - packet_generator_.SkipNPacketNumbers( - 1, sent_packet_manager_.GetLeastUnacked(), + const QuicPacketCount num_packet_numbers_to_skip = 1; + packet_creator_.SkipNPacketNumbers( + num_packet_numbers_to_skip, sent_packet_manager_.GetLeastUnacked(), sent_packet_manager_.EstimateMaxPacketsInFlight(max_packet_length())); + if (GetQuicReloadableFlag(quic_on_packet_numbers_skipped) && + debug_visitor_ != nullptr) { + QUIC_RELOADABLE_FLAG_COUNT(quic_on_packet_numbers_skipped); + debug_visitor_->OnNPacketNumbersSkipped(num_packet_numbers_to_skip); + } } WriteIfNotBlocked(); @@ -2712,45 +2645,42 @@ void QuicConnection::OnRetransmissionTimeout() { WriteIfNotBlocked(); } - if (sent_packet_manager_.fix_rto_retransmission()) { - if (packet_generator_.packet_number() == previous_created_packet_number && - (retransmission_mode == QuicSentPacketManager::TLP_MODE || - retransmission_mode == QuicSentPacketManager::RTO_MODE || - retransmission_mode == QuicSentPacketManager::PTO_MODE) && - !visitor_->WillingAndAbleToWrite()) { - // Send PING if timer fires in RTO or PTO mode but there is no data to - // send. - // When TLP fires, either new data or tail loss probe should be sent. - // There is corner case where TLP fires after RTO because packets get - // acked. Two packets are marked RTO_RETRANSMITTED, but the first packet - // is retransmitted as two packets because of packet number length - // increases (please see QuicConnectionTest.RtoPacketAsTwo). - QUIC_DLOG_IF(WARNING, - retransmission_mode == QuicSentPacketManager::TLP_MODE && - stats_.rto_count == 0) - << "No packet gets sent when timer fires in TLP mode, sending PING"; - DCHECK_LT(0u, sent_packet_manager_.pending_timer_transmission_count()); - visitor_->SendPing(); - } - if (retransmission_mode == QuicSentPacketManager::PTO_MODE) { - sent_packet_manager_.AdjustPendingTimerTransmissions(); - } - if (retransmission_mode != QuicSentPacketManager::LOSS_MODE) { - // When timer fires in TLP or RTO mode, ensure 1) at least one packet is - // created, or there is data to send and available credit (such that - // packets will be sent eventually). - QUIC_BUG_IF( - packet_generator_.packet_number() == previous_created_packet_number && - (!visitor_->WillingAndAbleToWrite() || - sent_packet_manager_.pending_timer_transmission_count() == 0u)) - << "retransmission_mode: " << retransmission_mode - << ", packet_number: " << packet_generator_.packet_number() - << ", session has data to write: " - << visitor_->WillingAndAbleToWrite() - << ", writer is blocked: " << writer_->IsWriteBlocked() - << ", pending_timer_transmission_count: " - << sent_packet_manager_.pending_timer_transmission_count(); - } + if (packet_creator_.packet_number() == previous_created_packet_number && + (retransmission_mode == QuicSentPacketManager::TLP_MODE || + retransmission_mode == QuicSentPacketManager::RTO_MODE || + retransmission_mode == QuicSentPacketManager::PTO_MODE) && + !visitor_->WillingAndAbleToWrite()) { + // Send PING if timer fires in RTO or PTO mode but there is no data to + // send. + // When TLP fires, either new data or tail loss probe should be sent. + // There is corner case where TLP fires after RTO because packets get + // acked. Two packets are marked RTO_RETRANSMITTED, but the first packet + // is retransmitted as two packets because of packet number length + // increases (please see QuicConnectionTest.RtoPacketAsTwo). + QUIC_DLOG_IF(WARNING, + retransmission_mode == QuicSentPacketManager::TLP_MODE && + stats_.rto_count == 0) + << "No packet gets sent when timer fires in TLP mode, sending PING"; + DCHECK_LT(0u, sent_packet_manager_.pending_timer_transmission_count()); + visitor_->SendPing(); + } + if (retransmission_mode == QuicSentPacketManager::PTO_MODE) { + sent_packet_manager_.AdjustPendingTimerTransmissions(); + } + if (retransmission_mode != QuicSentPacketManager::LOSS_MODE) { + // When timer fires in TLP or RTO mode, ensure 1) at least one packet is + // created, or there is data to send and available credit (such that + // packets will be sent eventually). + QUIC_BUG_IF(packet_creator_.packet_number() == + previous_created_packet_number && + (!visitor_->WillingAndAbleToWrite() || + sent_packet_manager_.pending_timer_transmission_count() == 0u)) + << "retransmission_mode: " << retransmission_mode + << ", packet_number: " << packet_creator_.packet_number() + << ", session has data to write: " << visitor_->WillingAndAbleToWrite() + << ", writer is blocked: " << writer_->IsWriteBlocked() + << ", pending_timer_transmission_count: " + << sent_packet_manager_.pending_timer_transmission_count(); } // Ensure the retransmission alarm is always set if there are unacked packets @@ -2764,26 +2694,26 @@ void QuicConnection::OnRetransmissionTimeout() { void QuicConnection::SetEncrypter(EncryptionLevel level, std::unique_ptr encrypter) { - packet_generator_.SetEncrypter(level, std::move(encrypter)); + packet_creator_.SetEncrypter(level, std::move(encrypter)); } void QuicConnection::SetDiversificationNonce( const DiversificationNonce& nonce) { DCHECK_EQ(Perspective::IS_SERVER, perspective_); - packet_generator_.SetDiversificationNonce(nonce); + packet_creator_.SetDiversificationNonce(nonce); } void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) { QUIC_DVLOG(1) << ENDPOINT << "Setting default encryption level from " << EncryptionLevelToString(encryption_level_) << " to " << EncryptionLevelToString(level); - if (level != encryption_level_ && packet_generator_.HasPendingFrames()) { + if (level != encryption_level_ && packet_creator_.HasPendingFrames()) { // Flush all queued frames when encryption level changes. ScopedPacketFlusher flusher(this); - packet_generator_.FlushAllQueuedFrames(); + packet_creator_.FlushCurrentPacket(); } encryption_level_ = level; - packet_generator_.set_encryption_level(level); + packet_creator_.set_encryption_level(level); } void QuicConnection::SetDecrypter(EncryptionLevel level, @@ -2832,13 +2762,13 @@ const QuicDecrypter* QuicConnection::alternative_decrypter() const { void QuicConnection::QueueUndecryptablePacket( const QuicEncryptedPacket& packet) { - for (const auto& saved_packet : undecryptable_packets_) { - if (packet.data() == saved_packet->data() && - packet.length() == saved_packet->length()) { - QUIC_DVLOG(1) << ENDPOINT << "Not queueing known undecryptable packet"; - return; - } + for (const auto& saved_packet : undecryptable_packets_) { + if (packet.data() == saved_packet->data() && + packet.length() == saved_packet->length()) { + QUIC_DVLOG(1) << ENDPOINT << "Not queueing known undecryptable packet"; + return; } + } QUIC_DVLOG(1) << ENDPOINT << "Queueing undecryptable packet."; undecryptable_packets_.push_back(packet.Clone()); } @@ -2854,7 +2784,7 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { while (connected_ && !undecryptable_packets_.empty()) { // Making sure there is no pending frames when processing next undecrypted // packet because the queued ack frame may change. - packet_generator_.FlushAllQueuedFrames(); + packet_creator_.FlushCurrentPacket(); if (!connected_) { return; } @@ -2888,26 +2818,28 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { void QuicConnection::QueueCoalescedPacket(const QuicEncryptedPacket& packet) { QUIC_DVLOG(1) << ENDPOINT << "Queueing coalesced packet."; - coalesced_packets_.push_back(packet.Clone()); + received_coalesced_packets_.push_back(packet.Clone()); + ++stats_.num_coalesced_packets_received; } void QuicConnection::MaybeProcessCoalescedPackets() { bool processed = false; - while (connected_ && !coalesced_packets_.empty()) { + while (connected_ && !received_coalesced_packets_.empty()) { // Making sure there are no pending frames when processing the next // coalesced packet because the queued ack frame may change. - packet_generator_.FlushAllQueuedFrames(); + packet_creator_.FlushCurrentPacket(); if (!connected_) { return; } std::unique_ptr packet = - std::move(coalesced_packets_.front()); - coalesced_packets_.pop_front(); + std::move(received_coalesced_packets_.front()); + received_coalesced_packets_.pop_front(); QUIC_DVLOG(1) << ENDPOINT << "Processing coalesced packet"; if (framer_.ProcessPacket(*packet)) { processed = true; + ++stats_.num_coalesced_packets_processed; } else { // If we are unable to decrypt this packet, it might be // because the CHLO or SHLO packet was lost. @@ -2942,25 +2874,76 @@ void QuicConnection::CloseConnection( void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, const std::string& details) { - QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet."; - SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel()); - ClearQueuedPackets(); - // If there was a packet write error, write the smallest close possible. + if (!GetQuicReloadableFlag(quic_close_all_encryptions_levels2)) { + QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet."; + SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel()); + if (version().CanSendCoalescedPackets()) { + coalesced_packet_.Clear(); + } + ClearQueuedPackets(); + // If there was a packet write error, write the smallest close possible. + ScopedPacketFlusher flusher(this); + // When multiple packet number spaces is supported, an ACK frame will be + // bundled when connection is not write blocked. + if (!SupportsMultiplePacketNumberSpaces() && + error != QUIC_PACKET_WRITE_ERROR && + !GetUpdatedAckFrame().ack_frame->packets.Empty()) { + SendAck(); + } + QuicConnectionCloseFrame* frame; + + frame = new QuicConnectionCloseFrame(transport_version(), error, details, + framer_.current_received_frame_type()); + packet_creator_.ConsumeRetransmittableControlFrame(QuicFrame(frame)); + packet_creator_.FlushCurrentPacket(); + if (version().CanSendCoalescedPackets()) { + FlushCoalescedPacket(); + } + ClearQueuedPackets(); + return; + } + const EncryptionLevel current_encryption_level = encryption_level_; ScopedPacketFlusher flusher(this); - // When multiple packet number spaces is supported, an ACK frame will be - // bundled when connection is not write blocked. - if (!SupportsMultiplePacketNumberSpaces() && - error != QUIC_PACKET_WRITE_ERROR && - !GetUpdatedAckFrame().ack_frame->packets.Empty()) { - SendAck(); - } - QuicConnectionCloseFrame* frame; - - frame = new QuicConnectionCloseFrame(transport_version(), error, details, - framer_.current_received_frame_type()); - packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame)); - packet_generator_.FlushAllQueuedFrames(); + QUIC_RELOADABLE_FLAG_COUNT(quic_close_all_encryptions_levels2); + + // Now that the connection is being closed, discard any unsent packets + // so the only packets to be sent will be connection close packets. + if (version().CanSendCoalescedPackets()) { + coalesced_packet_.Clear(); + } + ClearQueuedPackets(); + + for (EncryptionLevel level : + {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, + ENCRYPTION_FORWARD_SECURE}) { + if (!framer_.HasEncrypterOfEncryptionLevel(level)) { + continue; + } + QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet at level: " + << EncryptionLevelToString(level); + SetDefaultEncryptionLevel(level); + // If there was a packet write error, write the smallest close possible. + // When multiple packet number spaces are supported, an ACK frame will + // be bundled by the ScopedPacketFlusher. Otherwise, an ACK must be sent + // explicitly. + if (!SupportsMultiplePacketNumberSpaces() && + error != QUIC_PACKET_WRITE_ERROR && + !GetUpdatedAckFrame().ack_frame->packets.Empty()) { + SendAck(); + } + auto* frame = + new QuicConnectionCloseFrame(transport_version(), error, details, + framer_.current_received_frame_type()); + packet_creator_.ConsumeRetransmittableControlFrame(QuicFrame(frame)); + packet_creator_.FlushCurrentPacket(); + } + if (version().CanSendCoalescedPackets()) { + FlushCoalescedPacket(); + } + // Since the connection is closing, if the connection close packets were not + // sent, then they should be discarded. ClearQueuedPackets(); + SetDefaultEncryptionLevel(current_encryption_level); } void QuicConnection::TearDownLocalConnectionState( @@ -3007,24 +2990,23 @@ void QuicConnection::CancelAllAlarms() { } QuicByteCount QuicConnection::max_packet_length() const { - return packet_generator_.GetCurrentMaxPacketLength(); + return packet_creator_.max_packet_length(); } void QuicConnection::SetMaxPacketLength(QuicByteCount length) { long_term_mtu_ = length; - packet_generator_.SetMaxPacketLength(GetLimitedMaxPacketSize(length)); + packet_creator_.SetMaxPacketLength(GetLimitedMaxPacketSize(length)); } bool QuicConnection::HasQueuedData() const { - return pending_version_negotiation_packet_ || !queued_packets_.empty() || - packet_generator_.HasPendingFrames() || !buffered_packets_.empty(); + return pending_version_negotiation_packet_ || + packet_creator_.HasPendingFrames() || !buffered_packets_.empty(); } bool QuicConnection::CanWriteStreamData() { // Don't write stream data if there are negotiation or queued data packets // to send. Otherwise, continue and bundle as many frames as possible. - if (pending_version_negotiation_packet_ || !queued_packets_.empty() || - !buffered_packets_.empty()) { + if (pending_version_negotiation_packet_ || !buffered_packets_.empty()) { return false; } @@ -3129,28 +3111,52 @@ void QuicConnection::SetPingAlarm() { // because it is expecting a response from the server. return; } - if (retransmittable_on_wire_timeout_.IsInfinite() || + if (initial_retransmittable_on_wire_timeout_.IsInfinite() || sent_packet_manager_.HasInFlightPackets()) { // Extend the ping alarm. ping_alarm_->Update(clock_->ApproximateNow() + ping_timeout_, QuicTime::Delta::FromSeconds(1)); return; } - DCHECK_LT(retransmittable_on_wire_timeout_, ping_timeout_); + DCHECK_LT(initial_retransmittable_on_wire_timeout_, ping_timeout_); + QuicTime::Delta retransmittable_on_wire_timeout = + initial_retransmittable_on_wire_timeout_; + int max_aggressive_retransmittable_on_wire_ping_count = + GetQuicFlag(FLAGS_quic_max_aggressive_retransmittable_on_wire_ping_count); + DCHECK_LE(0, max_aggressive_retransmittable_on_wire_ping_count); + if (consecutive_retransmittable_on_wire_ping_count_ > + max_aggressive_retransmittable_on_wire_ping_count) { + // Exponentially back off the timeout if the number of consecutive + // retransmittable on wire pings has exceeds the allowance. + int shift = consecutive_retransmittable_on_wire_ping_count_ - + max_aggressive_retransmittable_on_wire_ping_count; + retransmittable_on_wire_timeout = + initial_retransmittable_on_wire_timeout_ * (1 << shift); + } // If it's already set to an earlier time, then don't update it. if (ping_alarm_->IsSet() && ping_alarm_->deadline() < - clock_->ApproximateNow() + retransmittable_on_wire_timeout_) { + clock_->ApproximateNow() + retransmittable_on_wire_timeout) { + return; + } + + if (retransmittable_on_wire_timeout < ping_timeout_) { + // Use a shorter timeout if there are open streams, but nothing on the wire. + ping_alarm_->Update( + clock_->ApproximateNow() + retransmittable_on_wire_timeout, + QuicTime::Delta::FromMilliseconds(1)); + if (max_aggressive_retransmittable_on_wire_ping_count != 0) { + consecutive_retransmittable_on_wire_ping_count_++; + } return; } - // Use a shorter timeout if there are open streams, but nothing on the wire. - ping_alarm_->Update( - clock_->ApproximateNow() + retransmittable_on_wire_timeout_, - QuicTime::Delta::FromMilliseconds(1)); + + ping_alarm_->Update(clock_->ApproximateNow() + ping_timeout_, + QuicTime::Delta::FromMilliseconds(1)); } void QuicConnection::SetRetransmissionAlarm() { - if (packet_generator_.PacketFlusherAttached()) { + if (packet_creator_.PacketFlusherAttached()) { pending_retransmission_alarm_ = true; return; } @@ -3175,35 +3181,11 @@ void QuicConnection::SetPathDegradingAlarm() { } void QuicConnection::MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number) { - if (mtu_discovery_v2_) { - if (mtu_discovery_alarm_->IsSet() || - !mtu_discoverer_.ShouldProbeMtu(sent_packet_number)) { - return; - } - mtu_discovery_alarm_->Set(clock_->ApproximateNow()); + if (mtu_discovery_alarm_->IsSet() || + !mtu_discoverer_.ShouldProbeMtu(sent_packet_number)) { return; } - - // Do not set the alarm if the target size is less than the current size. - // This covers the case when |mtu_discovery_target_| is at its default value, - // zero. - if (mtu_discovery_target_ <= max_packet_length()) { - return; - } - - if (mtu_probe_count_ >= kMtuDiscoveryAttempts) { - return; - } - - if (mtu_discovery_alarm_->IsSet()) { - return; - } - - if (sent_packet_number >= next_mtu_probe_at_) { - // Use an alarm to send the MTU probe to ensure that no ScopedPacketFlushers - // are active. - mtu_discovery_alarm_->Set(clock_->ApproximateNow()); - } + mtu_discovery_alarm_->Set(clock_->ApproximateNow()); } void QuicConnection::MaybeSetAckAlarmTo(QuicTime time) { @@ -3220,9 +3202,9 @@ QuicConnection::ScopedPacketFlusher::ScopedPacketFlusher( return; } - if (!connection_->packet_generator_.PacketFlusherAttached()) { + if (!connection_->packet_creator_.PacketFlusherAttached()) { flush_and_set_pending_retransmission_alarm_on_delete_ = true; - connection->packet_generator_.AttachPacketFlusher(); + connection->packet_creator_.AttachPacketFlusher(); } } @@ -3261,12 +3243,13 @@ QuicConnection::ScopedPacketFlusher::~ScopedPacketFlusher() { connection_->SendAck(); } } - connection_->packet_generator_.Flush(); - connection_->FlushPackets(); - if (connection_->session_decides_what_to_write()) { - // Reset transmission type. - connection_->SetTransmissionType(NOT_RETRANSMISSION); + connection_->packet_creator_.Flush(); + if (connection_->version().CanSendCoalescedPackets()) { + connection_->FlushCoalescedPacket(); } + connection_->FlushPackets(); + // Reset transmission type. + connection_->SetTransmissionType(NOT_RETRANSMISSION); // Once all transmissions are done, check if there is any outstanding data // to send and notify the congestion controller if not. @@ -3294,7 +3277,7 @@ QuicConnection::ScopedPacketFlusher::~ScopedPacketFlusher() { } } DCHECK_EQ(flush_and_set_pending_retransmission_alarm_on_delete_, - !connection_->packet_generator_.PacketFlusherAttached()); + !connection_->packet_creator_.PacketFlusherAttached()); } QuicConnection::BufferedPacket::BufferedPacket( @@ -3305,6 +3288,16 @@ QuicConnection::BufferedPacket::BufferedPacket( self_address(self_address), peer_address(peer_address) {} +QuicConnection::BufferedPacket::BufferedPacket( + char* encrypted_buffer, + QuicPacketLength encrypted_length, + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address) + : encrypted_buffer(CopyBuffer(encrypted_buffer, encrypted_length), + encrypted_length), + self_address(self_address), + peer_address(peer_address) {} + QuicConnection::BufferedPacket::~BufferedPacket() { delete[] encrypted_buffer.data(); } @@ -3334,13 +3327,9 @@ bool QuicConnection::IsTerminationPacket(const SerializedPacket& packet) { } void QuicConnection::SetMtuDiscoveryTarget(QuicByteCount target) { - if (mtu_discovery_v2_) { - mtu_discoverer_.Disable(); - mtu_discoverer_.Enable(max_packet_length(), - GetLimitedMaxPacketSize(target)); - } else { - mtu_discovery_target_ = GetLimitedMaxPacketSize(target); - } + QUIC_DVLOG(2) << ENDPOINT << "SetMtuDiscoveryTarget: " << target; + mtu_discoverer_.Disable(); + mtu_discoverer_.Enable(max_packet_length(), GetLimitedMaxPacketSize(target)); } QuicByteCount QuicConnection::GetLimitedMaxPacketSize( @@ -3367,7 +3356,7 @@ void QuicConnection::SendMtuDiscoveryPacket(QuicByteCount target_mtu) { DCHECK_EQ(target_mtu, GetLimitedMaxPacketSize(target_mtu)); // Send the probe. - packet_generator_.GenerateMtuDiscoveryPacket(target_mtu); + packet_creator_.GenerateMtuDiscoveryPacket(target_mtu); } // TODO(zhongyi): change this method to generate a connectivity probing packet @@ -3422,7 +3411,7 @@ bool QuicConnection::SendGenericPathProbePacket( if (!VersionHasIetfQuicFrames(transport_version())) { // Non-IETF QUIC, generate a padded ping regardless of whether this is a // request or a response. - probing_packet = packet_generator_.SerializeConnectivityProbingPacket(); + probing_packet = packet_creator_.SerializeConnectivityProbingPacket(); } else { if (is_response) { // Respond using IETF QUIC PATH_RESPONSE frame @@ -3430,14 +3419,14 @@ bool QuicConnection::SendGenericPathProbePacket( // Pad the response if the request was a google connectivity probe // (padded). probing_packet = - packet_generator_.SerializePathResponseConnectivityProbingPacket( + packet_creator_.SerializePathResponseConnectivityProbingPacket( received_path_challenge_payloads_, /* is_padded = */ true); received_path_challenge_payloads_.clear(); } else { // Do not pad the response if the path challenge was not a google // connectivity probe. probing_packet = - packet_generator_.SerializePathResponseConnectivityProbingPacket( + packet_creator_.SerializePathResponseConnectivityProbingPacket( received_path_challenge_payloads_, /* is_padded = */ false); received_path_challenge_payloads_.clear(); @@ -3447,7 +3436,7 @@ bool QuicConnection::SendGenericPathProbePacket( transmitted_connectivity_probe_payload_ = std::make_unique(); probing_packet = - packet_generator_.SerializePathChallengeConnectivityProbingPacket( + packet_creator_.SerializePathChallengeConnectivityProbingPacket( transmitted_connectivity_probe_payload_.get()); if (!probing_packet) { transmitted_connectivity_probe_payload_ = nullptr; @@ -3484,15 +3473,13 @@ bool QuicConnection::SendGenericPathProbePacket( if (debug_visitor_ != nullptr) { debug_visitor_->OnPacketSent( - *probing_packet, probing_packet->original_packet_number, - probing_packet->transmission_type, packet_send_time); + *probing_packet, probing_packet->transmission_type, packet_send_time); } // Call OnPacketSent regardless of the write result. - sent_packet_manager_.OnPacketSent( - probing_packet.get(), probing_packet->original_packet_number, - packet_send_time, probing_packet->transmission_type, - NO_RETRANSMITTABLE_DATA); + sent_packet_manager_.OnPacketSent(probing_packet.get(), packet_send_time, + probing_packet->transmission_type, + NO_RETRANSMITTABLE_DATA); if (IsWriteBlockedStatus(result.status)) { if (probing_writer == writer_) { @@ -3511,35 +3498,13 @@ bool QuicConnection::SendGenericPathProbePacket( void QuicConnection::DiscoverMtu() { DCHECK(!mtu_discovery_alarm_->IsSet()); - if (mtu_discovery_v2_) { - const QuicPacketNumber largest_sent_packet = - sent_packet_manager_.GetLargestSentPacket(); - if (mtu_discoverer_.ShouldProbeMtu(largest_sent_packet)) { - ++mtu_probe_count_; - SendMtuDiscoveryPacket( - mtu_discoverer_.GetUpdatedMtuProbeSize(largest_sent_packet)); - } - DCHECK(!mtu_discovery_alarm_->IsSet()); - return; - } - - // Check if the MTU has been already increased. - if (mtu_discovery_target_ <= max_packet_length()) { - return; + const QuicPacketNumber largest_sent_packet = + sent_packet_manager_.GetLargestSentPacket(); + if (mtu_discoverer_.ShouldProbeMtu(largest_sent_packet)) { + ++mtu_probe_count_; + SendMtuDiscoveryPacket( + mtu_discoverer_.GetUpdatedMtuProbeSize(largest_sent_packet)); } - - // Calculate the packet number of the next probe *before* sending the current - // one. Otherwise, when SendMtuDiscoveryPacket() is called, - // MaybeSetMtuAlarm() will not realize that the probe has been just sent, and - // will reschedule this probe again. - packets_between_mtu_probes_ *= 2; - next_mtu_probe_at_ = sent_packet_manager_.GetLargestSentPacket() + - packets_between_mtu_probes_ + 1; - ++mtu_probe_count_; - - QUIC_DVLOG(2) << "Sending a path MTU discovery packet #" << mtu_probe_count_; - SendMtuDiscoveryPacket(mtu_discovery_target_); - DCHECK(!mtu_discovery_alarm_->IsSet()); } @@ -3623,7 +3588,7 @@ void QuicConnection::MaybeSendProbingRetransmissions() { DCHECK(fill_up_link_during_probing_); // Don't send probing retransmissions until the handshake has completed. - if (!sent_packet_manager_.handshake_confirmed() || + if (!IsHandshakeComplete() || sent_packet_manager().HasUnackedCryptoPackets()) { return; } @@ -3640,14 +3605,12 @@ void QuicConnection::MaybeSendProbingRetransmissions() { } void QuicConnection::CheckIfApplicationLimited() { - if (session_decides_what_to_write() && probing_retransmission_pending_) { + if (probing_retransmission_pending_) { return; } bool application_limited = - queued_packets_.empty() && buffered_packets_.empty() && - !sent_packet_manager_.HasPendingRetransmissions() && - !visitor_->WillingAndAbleToWrite(); + buffered_packets_.empty() && !visitor_->WillingAndAbleToWrite(); if (!application_limited) { return; @@ -3716,20 +3679,6 @@ void QuicConnection::UpdatePacketContent(PacketContent type) { current_effective_peer_migration_type_ = NO_CHANGE; } -void QuicConnection::MaybeEnableSessionDecidesWhatToWrite() { - // Only enable session decides what to write code path for version 42+, - // because it needs the receiver to allow receiving overlapping stream data. - const bool enable_session_decides_what_to_write = - transport_version() > QUIC_VERSION_39; - sent_packet_manager_.SetSessionDecideWhatToWrite( - enable_session_decides_what_to_write); - if (version().SupportsAntiAmplificationLimit()) { - sent_packet_manager_.EnableIetfPtoAndLossDetection(); - } - packet_generator_.SetCanSetTransmissionType( - enable_session_decides_what_to_write); -} - void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, bool acked_new_packet) { if (no_stop_waiting_frames_) { @@ -3777,11 +3726,7 @@ void QuicConnection::SetDataProducer( } void QuicConnection::SetTransmissionType(TransmissionType type) { - packet_generator_.SetTransmissionType(type); -} - -bool QuicConnection::session_decides_what_to_write() const { - return sent_packet_manager_.session_decides_what_to_write(); + packet_creator_.SetTransmissionType(type); } void QuicConnection::UpdateReleaseTimeIntoFuture() { @@ -3803,7 +3748,8 @@ void QuicConnection::ResetAckStates() { } MessageStatus QuicConnection::SendMessage(QuicMessageId message_id, - QuicMemSliceSpan message) { + QuicMemSliceSpan message, + bool flush) { if (!VersionSupportsMessageFrames(transport_version())) { QUIC_BUG << "MESSAGE frame is not supported for version " << transport_version(); @@ -3812,19 +3758,19 @@ MessageStatus QuicConnection::SendMessage(QuicMessageId message_id, if (message.total_length() > GetCurrentLargestMessagePayload()) { return MESSAGE_STATUS_TOO_LARGE; } - if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) { + if (!connected_ || (!flush && !CanWrite(HAS_RETRANSMITTABLE_DATA))) { return MESSAGE_STATUS_BLOCKED; } ScopedPacketFlusher flusher(this); - return packet_generator_.AddMessageFrame(message_id, message); + return packet_creator_.AddMessageFrame(message_id, message); } QuicPacketLength QuicConnection::GetCurrentLargestMessagePayload() const { - return packet_generator_.GetCurrentLargestMessagePayload(); + return packet_creator_.GetCurrentLargestMessagePayload(); } QuicPacketLength QuicConnection::GetGuaranteedLargestMessagePayload() const { - return packet_generator_.GetGuaranteedLargestMessagePayload(); + return packet_creator_.GetGuaranteedLargestMessagePayload(); } uint32_t QuicConnection::cipher_id() const { @@ -3838,7 +3784,7 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const { if (perspective_ == Perspective::IS_CLIENT) { return encryption_level_; } - if (sent_packet_manager_.handshake_confirmed()) { + if (IsHandshakeComplete()) { // A forward secure packet has been received. QUIC_BUG_IF(encryption_level_ != ENCRYPTION_FORWARD_SECURE) << ENDPOINT << "Unexpected connection close encryption level " @@ -3887,7 +3833,7 @@ void QuicConnection::SendAllPendingAcks() { QuicFrames frames; frames.push_back(uber_received_packet_manager_.GetUpdatedAckFrame( static_cast(i), clock_->ApproximateNow())); - const bool flushed = packet_generator_.FlushAckFrame(frames); + const bool flushed = packet_creator_.FlushAckFrame(frames); if (!flushed) { // Connection is write blocked. QUIC_BUG_IF(!writer_->IsWriteBlocked()) @@ -3913,7 +3859,7 @@ void QuicConnection::SendAllPendingAcks() { return; } consecutive_num_packets_with_no_retransmittable_frames_ = 0; - if (packet_generator_.HasRetransmittableFrames() || + if (packet_creator_.HasPendingRetransmittableFrames() || visitor_->WillingAndAbleToWrite()) { // There are pending retransmittable frames. return; @@ -3922,6 +3868,65 @@ void QuicConnection::SendAllPendingAcks() { visitor_->OnAckNeedsRetransmittableFrame(); } +bool QuicConnection::FlushCoalescedPacket() { + ScopedCoalescedPacketClearer clearer(&coalesced_packet_); + if (!version().CanSendCoalescedPackets()) { + QUIC_BUG_IF(coalesced_packet_.length() > 0); + return true; + } + if (coalesced_packet_.length() == 0) { + return true; + } + QUIC_DVLOG(1) << ENDPOINT << "Sending coalesced packet"; + char buffer[kMaxOutgoingPacketSize]; + const size_t length = packet_creator_.SerializeCoalescedPacket( + coalesced_packet_, buffer, coalesced_packet_.max_packet_length()); + if (length == 0) { + return false; + } + + 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()); + return true; + } + + WriteResult result = writer_->WritePacket( + buffer, length, coalesced_packet_.self_address().host(), + coalesced_packet_.peer_address(), per_packet_options_); + if (IsWriteError(result.status)) { + OnWriteError(result.error_code); + return false; + } + if (IsWriteBlockedStatus(result.status)) { + visitor_->OnWriteBlocked(); + 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()); + } + } + // Account for added padding. + if (length > coalesced_packet_.length()) { + size_t padding_size = length - coalesced_packet_.length(); + if (EnforceAntiAmplificationLimit()) { + bytes_sent_before_address_validation_ += padding_size; + } + stats_.bytes_sent += padding_size; + if (coalesced_packet_.initial_packet() != nullptr && + coalesced_packet_.initial_packet()->transmission_type != + NOT_RETRANSMISSION) { + stats_.bytes_retransmitted += padding_size; + } + } + return true; +} + void QuicConnection::MaybeEnableMultiplePacketNumberSpacesSupport() { if (version().handshake_protocol != PROTOCOL_TLS1_3) { return; @@ -3988,9 +3993,21 @@ bool QuicConnection::LimitedByAmplificationFactor() const { bytes_received_before_address_validation_; } -QuicConnection::SerializedPacketFate QuicConnection::DeterminePacketFate() { - if (treat_queued_packets_as_sent_ && - (!buffered_packets_.empty() || HandleWriteBlocked())) { +SerializedPacketFate QuicConnection::DeterminePacketFate( + bool is_mtu_discovery) { + if (version().CanSendCoalescedPackets() && + sent_packet_manager_.handshake_state() < + QuicSentPacketManager::HANDSHAKE_CONFIRMED && + !is_mtu_discovery) { + // 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 (version().CanSendCoalescedPackets() && !FlushCoalescedPacket()) { + return FAILED_TO_WRITE_COALESCED_PACKET; + } + if (!buffered_packets_.empty() || HandleWriteBlocked()) { return BUFFER; } return SEND_TO_WRITER; @@ -4037,7 +4054,7 @@ void QuicConnection::set_client_connection_id( << client_connection_id_ << " for connection with server connection ID " << server_connection_id_; - packet_generator_.SetClientConnectionId(client_connection_id_); + packet_creator_.SetClientConnectionId(client_connection_id_); framer_.SetExpectedClientConnectionIdLength(client_connection_id_.length()); } 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 3d07946b316..abd836f4c6d 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 @@ -37,7 +37,6 @@ #include "net/third_party/quiche/src/quic/core/quic_mtu_discovery.h" #include "net/third_party/quiche/src/quic/core/quic_one_block_arena.h" #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" -#include "net/third_party/quiche/src/quic/core/quic_packet_generator.h" #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" @@ -165,7 +164,10 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { virtual void OnForwardProgressConfirmed() = 0; // Called when a STOP_SENDING frame has been received. - virtual bool OnStopSendingFrame(const QuicStopSendingFrame& frame) = 0; + virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) = 0; + + // Called when a packet of encryption |level| has been successfully decrypted. + virtual void OnPacketDecrypted(EncryptionLevel level) = 0; }; // Interface which gets callbacks from the QuicConnection at interesting @@ -178,7 +180,6 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor // Called when a packet has been sent. virtual void OnPacketSent(const SerializedPacket& /*serialized_packet*/, - QuicPacketNumber /*original_packet_number*/, TransmissionType /*transmission_type*/, QuicTime /*sent_time*/) {} @@ -305,6 +306,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor // Called when a MaxStreamsFrame has been parsed. virtual void OnMaxStreamsFrame(const QuicMaxStreamsFrame& /*frame*/) {} + + // Called when |count| packet numbers have been skipped. + virtual void OnNPacketNumbersSkipped(QuicPacketCount /*count*/) {} }; class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface { @@ -364,6 +368,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Allows the client to adjust network parameters based on external // information. + void AdjustNetworkParameters( + const SendAlgorithmInterface::NetworkParams& params); void AdjustNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt, bool allow_cwnd_to_decrease); @@ -514,12 +520,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection void OnAuthenticatedIetfStatelessResetPacket( const QuicIetfStatelessResetPacket& packet) override; - // QuicPacketGenerator::DelegateInterface + // QuicPacketCreator::DelegateInterface bool ShouldGeneratePacket(HasRetransmittableData retransmittable, IsHandshake handshake) override; const QuicFrames MaybeBundleAckOpportunistically() override; - - // QuicPacketCreator::DelegateInterface char* GetPacketBuffer() override; void OnSerializedPacket(SerializedPacket* packet) override; void OnUnrecoverableError(QuicErrorCode error, @@ -553,21 +557,21 @@ class QUIC_EXPORT_PRIVATE QuicConnection DCHECK(!ping_alarm_->IsSet()); ping_timeout_ = ping_timeout; } - const QuicTime::Delta ping_timeout() { return ping_timeout_; } + const QuicTime::Delta ping_timeout() const { return ping_timeout_; } // Used in Chromium, but not internally. - // Sets a timeout for the ping alarm when there is no retransmittable data - // in flight, allowing for a more aggressive ping alarm in that case. - void set_retransmittable_on_wire_timeout( + // Sets an initial timeout for the ping alarm when there is no retransmittable + // data in flight, allowing for a more aggressive ping alarm in that case. + void set_initial_retransmittable_on_wire_timeout( QuicTime::Delta retransmittable_on_wire_timeout) { DCHECK(!ping_alarm_->IsSet()); - retransmittable_on_wire_timeout_ = retransmittable_on_wire_timeout; + initial_retransmittable_on_wire_timeout_ = retransmittable_on_wire_timeout; } - const QuicTime::Delta retransmittable_on_wire_timeout() { - return retransmittable_on_wire_timeout_; + const QuicTime::Delta initial_retransmittable_on_wire_timeout() const { + return initial_retransmittable_on_wire_timeout_; } // Used in Chromium, but not internally. void set_creator_debug_delegate(QuicPacketCreator::DebugDelegate* visitor) { - packet_generator_.set_debug_delegate(visitor); + packet_creator_.set_debug_delegate(visitor); } const QuicSocketAddress& self_address() const { return self_address_; } const QuicSocketAddress& peer_address() const { return direct_peer_address_; } @@ -595,12 +599,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection } // Testing only. - size_t NumQueuedPackets() const { - if (treat_queued_packets_as_sent_) { - return buffered_packets_.size(); - } - return queued_packets_.size(); - } + size_t NumQueuedPackets() const { return buffered_packets_.size(); } // Returns true if the underlying UDP socket is writable, there is // no queued data and the connection is not congestion-control @@ -743,8 +742,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection virtual void SendConnectivityProbingResponsePacket( const QuicSocketAddress& peer_address); - // Sends an MTU discovery packet of size |mtu_discovery_target_| and updates - // the MTU discovery alarm. + // Sends an MTU discovery packet and updates the MTU discovery alarm. void DiscoverMtu(); // Sets the session notifier on the SentPacketManager. @@ -757,8 +755,11 @@ class QUIC_EXPORT_PRIVATE QuicConnection void SetTransmissionType(TransmissionType type); // Tries to send |message| and returns the message status. + // If |flush| is false, this will return a MESSAGE_STATUS_BLOCKED + // when the connection is deemed unwritable. virtual MessageStatus SendMessage(QuicMessageId message_id, - QuicMemSliceSpan message); + QuicMemSliceSpan message, + bool flush); // Returns the largest payload that will fit into a single MESSAGE frame. // Because overhead can vary during a connection, this method should be @@ -785,9 +786,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicFramer& framer() const { return framer_; } - const QuicPacketGenerator& packet_generator() const { - return packet_generator_; - } + const QuicPacketCreator& packet_creator() const { return packet_creator_; } EncryptionLevel encryption_level() const { return encryption_level_; } EncryptionLevel last_decrypted_level() const { @@ -812,11 +811,11 @@ class QUIC_EXPORT_PRIVATE QuicConnection // can only be set to false if there is some other mechanism of preventing // amplification attacks, such as ICE (plus its a non-standard quic). void set_fully_pad_crypto_handshake_packets(bool new_value) { - packet_generator_.set_fully_pad_crypto_handshake_packets(new_value); + packet_creator_.set_fully_pad_crypto_handshake_packets(new_value); } bool fully_pad_during_crypto_handshake() const { - return packet_generator_.fully_pad_crypto_handshake_packets(); + return packet_creator_.fully_pad_crypto_handshake_packets(); } size_t min_received_before_ack_decimation() const; @@ -832,8 +831,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection defer_send_in_response_to_packets_ = defer; } - bool session_decides_what_to_write() const; - // Sets the current per-packet options for the connection. The QuicConnection // does not take ownership of |options|; |options| must live for as long as // the QuicConnection is in use. @@ -862,9 +859,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection NOT_PADDED_PING, // Set if the packet is not {PING, PADDING}. }; - // Whether the handshake is confirmed from this connection's perspective. - bool IsHandshakeConfirmed() const { - return sent_packet_manager_.handshake_confirmed(); + // Whether the handshake completes from this connection's perspective. + bool IsHandshakeComplete() const { + return sent_packet_manager_.handshake_state() >= + QuicSentPacketManager::HANDSHAKE_COMPLETE; } // Returns the largest received packet number sent by peer. @@ -890,6 +888,15 @@ class QUIC_EXPORT_PRIVATE QuicConnection // or the one sent after an IETF Retry. void InstallInitialCrypters(QuicConnectionId connection_id); + // Called when version is considered negotiated. + void OnSuccessfulVersionNegotiation(); + + bool quic_version_negotiated_by_default_at_server() const { + return quic_version_negotiated_by_default_at_server_; + } + + bool use_handshake_delegate() const { return use_handshake_delegate_; } + protected: // Calls cancel() on all the alarms owned by this connection. void CancelAllAlarms(); @@ -971,21 +978,18 @@ class QUIC_EXPORT_PRIVATE QuicConnection typedef std::list QueuedPacketList; - // Indicates the fate of a serialized packet in WritePacket(). - enum SerializedPacketFate : uint8_t { - COALESCE, // Try to coalesce packet. - BUFFER, // Buffer packet in buffered_packets_. - SEND_TO_WRITER, // Send packet to writer. - }; - // BufferedPacket stores necessary information (encrypted buffer and self/peer // addresses) of those packets which are serialized but failed to send because // socket is blocked. From unacked packet map and send algorithm's // perspective, buffered packets are treated as sent. - struct BufferedPacket { + struct QUIC_EXPORT_PRIVATE BufferedPacket { BufferedPacket(const SerializedPacket& packet, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address); + BufferedPacket(char* encrypted_buffer, + QuicPacketLength encrypted_length, + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address); BufferedPacket(const BufferedPacket& other) = delete; BufferedPacket(const BufferedPacket&& other) = delete; @@ -1042,9 +1046,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // blocked when this is called. void WriteQueuedPackets(); - // Writes as many pending retransmissions as possible. - void WritePendingRetransmissions(); - // Writes new data if congestion control allows. void WriteNewData(); @@ -1112,9 +1113,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // effective peer address change. void UpdatePacketContent(PacketContent type); - // Enables session decide what to write based on version and flags. - void MaybeEnableSessionDecidesWhatToWrite(); - // Called when last received ack frame has been processed. // |send_stop_waiting| indicates whether a stop waiting needs to be sent. // |acked_new_packet| is true if a previously-unacked packet was acked. @@ -1146,8 +1144,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection // and flags. void MaybeEnableMultiplePacketNumberSpacesSupport(); - // Returns packet fate when trying to write a packet. - SerializedPacketFate DeterminePacketFate(); + // Returns packet fate when trying to write a packet via WritePacket(). + SerializedPacketFate DeterminePacketFate(bool is_mtu_discovery); + + // Serialize and send coalesced_packet. Returns false if serialization fails + // or the write causes errors, otherwise, returns true. + bool FlushCoalescedPacket(); // Returns the encryption level the connection close packet should be sent at, // which is the highest encryption level that peer can guarantee to process. @@ -1259,7 +1261,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Collection of coalesced packets which were received while processing // the current packet. - QuicDeque> coalesced_packets_; + QuicDeque> received_coalesced_packets_; // Maximum number of undecryptable packets the connection will store. size_t max_undecryptable_packets_; @@ -1274,15 +1276,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool send_ietf_version_negotiation_packet_; bool send_version_negotiation_packet_with_prefixed_lengths_; - // When packets could not be sent because the socket was not writable, - // they are added to this list. All corresponding frames are in - // unacked_packets_ if they are to be retransmitted. Packets encrypted_buffer - // fields are owned by the QueuedPacketList, in order to ensure they outlast - // the original scope of the SerializedPacket. - // TODO(fayang): Remove this when deprecating - // quic_treat_queued_packets_as_sent. - QueuedPacketList queued_packets_; - // Contains the connection close packets if the connection has been closed. std::unique_ptr>> termination_packets_; @@ -1301,7 +1294,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Indicates how many consecutive times an ack has arrived which indicates // the peer needs to stop waiting for some packets. - // TODO(fayang): remove this when deprecating quic_simplify_stop_waiting. + // TODO(fayang): remove this when deprecating QUIC_VERSION_43. int stop_waiting_count_; // Indicates the retransmission alarm needs to be set. @@ -1314,8 +1307,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection // The timeout for PING. QuicTime::Delta ping_timeout_; - // Timeout for how long the wire can have no retransmittable packets. - QuicTime::Delta retransmittable_on_wire_timeout_; + // Initial timeout for how long the wire can have no retransmittable packets. + QuicTime::Delta initial_retransmittable_on_wire_timeout_; + + // Indicates how many retransmittable-on-wire pings have been emitted without + // receiving any new data in between. + int consecutive_retransmittable_on_wire_ping_count_; // Arena to store class implementations within the QuicConnection. QuicConnectionArena arena_; @@ -1344,7 +1341,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicConnectionVisitorInterface* visitor_; QuicConnectionDebugVisitor* debug_visitor_; - QuicPacketGenerator packet_generator_; + QuicPacketCreator packet_creator_; // Network idle time before this connection is closed. QuicTime::Delta idle_network_timeout_; @@ -1369,6 +1366,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicSentPacketManager sent_packet_manager_; // Indicates whether connection version has been negotiated. + // Always true for server connections. bool version_negotiated_; // Tracks if the connection was created by the server or the client. @@ -1392,19 +1390,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // version negotiation packet. ParsedQuicVersionVector server_supported_versions_; - // The size of the packet we are targeting while doing path MTU discovery. - QuicByteCount mtu_discovery_target_; - // The number of MTU probes already sent. size_t mtu_probe_count_; - // The number of packets between MTU probes. - QuicPacketCount packets_between_mtu_probes_; - - // The packet number of the packet after which the next MTU probe will be - // sent. - QuicPacketNumber next_mtu_probe_at_; - // The value of the MTU regularly used by the connection. This is different // from the value returned by max_packet_size(), as max_packet_size() returns // the value of the MTU as currently used by the serializer, so if @@ -1501,23 +1489,24 @@ class QUIC_EXPORT_PRIVATE QuicConnection // EnforceAntiAmplificationLimit returns true. bool address_validated_; - // If true, skip packet number before sending the last PTO retransmission. - bool skip_packet_number_for_pto_; - // Used to store content of packets which cannot be sent because of write // blocked. Packets' encrypted buffers are copied and owned by // buffered_packets_. From unacked_packet_map (and congestion control)'s - // perspective, those packets are considered sent. This is only used when - // treat_queued_packets_as_sent_ is true. + // perspective, those packets are considered sent. std::list buffered_packets_; - // Latched value of quic_treat_queued_packets_as_sent. - const bool treat_queued_packets_as_sent_; + // Used to coalesce packets of different encryption level into the same UDP + // datagram. Connection stops trying to coalesce packets if a forward secure + // packet gets acknowledged. + QuicCoalescedPacket coalesced_packet_; - // Latched value of quic_mtu_discovery_v2. - const bool mtu_discovery_v2_; - // Only used if quic_mtu_discovery_v2 is true. QuicConnectionMtuDiscoverer mtu_discoverer_; + + // Latched value of quic_version_negotiated_by_default_at_server. + const bool quic_version_negotiated_by_default_at_server_; + + // Latched value of quic_use_handshaker_delegate. + const bool use_handshake_delegate_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc index c2a8754af39..49e90b6bb38 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc @@ -14,11 +14,11 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.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" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h index 431cc741f60..25af43def29 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h @@ -127,7 +127,7 @@ QUIC_EXPORT_PRIVATE QuicConnectionId EmptyQuicConnectionId(); // Note however that this property is not guaranteed across process lifetimes. // This makes QuicConnectionIdHash suitable for data structures such as hash // tables but not for sending a hash over the network. -class QuicConnectionIdHash { +class QUIC_EXPORT_PRIVATE QuicConnectionIdHash { public: size_t operator()(QuicConnectionId const& connection_id) const noexcept { return connection_id.Hash(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc index 128bc93aa39..89f7e546d88 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc @@ -6,55 +6,6 @@ namespace quic { -QuicConnectionStats::QuicConnectionStats() - : bytes_sent(0), - packets_sent(0), - stream_bytes_sent(0), - packets_discarded(0), - bytes_received(0), - packets_received(0), - packets_processed(0), - stream_bytes_received(0), - bytes_retransmitted(0), - packets_retransmitted(0), - bytes_spuriously_retransmitted(0), - packets_spuriously_retransmitted(0), - packets_lost(0), - slowstart_count(0), - slowstart_num_rtts(0), - slowstart_packets_sent(0), - slowstart_bytes_sent(0), - slowstart_packets_lost(0), - slowstart_bytes_lost(0), - slowstart_duration(QuicTime::Delta::Zero()), - slowstart_start_time(QuicTime::Zero()), - packets_dropped(0), - undecryptable_packets_received_before_handshake_complete(0), - crypto_retransmit_count(0), - loss_timeout_count(0), - tlp_count(0), - rto_count(0), - pto_count(0), - min_rtt_us(0), - srtt_us(0), - max_packet_size(0), - max_received_packet_size(0), - estimated_bandwidth(QuicBandwidth::Zero()), - packets_reordered(0), - max_sequence_reordering(0), - max_time_reordering_us(0), - tcp_loss_events(0), - connection_creation_time(QuicTime::Zero()), - blocked_frames_received(0), - blocked_frames_sent(0), - num_connectivity_probing_received(0), - retry_packet_processed(false) {} - -QuicConnectionStats::QuicConnectionStats(const QuicConnectionStats& other) = - default; - -QuicConnectionStats::~QuicConnectionStats() {} - std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) { os << "{ bytes_sent: " << s.bytes_sent; os << " packets_sent: " << s.packets_sent; @@ -98,6 +49,10 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) { << s.num_connectivity_probing_received; os << " retry_packet_processed: " << (s.retry_packet_processed ? "yes" : "no"); + os << " num_coalesced_packets_received: " << s.num_coalesced_packets_received; + os << " num_coalesced_packets_processed: " + << s.num_coalesced_packets_processed; + os << " num_ack_aggregation_epochs: " << s.num_ack_aggregation_epochs; os << " }"; return os; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h index 805afd15a73..c76d591602b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h @@ -11,104 +11,107 @@ #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_time_accumulator.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" namespace quic { // Structure to hold stats for a QuicConnection. struct QUIC_EXPORT_PRIVATE QuicConnectionStats { - QuicConnectionStats(); - QuicConnectionStats(const QuicConnectionStats& other); - ~QuicConnectionStats(); - QUIC_EXPORT_PRIVATE friend std::ostream& operator<<( std::ostream& os, const QuicConnectionStats& s); - QuicByteCount bytes_sent; // Includes retransmissions. - QuicPacketCount packets_sent; + QuicByteCount bytes_sent = 0; // Includes retransmissions. + QuicPacketCount packets_sent = 0; // Non-retransmitted bytes sent in a stream frame. - QuicByteCount stream_bytes_sent; + QuicByteCount stream_bytes_sent = 0; // Packets serialized and discarded before sending. - QuicPacketCount packets_discarded; + QuicPacketCount packets_discarded = 0; // These include version negotiation and public reset packets, which do not // have packet numbers or frame data. - QuicByteCount bytes_received; // Includes duplicate data for a stream. + QuicByteCount bytes_received = 0; // Includes duplicate data for a stream. // Includes packets which were not processable. - QuicPacketCount packets_received; + QuicPacketCount packets_received = 0; // Excludes packets which were not processable. - QuicPacketCount packets_processed; - QuicByteCount stream_bytes_received; // Bytes received in a stream frame. + QuicPacketCount packets_processed = 0; + QuicByteCount stream_bytes_received = 0; // Bytes received in a stream frame. - QuicByteCount bytes_retransmitted; - QuicPacketCount packets_retransmitted; + QuicByteCount bytes_retransmitted = 0; + QuicPacketCount packets_retransmitted = 0; - QuicByteCount bytes_spuriously_retransmitted; - QuicPacketCount packets_spuriously_retransmitted; + QuicByteCount bytes_spuriously_retransmitted = 0; + QuicPacketCount packets_spuriously_retransmitted = 0; // Number of packets abandoned as lost by the loss detection algorithm. - QuicPacketCount packets_lost; + QuicPacketCount packets_lost = 0; // Number of times this connection went through the slow start phase. - uint32_t slowstart_count; + uint32_t slowstart_count = 0; // Number of round trips spent in slow start. - uint32_t slowstart_num_rtts; + uint32_t slowstart_num_rtts = 0; // Number of packets sent in slow start. - QuicPacketCount slowstart_packets_sent; + QuicPacketCount slowstart_packets_sent = 0; // Number of bytes sent in slow start. - QuicByteCount slowstart_bytes_sent; + QuicByteCount slowstart_bytes_sent = 0; // Number of packets lost exiting slow start. - QuicPacketCount slowstart_packets_lost; + QuicPacketCount slowstart_packets_lost = 0; // Number of bytes lost exiting slow start. - QuicByteCount slowstart_bytes_lost; - // Time spent in COMPLETED slow start phases. - QuicTime::Delta slowstart_duration; - // Start time of the last slow start phase. - QuicTime slowstart_start_time; + QuicByteCount slowstart_bytes_lost = 0; + // Time spent in slow start. Populated for BBRv1 and BBRv2. + QuicTimeAccumulator slowstart_duration; - QuicPacketCount packets_dropped; // Duplicate or less than least unacked. + QuicPacketCount packets_dropped = 0; // Duplicate or less than least unacked. // Packets that failed to decrypt when they were first received, // before the handshake was complete. - QuicPacketCount undecryptable_packets_received_before_handshake_complete; + QuicPacketCount undecryptable_packets_received_before_handshake_complete = 0; - size_t crypto_retransmit_count; + size_t crypto_retransmit_count = 0; // Count of times the loss detection alarm fired. At least one packet should // be lost when the alarm fires. - size_t loss_timeout_count; - size_t tlp_count; - size_t rto_count; // Count of times the rto timer fired. - size_t pto_count; + size_t loss_timeout_count = 0; + size_t tlp_count = 0; + size_t rto_count = 0; // Count of times the rto timer fired. + size_t pto_count = 0; - int64_t min_rtt_us; // Minimum RTT in microseconds. - int64_t srtt_us; // Smoothed RTT in microseconds. - QuicByteCount max_packet_size; - QuicByteCount max_received_packet_size; - QuicBandwidth estimated_bandwidth; + int64_t min_rtt_us = 0; // Minimum RTT in microseconds. + int64_t srtt_us = 0; // Smoothed RTT in microseconds. + QuicByteCount max_packet_size = 0; + QuicByteCount max_received_packet_size = 0; + QuicBandwidth estimated_bandwidth = QuicBandwidth::Zero(); // Reordering stats for received packets. // Number of packets received out of packet number order. - QuicPacketCount packets_reordered; + QuicPacketCount packets_reordered = 0; // Maximum reordering observed in packet number space. - QuicPacketCount max_sequence_reordering; + QuicPacketCount max_sequence_reordering = 0; // Maximum reordering observed in microseconds - int64_t max_time_reordering_us; + int64_t max_time_reordering_us = 0; // The following stats are used only in TcpCubicSender. // The number of loss events from TCP's perspective. Each loss event includes // one or more lost packets. - uint32_t tcp_loss_events; + uint32_t tcp_loss_events = 0; // Creation time, as reported by the QuicClock. - QuicTime connection_creation_time; + QuicTime connection_creation_time = QuicTime::Zero(); - uint64_t blocked_frames_received; - uint64_t blocked_frames_sent; + uint64_t blocked_frames_received = 0; + uint64_t blocked_frames_sent = 0; // Number of connectivity probing packets received by this connection. - uint64_t num_connectivity_probing_received; + uint64_t num_connectivity_probing_received = 0; // Whether a RETRY packet was successfully processed. - bool retry_packet_processed; + bool retry_packet_processed = false; + + // Number of received coalesced packets. + uint64_t num_coalesced_packets_received = 0; + // Number of successfully processed coalesced packets. + uint64_t num_coalesced_packets_processed = 0; + // Number of ack aggregation epochs. For the same number of bytes acked, the + // smaller this value, the more ack aggregation is going on. + uint64_t num_ack_aggregation_epochs = 0; }; } // 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 3d923a2deac..3babced88b6 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 @@ -36,7 +36,6 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h" #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" @@ -338,6 +337,7 @@ class TestPacketWriter : public QuicPacketWriter { final_bytes_of_previous_packet_(0), use_tagging_decrypter_(false), packets_write_attempts_(0), + connection_close_packets_(0), clock_(clock), write_pause_time_delta_(QuicTime::Delta::Zero()), max_packet_size_(kMaxOutgoingPacketSize), @@ -406,7 +406,9 @@ class TestPacketWriter : public QuicPacketWriter { 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_); } @@ -514,6 +516,10 @@ class TestPacketWriter : public QuicPacketWriter { 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 { @@ -550,6 +556,10 @@ class TestPacketWriter : public QuicPacketWriter { uint32_t packets_write_attempts() { return packets_write_attempts_; } + uint32_t connection_close_packets() const { + return connection_close_packets_; + } + void Reset() { framer_.Reset(); } void SetSupportedVersions(const ParsedQuicVersionVector& versions) { @@ -583,6 +593,7 @@ class TestPacketWriter : public QuicPacketWriter { uint32_t final_bytes_of_previous_packet_; bool use_tagging_decrypter_; uint32_t packets_write_attempts_; + uint32_t connection_close_packets_; MockClock* clock_; // If non-zero, the clock will pause during WritePacket for this amount of // time. @@ -631,6 +642,7 @@ class TestConnection : public QuicConnection { HasRetransmittableData retransmittable, bool has_ack, bool has_pending_frames) { + ScopedPacketFlusher flusher(this); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = QuicConnectionPeer::GetFramer(this)->EncryptPayload( @@ -641,7 +653,7 @@ class TestConnection : public QuicConnection { encrypted_length, has_ack, has_pending_frames); if (retransmittable == HAS_RETRANSMITTABLE_DATA) { serialized_packet.retransmittable_frames.push_back( - QuicFrame(QuicStreamFrame())); + QuicFrame(QuicPingFrame())); } OnSerializedPacket(&serialized_packet); } @@ -668,7 +680,7 @@ class TestConnection : public QuicConnection { if (!QuicUtils::IsCryptoStreamId(transport_version(), id) && this->encryption_level() == ENCRYPTION_INITIAL) { this->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); - if (perspective() == Perspective::IS_CLIENT && !IsHandshakeConfirmed()) { + if (perspective() == Perspective::IS_CLIENT && !IsHandshakeComplete()) { OnHandshakeComplete(); } if (version().SupportsAntiAmplificationLimit()) { @@ -769,14 +781,14 @@ class TestConnection : public QuicConnection { } // Enable path MTU discovery. Assumes that the test is performed from the - // client perspective and the higher value of MTU target is used. + // server perspective and the higher value of MTU target is used. void EnablePathMtuDiscovery(MockSendAlgorithm* send_algorithm) { - ASSERT_EQ(Perspective::IS_CLIENT, perspective()); + ASSERT_EQ(Perspective::IS_SERVER, perspective()); QuicConfig config; QuicTagVector connection_options; connection_options.push_back(kMTUH); - config.SetConnectionOptionsToSend(connection_options); + config.SetInitialReceivedConnectionOptions(connection_options); EXPECT_CALL(*send_algorithm, SetFromConfig(_, _)); SetFromConfig(config); @@ -964,7 +976,6 @@ class QuicConnectionTest : public QuicTestWithParam { Perspective::IS_CLIENT, version()), creator_(QuicConnectionPeer::GetPacketCreator(&connection_)), - generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)), manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)), frame1_(0, false, 0, QuicStringPiece(data1)), frame2_(0, false, 3, QuicStringPiece(data2)), @@ -1016,10 +1027,8 @@ class QuicConnectionTest : public QuicTestWithParam { frame1_.stream_id = stream_id; frame2_.stream_id = stream_id; connection_.set_visitor(&visitor_); - if (connection_.session_decides_what_to_write()) { - connection_.SetSessionNotifier(¬ifier_); - connection_.set_notifier(¬ifier_); - } + connection_.SetSessionNotifier(¬ifier_); + connection_.set_notifier(¬ifier_); connection_.SetSendAlgorithm(send_algorithm_); connection_.SetLossAlgorithm(loss_algorithm_.get()); EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); @@ -1034,23 +1043,22 @@ class QuicConnectionTest : public QuicTestWithParam { EXPECT_CALL(*send_algorithm_, BandwidthEstimate()) .Times(AnyNumber()) .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, PopulateConnectionStats(_)) + .Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, InSlowStart()).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnPacketDecrypted(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber()); - if (connection_.session_decides_what_to_write()) { - EXPECT_CALL(visitor_, OnCanWrite()) - .WillRepeatedly( - Invoke(¬ifier_, &SimpleSessionNotifier::OnCanWrite)); - } else { - EXPECT_CALL(visitor_, OnCanWrite()).Times(AnyNumber()); - } + EXPECT_CALL(visitor_, OnCanWrite()) + .WillRepeatedly(Invoke(¬ifier_, &SimpleSessionNotifier::OnCanWrite)); EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) .WillRepeatedly(Return(false)); EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, OnPacketReceived(_, _, _)).Times(AnyNumber()); EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(AnyNumber()); EXPECT_CALL(*loss_algorithm_, GetLossTimeout()) .WillRepeatedly(Return(QuicTime::Zero())); @@ -1120,7 +1128,10 @@ class QuicConnectionTest : public QuicTestWithParam { QuicFrames frames; frames.push_back(QuicFrame(frame)); QuicPacketCreatorPeer::SetSendVersionInPacket( - &peer_creator_, connection_.perspective() == Perspective::IS_SERVER); + &peer_creator_, + QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_) < + ENCRYPTION_FORWARD_SECURE && + connection_.perspective() == Perspective::IS_SERVER); char buffer[kMaxOutgoingPacketSize]; SerializedPacket serialized_packet = @@ -1329,26 +1340,11 @@ class QuicConnectionTest : public QuicTestWithParam { void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written) { - if (connection_.session_decides_what_to_write()) { - notifier_.WriteOrBufferRstStream(id, error, bytes_written); - connection_.OnStreamReset(id, error); - return; - } - std::unique_ptr rst_stream = - std::make_unique(1, id, error, bytes_written); - if (connection_.SendControlFrame(QuicFrame(rst_stream.get()))) { - rst_stream.release(); - } + notifier_.WriteOrBufferRstStream(id, error, bytes_written); connection_.OnStreamReset(id, error); } - void SendPing() { - if (connection_.session_decides_what_to_write()) { - notifier_.WriteOrBufferPing(); - } else { - connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); - } - } + void SendPing() { notifier_.WriteOrBufferPing(); } void ProcessAckPacket(uint64_t packet_number, QuicAckFrame* frame) { if (packet_number > 1) { @@ -1536,8 +1532,8 @@ class QuicConnectionTest : public QuicTestWithParam { EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_INVALID_ACK_DATA, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_INVALID_ACK_DATA)); } void BlockOnNextWrite() { @@ -1567,6 +1563,10 @@ class QuicConnectionTest : public QuicTestWithParam { connection_.set_perspective(perspective); if (perspective == Perspective::IS_SERVER) { connection_.set_can_truncate_connection_ids(true); + QuicConnectionPeer::SetNegotiatedVersion(&connection_); + if (GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + connection_.OnSuccessfulVersionNegotiation(); + } } QuicFramerPeer::SetPerspective(&peer_framer_, QuicUtils::InvertPerspective(perspective)); @@ -1574,16 +1574,9 @@ class QuicConnectionTest : public QuicTestWithParam { void set_packets_between_probes_base( const QuicPacketCount packets_between_probes_base) { - if (GetQuicReloadableFlag(quic_mtu_discovery_v2)) { - QuicConnectionPeer::ReInitializeMtuDiscoverer( - &connection_, packets_between_probes_base, - QuicPacketNumber(packets_between_probes_base)); - } else { - QuicConnectionPeer::SetPacketsBetweenMtuProbes( - &connection_, packets_between_probes_base); - QuicConnectionPeer::SetNextMtuProbeAt( - &connection_, QuicPacketNumber(packets_between_probes_base)); - } + QuicConnectionPeer::ReInitializeMtuDiscoverer( + &connection_, packets_between_probes_base, + QuicPacketNumber(packets_between_probes_base)); } bool IsDefaultTestConfiguration() { @@ -1627,6 +1620,24 @@ class QuicConnectionTest : public QuicTestWithParam { } } + void MtuDiscoveryTestInit() { + set_perspective(Perspective::IS_SERVER); + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size + // across all encrypters. The initial encrypter used with IETF QUIC has a + // 16-byte overhead, while the NullEncrypter used throughout this test has a + // 12-byte overhead. This test tests behavior that relies on computing the + // packet size correctly, so by unsetting the initial encrypter, we avoid + // having a mismatch between the overheads for the encrypters used. In + // non-test scenarios all encrypters used for a given connection have the + // same overhead, either 12 bytes for ones using Google QUIC crypto, or 16 + // bytes for ones using TLS. + connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); + EXPECT_TRUE(connection_.connected()); + } + QuicConnectionId connection_id_; QuicFramer framer_; @@ -1642,7 +1653,6 @@ class QuicConnectionTest : public QuicTestWithParam { std::unique_ptr writer_; TestConnection connection_; QuicPacketCreator* creator_; - QuicPacketGenerator* generator_; QuicSentPacketManager* manager_; StrictMock visitor_; @@ -1727,8 +1737,6 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) { } TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1758,8 +1766,6 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) { } TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1793,7 +1799,6 @@ TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) { } TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1832,7 +1837,6 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { } TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); @@ -1870,7 +1874,6 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { } TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); @@ -1956,7 +1959,6 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { } TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); @@ -2032,29 +2034,17 @@ TEST_P(QuicConnectionTest, WriteOutOfOrderQueuedPackets) { writer_->SetWritable(); connection_.SendConnectivityProbingPacket(writer_.get(), connection_.peer_address()); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); - connection_.OnCanWrite(); - return; - } - EXPECT_CALL(visitor_, - OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_QUIC_BUG(connection_.OnCanWrite(), - "Attempt to write packet:1 after:2"); - EXPECT_FALSE(connection_.connected()); - TestConnectionCloseQuicErrorCode(QUIC_INTERNAL_ERROR); - const std::vector& connection_close_frames = - writer_->connection_close_frames(); - EXPECT_EQ("Packet written out of order.", - connection_close_frames[0].error_details); + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); + connection_.OnCanWrite(); } TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { // Regression test for b/74073386. { InSequence seq; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .Times(AtLeast(1)); + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(AtLeast(1)); } set_perspective(Perspective::IS_CLIENT); @@ -2067,12 +2057,8 @@ TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { connection_.SendStreamDataWithString(/*id=*/2, "foo", 0, NO_FIN); EXPECT_FALSE(connection_.connected()); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - // No need to buffer packets. - EXPECT_EQ(0u, connection_.NumQueuedPackets()); - } else { - EXPECT_EQ(1u, connection_.NumQueuedPackets()); - } + // No need to buffer packets. + EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_EQ(0u, connection_.GetStats().packets_discarded); connection_.OnCanWrite(); @@ -2080,7 +2066,6 @@ TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { } TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); @@ -2139,7 +2124,6 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { } TEST_P(QuicConnectionTest, ReceiveReorderedConnectivityProbingAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); @@ -2196,7 +2180,6 @@ TEST_P(QuicConnectionTest, ReceiveReorderedConnectivityProbingAtServer) { } TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); @@ -2397,8 +2380,6 @@ TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) { } TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - set_perspective(Perspective::IS_SERVER); connection_.SetMaxPacketLength(1000); @@ -2443,8 +2424,6 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { } TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - const QuicByteCount lower_max_packet_size = 1240; writer_->set_max_packet_size(lower_max_packet_size); set_perspective(Perspective::IS_SERVER); @@ -2708,18 +2687,13 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { connection_.SendStreamDataWithString(3, "foofoofoo", 9, NO_FIN); // Ack bundled. if (GetParam().no_stop_waiting) { - if (GetQuicReloadableFlag(quic_simplify_stop_waiting)) { - // Do not ACK acks. - EXPECT_EQ(1u, writer_->frame_count()); - } else { - EXPECT_EQ(2u, writer_->frame_count()); - } + // Do not ACK acks. + EXPECT_EQ(1u, writer_->frame_count()); } else { EXPECT_EQ(3u, writer_->frame_count()); } EXPECT_EQ(1u, writer_->stream_frames().size()); - if (GetParam().no_stop_waiting && - GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + if (GetParam().no_stop_waiting) { EXPECT_TRUE(writer_->ack_frames().empty()); } else { EXPECT_FALSE(writer_->ack_frames().empty()); @@ -2852,9 +2826,11 @@ TEST_P(QuicConnectionTest, LeastUnackedLower) { // one. This should cause a connection error. QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 7); if (!GetParam().no_stop_waiting) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .Times(AtLeast(1)); EXPECT_CALL(visitor_, - OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); + OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) + .Times(AtLeast(1)); } ProcessStopWaitingPacket(InitStopWaitingFrame(1)); if (!GetParam().no_stop_waiting) { @@ -2907,7 +2883,7 @@ TEST_P(QuicConnectionTest, AckUnsentData) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); QuicAckFrame frame = InitAckFrame(1); EXPECT_CALL(visitor_, OnCanWrite()).Times(0); ProcessAckPacket(&frame); @@ -3078,7 +3054,9 @@ TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); QuicConnection::ScopedPacketFlusher flusher(&connection_); connection_.SendStreamData3(); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); connection_.SendCryptoStreamData(); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -3366,11 +3344,6 @@ TEST_P(QuicConnectionTest, DoNotSendQueuedPacketForResetStream) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); writer_->SetWritable(); connection_.OnCanWrite(); - if (!connection_.session_decides_what_to_write()) { - // OnCanWrite will cause RST_STREAM be sent again. - connection_.SendControlFrame(QuicFrame(new QuicRstStreamFrame( - 1, stream_id, QUIC_ERROR_PROCESSING_STREAM, 14))); - } size_t padding_frame_count = writer_->padding_frames().size(); EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->rst_stream_frames().size()); @@ -3381,11 +3354,7 @@ TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) { BlockOnNextWrite(); QuicStreamId stream_id = 2; - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamDataWithString(stream_id, "foo", 0, NO_FIN); // Now that there is a queued packet, reset the stream. @@ -3393,20 +3362,9 @@ TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) { // Unblock the connection and verify that the RST_STREAM is sent and the data // packet is sent. - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) - .Times(AtLeast(1)); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) - .Times(AtLeast(2)); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); writer_->SetWritable(); connection_.OnCanWrite(); - if (!connection_.session_decides_what_to_write()) { - // OnCanWrite will cause RST_STREAM be sent again. - connection_.SendControlFrame(QuicFrame( - new QuicRstStreamFrame(1, stream_id, QUIC_STREAM_NO_ERROR, 14))); - } size_t padding_frame_count = writer_->padding_frames().size(); EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->rst_stream_frames().size()); @@ -3495,12 +3453,7 @@ TEST_P(QuicConnectionTest, CancelRetransmissionAlarmAfterResetStream) { // Ensure that the data is still in flight, but the retransmission alarm is no // longer set. EXPECT_GT(manager_->GetBytesInFlight(), 0u); - if (QuicConnectionPeer::GetSentPacketManager(&connection_) - ->fix_rto_retransmission()) { - EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - } else { - EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - } + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); } TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) { @@ -3547,11 +3500,6 @@ TEST_P(QuicConnectionTest, DoNotSendPendingRetransmissionForResetStream) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); writer_->SetWritable(); connection_.OnCanWrite(); - if (!connection_.session_decides_what_to_write()) { - // OnCanWrite will cause this RST_STREAM_FRAME be sent again. - connection_.SendControlFrame(QuicFrame(new QuicRstStreamFrame( - 1, stream_id, QUIC_ERROR_PROCESSING_STREAM, 14))); - } size_t padding_frame_count = writer_->padding_frames().size(); EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->rst_stream_frames().size()); @@ -3613,12 +3561,8 @@ TEST_P(QuicConnectionTest, RetransmitAckedPacket) { EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) .WillOnce(SetArgPointee<5>(lost_packets)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)) - .Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)) + .Times(1); ProcessAckPacket(&nack_two); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -3628,15 +3572,8 @@ TEST_P(QuicConnectionTest, RetransmitAckedPacket) { QuicAckFrame ack_all = InitAckFrame(3); ProcessAckPacket(&ack_all); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)) - .Times(0); - } else { - // Unblock the socket and attempt to send the queued packets. We will always - // send the retransmission. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)) - .Times(1); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)) + .Times(0); writer_->SetWritable(); connection_.OnCanWrite(); @@ -3674,8 +3611,7 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { } TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { - if (connection_.PtoEnabled() || - !connection_.session_decides_what_to_write()) { + if (connection_.PtoEnabled()) { return; } connection_.SetMaxTailLossProbes(0); @@ -3688,11 +3624,7 @@ TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { // Block the writer and ensure they're queued. BlockOnNextWrite(); clock_.AdvanceTime(DefaultRetransmissionTime()); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_TRUE(connection_.HasQueuedData()); @@ -3700,12 +3632,7 @@ TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { writer_->SetWritable(); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds( 2 * DefaultRetransmissionTime().ToMicroseconds())); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); - } else { - // 2 RTOs + 1 TLP, which is buggy. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); connection_.GetRetransmissionAlarm()->Fire(); connection_.OnCanWrite(); } @@ -3725,36 +3652,20 @@ TEST_P(QuicConnectionTest, WriteBlockedBufferedThenSent) { TEST_P(QuicConnectionTest, WriteBlockedThenSent) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); BlockOnNextWrite(); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - } else { - EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - } + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // The second packet should also be queued, in order to ensure packets are // never sent out of order. writer_->SetWritable(); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); EXPECT_EQ(2u, connection_.NumQueuedPackets()); // Now both are sent in order when we unblock. - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); connection_.OnCanWrite(); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -3779,12 +3690,7 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) { writer_->SetWritable(); connection_.OnCanWrite(); - if (QuicConnectionPeer::GetSentPacketManager(&connection_) - ->fix_rto_retransmission()) { - EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - } else { - EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - } + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, 2)); } @@ -3867,8 +3773,8 @@ TEST_P(QuicConnectionTest, DoNotAddToWriteBlockedListAfterDisconnect) { writer_->SetWriteBlocked(); } EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PEER_GOING_AWAY, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PEER_GOING_AWAY)); } TEST_P(QuicConnectionTest, AddToWriteBlockedListIfBlockedOnFlushPackets) { @@ -3906,11 +3812,7 @@ TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) { EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) .WillOnce(SetArgPointee<5>(lost_packets)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - if (connection_.session_decides_what_to_write()) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(14); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessAckPacket(&nack); } @@ -4036,8 +3938,7 @@ TEST_P(QuicConnectionTest, TLP) { } TEST_P(QuicConnectionTest, TailLossProbeDelayForStreamDataInTLPR) { - if (!connection_.session_decides_what_to_write() || - connection_.PtoEnabled()) { + if (connection_.PtoEnabled()) { return; } @@ -4072,8 +3973,7 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForStreamDataInTLPR) { } TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { - if (!connection_.session_decides_what_to_write() || - connection_.PtoEnabled()) { + if (connection_.PtoEnabled()) { return; } @@ -4089,7 +3989,7 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { // Sets retransmittable on wire. const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); - connection_.set_retransmittable_on_wire_timeout( + connection_.set_initial_retransmittable_on_wire_timeout( retransmittable_on_wire_timeout); EXPECT_TRUE(connection_.connected()); @@ -4129,7 +4029,7 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { // The ping alarm is set for the ping timeout, not the shorter // retransmittable_on_wire_timeout. EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs), + EXPECT_EQ(connection_.ping_timeout(), connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Receive an ACK for the data packet. @@ -4184,7 +4084,7 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { // The ping alarm is set for the ping timeout, not the shorter // retransmittable_on_wire_timeout. EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs), + EXPECT_EQ(connection_.ping_timeout(), connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Advance a small period of time: 5ms. And receive a retransmitted ACK. @@ -4227,8 +4127,7 @@ TEST_P(QuicConnectionTest, RTO) { // Regression test of b/133771183. TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) { - if (!connection_.session_decides_what_to_write() || - connection_.PtoEnabled()) { + if (connection_.PtoEnabled()) { return; } connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); @@ -4243,31 +4142,14 @@ TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) { // Simulate the retransmission alarm firing. clock_.AdvanceTime(DefaultRetransmissionTime()); // RTO fires, but there is no packet to be RTOed. - if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.GetRetransmissionAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - EXPECT_EQ(1u, writer_->rst_stream_frames().size()); - } + EXPECT_EQ(1u, writer_->rst_stream_frames().size()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(40); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(20); - if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - EXPECT_CALL(visitor_, WillingAndAbleToWrite()) - .WillRepeatedly(Return(false)); - } else { - EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true)); - } - if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1); - } else { - // Since there is a buffered RST_STREAM, no retransmittable frame is bundled - // with ACKs. - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(0); - } + EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(false)); + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1); // Receives packets 1 - 40. for (size_t i = 1; i <= 40; ++i) { ProcessDataPacket(i); @@ -4304,9 +4186,12 @@ TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { // Manually mark both packets for retransmission. connection_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); - - // Packet should have been sent with ENCRYPTION_INITIAL. - EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet()); + if (!connection_.version().CanSendCoalescedPackets()) { + // Packet should have been sent with ENCRYPTION_INITIAL. + // If connection can send coalesced packet, both retransmissions will be + // coalesced in the same UDP datagram. + EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet()); + } // Packet should have been sent with ENCRYPTION_ZERO_RTT. EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); @@ -4346,17 +4231,12 @@ TEST_P(QuicConnectionTest, use_tagging_decrypter(); connection_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique(0x01)); - QuicPacketNumber packet_number; connection_.SendCryptoStreamData(); // Simulate the retransmission alarm firing and the socket blocking. BlockOnNextWrite(); clock_.AdvanceTime(DefaultRetransmissionTime()); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -4506,26 +4386,13 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePacketsThenKeyChange) { TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) { BlockOnNextWrite(); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - } else { - // Make sure that RTO is not started when the packet is queued. - EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - } + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); // Test that RTO is started once we write to the socket. writer_->SetWritable(); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); connection_.OnCanWrite(); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); } @@ -4542,8 +4409,8 @@ TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) { connection_.SendStreamDataWithString(3, "bar", 0, NO_FIN); QuicAlarm* retransmission_alarm = connection_.GetRetransmissionAlarm(); EXPECT_TRUE(retransmission_alarm->IsSet()); - EXPECT_EQ(clock_.Now() + DefaultRetransmissionTime(), - retransmission_alarm->deadline()); + EXPECT_EQ(DefaultRetransmissionTime(), + retransmission_alarm->deadline() - clock_.Now()); // Advance the time right before the RTO, then receive an ack for the first // packet to delay the RTO. @@ -4554,8 +4421,8 @@ TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) { // Now we have an RTT sample of DefaultRetransmissionTime(500ms), // so the RTO has increased to 2 * SRTT. EXPECT_TRUE(retransmission_alarm->IsSet()); - EXPECT_EQ(retransmission_alarm->deadline(), - clock_.Now() + 2 * DefaultRetransmissionTime()); + EXPECT_EQ(retransmission_alarm->deadline() - clock_.Now(), + 2 * DefaultRetransmissionTime()); // Move forward past the original RTO and ensure the RTO is still pending. clock_.AdvanceTime(2 * DefaultRetransmissionTime()); @@ -4780,8 +4647,8 @@ TEST_P(QuicConnectionTest, PingAfterSend) { GetNthClientInitiatedStreamId(0, connection_.transport_version()), "GET /", 0, FIN, nullptr); EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(QuicTime::Delta::FromSeconds(15), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Now recevie an ACK of the previous packet, which will move the // ping alarm forward. @@ -4793,9 +4660,9 @@ TEST_P(QuicConnectionTest, PingAfterSend) { EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); // The ping timer is set slightly less than 15 seconds in the future, because // of the 1s ping timer alarm granularity. - EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15) - - QuicTime::Delta::FromMilliseconds(5), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ( + QuicTime::Delta::FromSeconds(15) - QuicTime::Delta::FromMilliseconds(5), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); writer_->Reset(); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(15)); @@ -4834,8 +4701,8 @@ TEST_P(QuicConnectionTest, ReducedPingTimeout) { GetNthClientInitiatedStreamId(0, connection_.transport_version()), "GET /", 0, FIN, nullptr); EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(10), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(QuicTime::Delta::FromSeconds(10), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Now recevie an ACK of the previous packet, which will move the // ping alarm forward. @@ -4847,9 +4714,9 @@ TEST_P(QuicConnectionTest, ReducedPingTimeout) { EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); // The ping timer is set slightly less than 10 seconds in the future, because // of the 1s ping timer alarm granularity. - EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(10) - - QuicTime::Delta::FromMilliseconds(5), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ( + QuicTime::Delta::FromSeconds(10) - QuicTime::Delta::FromMilliseconds(5), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); writer_->Reset(); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); @@ -4873,10 +4740,7 @@ TEST_P(QuicConnectionTest, ReducedPingTimeout) { // Tests whether sending an MTU discovery packet to peer successfully causes the // maximum packet size to increase. TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } - EXPECT_TRUE(connection_.connected()); + MtuDiscoveryTestInit(); // Send an MTU probe. const size_t new_mtu = kDefaultMaxPacketSize + 100; @@ -4887,17 +4751,6 @@ TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) { EXPECT_EQ(new_mtu, mtu_probe_size); EXPECT_EQ(QuicPacketNumber(1u), creator_->packet_number()); - // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size across - // all encrypters. The initial encrypter used with IETF QUIC has a 16-byte - // overhead, while the NullEncrypter used throughout this test has a 12-byte - // overhead. This test tests behavior that relies on computing the packet size - // correctly, so by unsetting the initial encrypter, we avoid having a - // mismatch between the overheads for the encrypters used. In non-test - // scenarios all encrypters used for a given connection have the same - // overhead, either 12 bytes for ones using Google QUIC crypto, or 16 bytes - // for ones using TLS. - connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); - // Send more than MTU worth of data. No acknowledgement was received so far, // so the MTU should be at its old value. const std::string data(kDefaultMaxPacketSize + 1, '.'); @@ -4912,7 +4765,6 @@ TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) { // Acknowledge all packets so far. QuicAckFrame probe_ack = InitAckFrame(3); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); ProcessAckPacket(&probe_ack); EXPECT_EQ(new_mtu, connection_.max_packet_length()); @@ -4926,7 +4778,7 @@ TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) { // Tests whether MTU discovery does not happen when it is not explicitly enabled // by the connection options. TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) { - EXPECT_TRUE(connection_.connected()); + MtuDiscoveryTestInit(); const QuicPacketCount packets_between_probes_base = 10; set_packets_between_probes_base(packets_between_probes_base); @@ -4942,18 +4794,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) { // Tests whether MTU discovery works when all probes are acknowledged on the // first try. TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { - EXPECT_TRUE(connection_.connected()); - - // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size across - // all encrypters. The initial encrypter used with IETF QUIC has a 16-byte - // overhead, while the NullEncrypter used throughout this test has a 12-byte - // overhead. This test tests behavior that relies on computing the packet size - // correctly, so by unsetting the initial encrypter, we avoid having a - // mismatch between the overheads for the encrypters used. In non-test - // scenarios all encrypters used for a given connection have the same - // overhead, either 12 bytes for ones using Google QUIC crypto, or 16 bytes - // for ones using TLS. - connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); + MtuDiscoveryTestInit(); const QuicPacketCount packets_between_probes_base = 5; set_packets_between_probes_base(packets_between_probes_base); @@ -4974,12 +4815,9 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) .WillOnce(SaveArg<3>(&probe_size)); connection_.GetMtuDiscoveryAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_mtu_discovery_v2)) { - EXPECT_THAT(probe_size, InRange(connection_.max_packet_length(), - kMtuDiscoveryTargetPacketSizeHigh)); - } else { - EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size); - } + + EXPECT_THAT(probe_size, InRange(connection_.max_packet_length(), + kMtuDiscoveryTargetPacketSizeHigh)); const QuicPacketNumber probe_packet_number = FirstSendingPacketNumber() + packets_between_probes_base; @@ -4987,7 +4825,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { // Acknowledge all packets sent so far. QuicAckFrame probe_ack = InitAckFrame(probe_packet_number); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)) .Times(AnyNumber()); ProcessAckPacket(&probe_ack); @@ -4996,17 +4833,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { EXPECT_EQ(1u, connection_.mtu_probe_count()); - if (!GetQuicReloadableFlag(quic_mtu_discovery_v2)) { - // Send more packets, and ensure that none of them sets the alarm. - for (QuicPacketCount i = 0; i < 4 * packets_between_probes_base; i++) { - SendStreamDataToPeer(3, ".", packets_between_probes_base + i, NO_FIN, - nullptr); - ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet()); - } - - return; - } - QuicStreamOffset stream_offset = packets_between_probes_base; for (size_t num_probes = 1; num_probes < kMtuDiscoveryAttempts; ++num_probes) { @@ -5044,9 +4870,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { // Simulate the case where the first attempt to send a probe is write blocked, // and after unblock, the second attempt returns a MSG_TOO_BIG error. TEST_P(QuicConnectionTest, MtuDiscoveryWriteBlocked) { - EXPECT_TRUE(connection_.connected()); - - connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); + MtuDiscoveryTestInit(); const QuicPacketCount packets_between_probes_base = 5; set_packets_between_probes_base(packets_between_probes_base); @@ -5065,9 +4889,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriteBlocked) { SendStreamDataToPeer(3, "!", packets_between_probes_base - 1, NO_FIN, nullptr); ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet()); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); BlockOnNextWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); connection_.GetMtuDiscoveryAlarm()->Fire(); @@ -5086,7 +4908,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriteBlocked) { // Tests whether MTU discovery works correctly when the probes never get // acknowledged. TEST_P(QuicConnectionTest, MtuDiscoveryFailed) { - EXPECT_TRUE(connection_.connected()); + MtuDiscoveryTestInit(); // Lower the number of probes between packets in order to make the test go // much faster. @@ -5106,8 +4928,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryFailed) { const QuicPacketCount number_of_packets = packets_between_probes_base * (1 << (kMtuDiscoveryAttempts + 1)); std::vector mtu_discovery_packets; - // Called by the first ack. - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Called on many acks. EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)) .Times(AnyNumber()); @@ -5168,21 +4988,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryFailed) { // Probe 3 times, the first one succeeds, then fails, then succeeds again. TEST_P(QuicConnectionTest, MtuDiscoverySecondProbeFailed) { - if (!GetQuicReloadableFlag(quic_mtu_discovery_v2)) { - return; - } - EXPECT_TRUE(connection_.connected()); - - // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size across - // all encrypters. The initial encrypter used with IETF QUIC has a 16-byte - // overhead, while the NullEncrypter used throughout this test has a 12-byte - // overhead. This test tests behavior that relies on computing the packet size - // correctly, so by unsetting the initial encrypter, we avoid having a - // mismatch between the overheads for the encrypters used. In non-test - // scenarios all encrypters used for a given connection have the same - // overhead, either 12 bytes for ones using Google QUIC crypto, or 16 bytes - // for ones using TLS. - connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); + MtuDiscoveryTestInit(); const QuicPacketCount packets_between_probes_base = 5; set_packets_between_probes_base(packets_between_probes_base); @@ -5213,7 +5019,6 @@ TEST_P(QuicConnectionTest, MtuDiscoverySecondProbeFailed) { // Acknowledge all packets sent so far. QuicAckFrame first_ack = InitAckFrame(probe_packet_number); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)) .Times(AnyNumber()); ProcessAckPacket(&first_ack); @@ -5271,18 +5076,7 @@ TEST_P(QuicConnectionTest, MtuDiscoverySecondProbeFailed) { // Tests whether MTU discovery works when the writer has a limit on how large a // packet can be. TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { - EXPECT_TRUE(connection_.connected()); - - // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size across - // all encrypters. The initial encrypter used with IETF QUIC has a 16-byte - // overhead, while the NullEncrypter used throughout this test has a 12-byte - // overhead. This test tests behavior that relies on computing the packet size - // correctly, so by unsetting the initial encrypter, we avoid having a - // mismatch between the overheads for the encrypters used. In non-test - // scenarios all encrypters used for a given connection have the same - // overhead, either 12 bytes for ones using Google QUIC crypto, or 16 bytes - // for ones using TLS. - connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); + MtuDiscoveryTestInit(); const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1; writer_->set_max_packet_size(mtu_limit); @@ -5306,12 +5100,8 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) .WillOnce(SaveArg<3>(&probe_size)); connection_.GetMtuDiscoveryAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_mtu_discovery_v2)) { - EXPECT_THAT(probe_size, - InRange(connection_.max_packet_length(), mtu_limit)); - } else { - EXPECT_EQ(mtu_limit, probe_size); - } + + EXPECT_THAT(probe_size, InRange(connection_.max_packet_length(), mtu_limit)); const QuicPacketNumber probe_sequence_number = FirstSendingPacketNumber() + packets_between_probes_base; @@ -5319,7 +5109,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { // Acknowledge all packets sent so far. QuicAckFrame probe_ack = InitAckFrame(probe_sequence_number); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)) .Times(AnyNumber()); ProcessAckPacket(&probe_ack); @@ -5328,17 +5117,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { EXPECT_EQ(1u, connection_.mtu_probe_count()); - if (!GetQuicReloadableFlag(quic_mtu_discovery_v2)) { - // Send more packets, and ensure that none of them sets the alarm. - for (QuicPacketCount i = 0; i < 4 * packets_between_probes_base; i++) { - SendStreamDataToPeer(3, ".", packets_between_probes_base + i, NO_FIN, - nullptr); - ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet()); - } - - return; - } - QuicStreamOffset stream_offset = packets_between_probes_base; for (size_t num_probes = 1; num_probes < kMtuDiscoveryAttempts; ++num_probes) { @@ -5375,7 +5153,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { // Tests whether MTU discovery works when the writer returns an error despite // advertising higher packet length. TEST_P(QuicConnectionTest, MtuDiscoveryWriterFailed) { - EXPECT_TRUE(connection_.connected()); + MtuDiscoveryTestInit(); const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1; const QuicByteCount initial_mtu = connection_.max_packet_length(); @@ -5412,7 +5190,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterFailed) { // Acknowledge all packets sent so far, except for the lost probe. QuicAckFrame probe_ack = ConstructAckFrame(creator_->packet_number(), probe_number); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); ProcessAckPacket(&probe_ack); EXPECT_EQ(initial_mtu, connection_.max_packet_length()); @@ -5428,7 +5205,7 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterFailed) { } TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) { - EXPECT_TRUE(connection_.connected()); + MtuDiscoveryTestInit(); const QuicPacketCount packets_between_probes_base = 10; set_packets_between_probes_base(packets_between_probes_base); @@ -5492,7 +5269,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) { // This time, we should time out. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); clock_.AdvanceTime(five_ms); EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow()); connection_.GetTimeoutAlarm()->Fire(); @@ -5570,7 +5347,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { // This time, we should time out. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); clock_.AdvanceTime(final_timeout - clock_.Now()); EXPECT_EQ(connection_.GetTimeoutAlarm()->deadline(), clock_.Now()); EXPECT_EQ(final_timeout, clock_.Now()); @@ -5601,7 +5378,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); connection_.SetFromConfig(config); EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); @@ -5650,8 +5427,8 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_NETWORK_IDLE_TIMEOUT, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_NETWORK_IDLE_TIMEOUT)); } TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { @@ -5678,7 +5455,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); connection_.SetFromConfig(config); EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); @@ -5705,7 +5482,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { // This time, we should time out and send a connection close due to the TLP. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); clock_.AdvanceTime(connection_.GetTimeoutAlarm()->deadline() - clock_.ApproximateNow() + five_ms); connection_.GetTimeoutAlarm()->Fire(); @@ -5735,7 +5512,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); connection_.SetFromConfig(config); EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); @@ -5760,7 +5537,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { // This time, we should time out and send a connection close due to the TLP. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); clock_.AdvanceTime(connection_.GetTimeoutAlarm()->deadline() - clock_.ApproximateNow() + five_ms); connection_.GetTimeoutAlarm()->Fire(); @@ -5811,7 +5588,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceive) { // This time, we should time out. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); clock_.AdvanceTime(five_ms); EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow()); connection_.GetTimeoutAlarm()->Fire(); @@ -5914,7 +5691,7 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { // This time, we should time out. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); @@ -6567,7 +6344,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { EXPECT_EQ(2u, writer_->frame_count()); @@ -6584,7 +6361,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { ENCRYPTION_ZERO_RTT); // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { EXPECT_EQ(2u, writer_->frame_count()); @@ -6720,7 +6497,7 @@ TEST_P(QuicConnectionTest, } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { EXPECT_EQ(2u, writer_->frame_count()); @@ -6737,7 +6514,7 @@ TEST_P(QuicConnectionTest, ENCRYPTION_ZERO_RTT); // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { EXPECT_EQ(2u, writer_->frame_count()); @@ -6997,19 +6774,13 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { // Check that ack is bundled with outgoing data and the delayed ack // alarm is reset. if (GetParam().no_stop_waiting) { - if (GetQuicReloadableFlag(quic_simplify_stop_waiting)) { - // Do not ACK acks. - EXPECT_EQ(1u, writer_->frame_count()); - } else { - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } + // Do not ACK acks. + EXPECT_EQ(1u, writer_->frame_count()); } else { EXPECT_EQ(3u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } - if (GetParam().no_stop_waiting && - GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + if (GetParam().no_stop_waiting) { EXPECT_TRUE(writer_->ack_frames().empty()); } else { EXPECT_FALSE(writer_->ack_frames().empty()); @@ -7028,8 +6799,8 @@ TEST_P(QuicConnectionTest, NoAckSentForClose) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); ProcessClosePacket(2); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PEER_GOING_AWAY, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PEER_GOING_AWAY)); } TEST_P(QuicConnectionTest, SendWhenDisconnected) { @@ -7047,8 +6818,8 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) { connection_.SendPacket(ENCRYPTION_INITIAL, 1, std::move(packet), HAS_RETRANSMITTABLE_DATA, false, false); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PEER_GOING_AWAY, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PEER_GOING_AWAY)); } TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { @@ -7073,8 +6844,8 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { "Not sending connectivity probing packet as connection is " "disconnected."); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PEER_GOING_AWAY, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PEER_GOING_AWAY)); } TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { @@ -7155,7 +6926,8 @@ TEST_P(QuicConnectionTest, PublicReset) { .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PUBLIC_RESET, saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PUBLIC_RESET)); } TEST_P(QuicConnectionTest, IetfStatelessReset) { @@ -7177,7 +6949,8 @@ TEST_P(QuicConnectionTest, IetfStatelessReset) { .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PUBLIC_RESET, saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PUBLIC_RESET)); } TEST_P(QuicConnectionTest, GoAway) { @@ -7201,7 +6974,7 @@ TEST_P(QuicConnectionTest, WindowUpdate) { QuicWindowUpdateFrame window_update; window_update.stream_id = 3; - window_update.byte_offset = 1234; + window_update.max_data = 1234; EXPECT_CALL(visitor_, OnWindowUpdateFrame(_)); ProcessFramePacket(QuicFrame(&window_update)); } @@ -7259,8 +7032,8 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); EXPECT_FALSE(connection_.connected()); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_INVALID_VERSION, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_INVALID_VERSION)); } TEST_P(QuicConnectionTest, BadVersionNegotiation) { @@ -7278,8 +7051,8 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) { ConstructReceivedPacket(*encrypted, QuicTime::Zero())); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET)); } TEST_P(QuicConnectionTest, CheckSendStats) { @@ -7317,9 +7090,6 @@ TEST_P(QuicConnectionTest, CheckSendStats) { EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) .WillOnce(SetArgPointee<5>(lost_packets)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - if (!connection_.session_decides_what_to_write()) { - EXPECT_CALL(visitor_, OnCanWrite()); - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessAckPacket(&nack_three); @@ -7387,8 +7157,8 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_PEER_GOING_AWAY, - saved_connection_close_frame_.extracted_error_code); + EXPECT_THAT(saved_connection_close_frame_.extracted_error_code, + IsError(QUIC_PEER_GOING_AWAY)); } TEST_P(QuicConnectionTest, SelectMutualVersion) { @@ -7426,7 +7196,7 @@ TEST_P(QuicConnectionTest, ConnectionCloseWhenWritable) { EXPECT_EQ(1u, writer_->packets_write_attempts()); TriggerConnectionClose(); - EXPECT_EQ(2u, writer_->packets_write_attempts()); + EXPECT_LE(2u, writer_->packets_write_attempts()); } TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) { @@ -7450,10 +7220,10 @@ TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) { MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1); + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1); + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); connection_.SendConnectivityProbingPacket(writer_.get(), connection_.peer_address()); } @@ -7494,7 +7264,7 @@ TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) { // Send a WINDOW_UPDATE frame. QuicWindowUpdateFrame window_update; window_update.stream_id = 3; - window_update.byte_offset = 1234; + window_update.max_data = 1234; EXPECT_CALL(visitor_, OnWindowUpdateFrame(_)); ProcessFramePacket(QuicFrame(&window_update)); @@ -7582,7 +7352,7 @@ TEST_P(QuicConnectionTest, SendPingImmediately) { CongestionBlockWrites(); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1); + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); EXPECT_CALL(debug_visitor, OnPingSent()).Times(1); connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); EXPECT_FALSE(connection_.HasQueuedData()); @@ -7594,7 +7364,7 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) { connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1); + 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); @@ -7610,7 +7380,7 @@ TEST_P(QuicConnectionTest, FailedToSendBlockedFrames) { QuicBlockedFrame blocked(1, 3); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(0); + 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); @@ -7631,8 +7401,8 @@ TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) { "Cannot send stream data with level: ENCRYPTION_INITIAL"); EXPECT_FALSE(connection_.connected()); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, - saved_connection_close_frame_.quic_error_code); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA)); } TEST_P(QuicConnectionTest, SetRetransmissionAlarmForCryptoPacket) { @@ -7668,8 +7438,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) { EXPECT_FALSE(connection_.IsPathDegrading()); QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); // Fire the path degrading alarm, path degrading signal should be sent to // the visitor. @@ -7702,8 +7472,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); // Send a second packet. The path degrading alarm's deadline should remain // the same. @@ -7731,8 +7501,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { // Check the deadline of the path degrading alarm. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); if (i == 0) { // Now receive an ACK of the second packet. Since there are no more @@ -7758,7 +7528,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); - connection_.set_retransmittable_on_wire_timeout( + connection_.set_initial_retransmittable_on_wire_timeout( retransmittable_on_wire_timeout); EXPECT_TRUE(connection_.connected()); @@ -7782,15 +7552,15 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); ASSERT_TRUE(connection_.sent_packet_manager().HasInFlightPackets()); // The ping alarm is set for the ping timeout, not the shorter // retransmittable_on_wire_timeout. EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); QuicTime::Delta ping_delay = QuicTime::Delta::FromSeconds(kPingTimeoutSecs); - EXPECT_EQ((clock_.ApproximateNow() + ping_delay), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(ping_delay, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Now receive an ACK of the packet. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); @@ -7804,8 +7574,8 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { // retransmittable_on_wire_timeout. EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Simulate firing the ping alarm and sending a PING. clock_.AdvanceTime(retransmittable_on_wire_timeout); @@ -7819,8 +7589,8 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); } // This test verifies that the connection marks path as degrading and does not @@ -7843,8 +7613,8 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { // Check the deadline of the path degrading alarm. QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); // Send a second packet. The path degrading alarm's deadline should remain // the same. @@ -7867,8 +7637,8 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { // Check the deadline of the path degrading alarm. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); // Advance time to the path degrading alarm's deadline and simulate // firing the path degrading alarm. This path will be considered as @@ -7909,8 +7679,8 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) { // Check the deadline of the path degrading alarm. QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); // Send a second packet. The path degrading alarm's deadline should remain // the same. @@ -7933,8 +7703,8 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) { // Check the deadline of the path degrading alarm. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - EXPECT_EQ(clock_.ApproximateNow() + delay, - connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - + clock_.ApproximateNow()); // Advance time to the path degrading alarm's deadline and simulate // firing the alarm. @@ -7981,7 +7751,6 @@ TEST_P(QuicConnectionTest, NoPathDegradingOnServer) { // Ack data. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); QuicAckFrame frame = InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}}); @@ -8016,8 +7785,6 @@ TEST_P(QuicConnectionTest, MultipleCallsToCloseConnection) { } TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -8133,11 +7900,7 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) { EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true)); BlockOnNextWrite(); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamData3(); // Now unblock the writer, become congestion control blocked, @@ -8145,11 +7908,7 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) { writer_->SetWritable(); CongestionBlockWrites(); EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(false)); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(1); connection_.OnCanWrite(); } @@ -8203,7 +7962,7 @@ TEST_P(QuicConnectionTest, SendDataWhenApplicationLimited) { ProcessAckPacket(&ack); } -TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) { +TEST_P(QuicConnectionTest, DoNotForceSendingAckOnPacketTooLarge) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send an ack by simulating delayed ack alarm firing. ProcessPacket(1); @@ -8214,13 +7973,74 @@ TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) { EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); SimulateNextPacketTooLarge(); connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN); - EXPECT_EQ(1u, writer_->frame_count()); - EXPECT_FALSE(writer_->connection_close_frames().empty()); + EXPECT_EQ(1u, writer_->connection_close_frames().size()); // Ack frame is not bundled in connection close packet. EXPECT_TRUE(writer_->ack_frames().empty()); + if (writer_->padding_frames().empty()) { + EXPECT_EQ(1u, writer_->frame_count()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + } + TestConnectionCloseQuicErrorCode(QUIC_PACKET_WRITE_ERROR); } +TEST_P(QuicConnectionTest, CloseConnectionAllLevels) { + SetQuicReloadableFlag(quic_close_all_encryptions_levels2, true); + + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); + const QuicErrorCode kQuicErrorCode = QUIC_INTERNAL_ERROR; + connection_.CloseConnection( + kQuicErrorCode, "Some random error message", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + + EXPECT_EQ(2u, QuicConnectionPeer::GetNumEncryptionLevels(&connection_)); + + TestConnectionCloseQuicErrorCode(kQuicErrorCode); + EXPECT_EQ(1u, writer_->connection_close_frames().size()); + + if (!connection_.version().CanSendCoalescedPackets()) { + // Each connection close packet should be sent in distinct UDP packets. + EXPECT_EQ(QuicConnectionPeer::GetNumEncryptionLevels(&connection_), + writer_->connection_close_packets()); + EXPECT_EQ(QuicConnectionPeer::GetNumEncryptionLevels(&connection_), + writer_->packets_write_attempts()); + return; + } + + // A single UDP packet should be sent with multiple connection close packets + // coalesced together. + EXPECT_EQ(1u, writer_->packets_write_attempts()); + + // Only the first packet has been processed yet. + EXPECT_EQ(1u, writer_->connection_close_packets()); + + // ProcessPacket resets the visitor and frees the coalesced packet. + ASSERT_TRUE(writer_->coalesced_packet() != nullptr); + auto packet = writer_->coalesced_packet()->Clone(); + writer_->framer()->ProcessPacket(*packet); + EXPECT_EQ(1u, writer_->connection_close_packets()); + ASSERT_TRUE(writer_->coalesced_packet() == nullptr); +} + +TEST_P(QuicConnectionTest, CloseConnectionOneLevel) { + SetQuicReloadableFlag(quic_close_all_encryptions_levels2, false); + + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); + const QuicErrorCode kQuicErrorCode = QUIC_INTERNAL_ERROR; + connection_.CloseConnection( + kQuicErrorCode, "Some random error message", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + + EXPECT_EQ(2u, QuicConnectionPeer::GetNumEncryptionLevels(&connection_)); + + TestConnectionCloseQuicErrorCode(kQuicErrorCode); + EXPECT_EQ(1u, writer_->connection_close_frames().size()); + EXPECT_EQ(1u, writer_->connection_close_packets()); + EXPECT_EQ(1u, writer_->packets_write_attempts()); + ASSERT_TRUE(writer_->coalesced_packet() == nullptr); +} + // Regression test for b/63620844. TEST_P(QuicConnectionTest, FailedToWriteHandshakePacket) { SimulateNextPacketTooLarge(); @@ -8279,13 +8099,19 @@ TEST_P(QuicConnectionTest, SendProbingRetransmissions) { } // Expect them retransmitted in cyclic order (foo, bar, test, foo, bar...). QuicPacketCount sent_count = 0; - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)) + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)) .WillRepeatedly(Invoke([this, &sent_count](const SerializedPacket&, - QuicPacketNumber, TransmissionType, QuicTime) { ASSERT_EQ(1u, writer_->stream_frames().size()); - // Identify the frames by stream offset (0, 3, 6, 0, 3...). - EXPECT_EQ(3 * (sent_count % 3), writer_->stream_frames()[0]->offset); + 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()) @@ -8311,7 +8137,7 @@ TEST_P(QuicConnectionTest, MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(0); + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0); EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket()) .WillRepeatedly(Return(true)); EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] { @@ -8325,7 +8151,7 @@ TEST_P(QuicConnectionTest, TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); - connection_.set_retransmittable_on_wire_timeout( + connection_.set_initial_retransmittable_on_wire_timeout( retransmittable_on_wire_timeout); EXPECT_TRUE(connection_.connected()); @@ -8346,8 +8172,8 @@ TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { // retransmittable_on_wire_timeout. EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); QuicTime::Delta ping_delay = QuicTime::Delta::FromSeconds(kPingTimeoutSecs); - EXPECT_EQ((clock_.ApproximateNow() + ping_delay), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(ping_delay, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Advance 5ms, send a second retransmittable packet to the peer. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); @@ -8370,9 +8196,8 @@ TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); // The ping alarm has a 1 second granularity, and the clock has been advanced // 10ms since it was originally set. - EXPECT_EQ((clock_.ApproximateNow() + ping_delay - - QuicTime::Delta::FromMilliseconds(10)), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(ping_delay - QuicTime::Delta::FromMilliseconds(10), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Now receive an ACK of the second packet. This should set the // retransmittable-on-wire alarm now that no retransmittable packets are on @@ -8382,8 +8207,8 @@ TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); ProcessAckPacket(&frame); EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Now receive a duplicate ACK of the second packet. This should not update // the ping alarm. @@ -8418,7 +8243,7 @@ TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); - connection_.set_retransmittable_on_wire_timeout( + connection_.set_initial_retransmittable_on_wire_timeout( retransmittable_on_wire_timeout); EXPECT_TRUE(connection_.connected()); @@ -8439,8 +8264,8 @@ TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { // retransmittable_on_wire_timeout. EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); QuicTime::Delta ping_delay = QuicTime::Delta::FromSeconds(kPingTimeoutSecs); - EXPECT_EQ((clock_.ApproximateNow() + ping_delay), - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(ping_delay, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Now receive an ACK of the first packet. This should set the // retransmittable-on-wire alarm now that no retransmittable packets are on @@ -8452,8 +8277,8 @@ TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}}); ProcessAckPacket(&frame); EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Before the alarm fires, send another retransmittable packet. This should // cancel the retransmittable-on-wire alarm since now there's a @@ -8470,8 +8295,8 @@ TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); ProcessAckPacket(&frame); EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); - EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, - connection_.GetPingAlarm()->deadline()); + EXPECT_EQ(retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); // Simulate the alarm firing and check that a PING is sent. writer_->Reset(); @@ -8481,18 +8306,233 @@ TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { connection_.GetPingAlarm()->Fire(); size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - if (GetQuicReloadableFlag(quic_simplify_stop_waiting)) { - // Do not ACK acks. - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - } + // Do not ACK acks. + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); } else { EXPECT_EQ(padding_frame_count + 3u, writer_->frame_count()); } ASSERT_EQ(1u, writer_->ping_frames().size()); } +// When there is no stream data received but are open streams, send the +// first few consecutive pings with aggressive retransmittable-on-wire +// timeout. Exponentially back off the retransmittable-on-wire ping timeout +// afterwards until it exceeds the default ping timeout. +TEST_P(QuicConnectionTest, BackOffRetransmittableOnWireTimeout) { + int max_aggressive_retransmittable_on_wire_ping_count = 5; + SetQuicFlag(FLAGS_quic_max_aggressive_retransmittable_on_wire_ping_count, + max_aggressive_retransmittable_on_wire_ping_count); + const QuicTime::Delta initial_retransmittable_on_wire_timeout = + QuicTime::Delta::FromMilliseconds(200); + connection_.set_initial_retransmittable_on_wire_timeout( + initial_retransmittable_on_wire_timeout); + + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) + .WillRepeatedly(Return(true)); + + const char data[] = "data"; + // Advance 5ms, send a retransmittable data packet to the peer. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); + connection_.SendStreamDataWithString(1, data, 0, NO_FIN); + EXPECT_TRUE(connection_.sent_packet_manager().HasInFlightPackets()); + // The ping alarm is set for the ping timeout, not the shorter + // retransmittable_on_wire_timeout. + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(connection_.ping_timeout(), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)) + .Times(AnyNumber()); + + // Verify that the first few consecutive retransmittable on wire pings are + // sent with aggressive timeout. + for (int i = 0; i <= max_aggressive_retransmittable_on_wire_ping_count; i++) { + // Receive an ACK of the previous packet. This should set the ping alarm + // with the initial retransmittable-on-wire timeout. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + QuicPacketNumber ack_num = creator_->packet_number(); + QuicAckFrame frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(initial_retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + // Simulate the alarm firing and check that a PING is sent. + writer_->Reset(); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + SendPing(); + })); + clock_.AdvanceTime(initial_retransmittable_on_wire_timeout); + connection_.GetPingAlarm()->Fire(); + } + + QuicTime::Delta retransmittable_on_wire_timeout = + initial_retransmittable_on_wire_timeout; + + // Verify subsequent pings are sent with timeout that is exponentially backed + // off. + while (retransmittable_on_wire_timeout * 2 < connection_.ping_timeout()) { + // Receive an ACK for the previous PING. This should set the + // ping alarm with backed off retransmittable-on-wire timeout. + retransmittable_on_wire_timeout = retransmittable_on_wire_timeout * 2; + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + QuicPacketNumber ack_num = creator_->packet_number(); + QuicAckFrame frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + // Simulate the alarm firing and check that a PING is sent. + writer_->Reset(); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + SendPing(); + })); + clock_.AdvanceTime(retransmittable_on_wire_timeout); + connection_.GetPingAlarm()->Fire(); + } + + // The ping alarm is set with default ping timeout. + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(connection_.ping_timeout(), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + // Receive an ACK for the previous PING. The ping alarm is set with an + // earlier deadline. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + QuicPacketNumber ack_num = creator_->packet_number(); + QuicAckFrame frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(connection_.ping_timeout() - QuicTime::Delta::FromMilliseconds(5), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); +} + +// This test verify that the count of consecutive aggressive pings is reset +// when new data is received. And it also verifies the connection resets +// the exponential back-off of the retransmittable-on-wire ping timeout +// after receiving new stream data. +TEST_P(QuicConnectionTest, ResetBackOffRetransmitableOnWireTimeout) { + int max_aggressive_retransmittable_on_wire_ping_count = 3; + SetQuicFlag(FLAGS_quic_max_aggressive_retransmittable_on_wire_ping_count, 3); + const QuicTime::Delta initial_retransmittable_on_wire_timeout = + QuicTime::Delta::FromMilliseconds(200); + connection_.set_initial_retransmittable_on_wire_timeout( + initial_retransmittable_on_wire_timeout); + + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)) + .Times(AnyNumber()); + + const char data[] = "data"; + // Advance 5ms, send a retransmittable data packet to the peer. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); + connection_.SendStreamDataWithString(1, data, 0, NO_FIN); + EXPECT_TRUE(connection_.sent_packet_manager().HasInFlightPackets()); + // The ping alarm is set for the ping timeout, not the shorter + // retransmittable_on_wire_timeout. + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(connection_.ping_timeout(), + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + // Receive an ACK of the first packet. This should set the ping alarm with + // initial retransmittable-on-wire timeout since there is no retransmittable + // packet on the wire. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + QuicAckFrame frame = + InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(initial_retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + // Simulate the alarm firing and check that a PING is sent. + writer_->Reset(); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); + clock_.AdvanceTime(initial_retransmittable_on_wire_timeout); + connection_.GetPingAlarm()->Fire(); + + // Receive an ACK for the previous PING. Ping alarm will be set with + // aggressive timeout. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + QuicPacketNumber ack_num = creator_->packet_number(); + frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(initial_retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + // Process a data packet. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(peer_creator_.packet_number() + 1); + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, + peer_creator_.packet_number() + 1); + EXPECT_EQ(initial_retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + // Verify the count of consecutive aggressive pings is reset. + for (int i = 0; i < max_aggressive_retransmittable_on_wire_ping_count; i++) { + // Receive an ACK of the previous packet. This should set the ping alarm + // with the initial retransmittable-on-wire timeout. + QuicPacketNumber ack_num = creator_->packet_number(); + QuicAckFrame frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(initial_retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + // Simulate the alarm firing and check that a PING is sent. + writer_->Reset(); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + SendPing(); + })); + clock_.AdvanceTime(initial_retransmittable_on_wire_timeout); + connection_.GetPingAlarm()->Fire(); + // Advance 5ms to receive next packet. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + } + + // Receive another ACK for the previous PING. This should set the + // ping alarm with backed off retransmittable-on-wire timeout. + ack_num = creator_->packet_number(); + frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(initial_retransmittable_on_wire_timeout * 2, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); + + writer_->Reset(); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); + clock_.AdvanceTime(2 * initial_retransmittable_on_wire_timeout); + connection_.GetPingAlarm()->Fire(); + + // Process another data packet and a new ACK packet. The ping alarm is set + // with aggressive ping timeout again. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + ProcessDataPacket(peer_creator_.packet_number() + 1); + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, + peer_creator_.packet_number() + 1); + ack_num = creator_->packet_number(); + frame = InitAckFrame( + {{QuicPacketNumber(ack_num), QuicPacketNumber(ack_num + 1)}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPingAlarm()->IsSet()); + EXPECT_EQ(initial_retransmittable_on_wire_timeout, + connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); +} + TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) { EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(Exactly(0)); EXPECT_TRUE(connection_.connected()); @@ -8552,32 +8592,15 @@ TEST_P(QuicConnectionTest, ValidStatelessResetToken) { TEST_P(QuicConnectionTest, WriteBlockedWithInvalidAck) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); - } else { - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)) - .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); - } + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); BlockOnNextWrite(); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamDataWithString(5, "foo", 0, FIN); // This causes connection to be closed because packet 1 has not been sent yet. QuicAckFrame frame = InitAckFrame(1); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)); - } + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)); ProcessAckPacket(1, &frame); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_EQ(0, connection_close_frame_count_); - } else { - EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_EQ(QUIC_INVALID_ACK_DATA, - saved_connection_close_frame_.quic_error_code); - } + EXPECT_EQ(0, connection_close_frame_count_); } TEST_P(QuicConnectionTest, SendMessage) { @@ -8594,33 +8617,36 @@ TEST_P(QuicConnectionTest, SendMessage) { // get sent, one contains stream frame, and the other only contains the // message frame. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); - EXPECT_EQ( - MESSAGE_STATUS_SUCCESS, - connection_.SendMessage( - 1, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), - QuicStringPiece( - message_data.data(), - connection_.GetCurrentLargestMessagePayload()), - &storage))); + EXPECT_EQ(MESSAGE_STATUS_SUCCESS, + connection_.SendMessage( + 1, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + QuicStringPiece( + message_data.data(), + connection_.GetCurrentLargestMessagePayload()), + &storage), + false)); } // Fail to send a message if connection is congestion control blocked. EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); - EXPECT_EQ( - MESSAGE_STATUS_BLOCKED, - connection_.SendMessage( - 2, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), - "message", &storage))); + EXPECT_EQ(MESSAGE_STATUS_BLOCKED, + connection_.SendMessage( + 2, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + "message", &storage), + false)); // Always fail to send a message which cannot fit into one packet. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - EXPECT_EQ( - MESSAGE_STATUS_TOO_LARGE, - connection_.SendMessage( - 3, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), - QuicStringPiece( - message_data.data(), - connection_.GetCurrentLargestMessagePayload() + 1), - &storage))); + EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE, + connection_.SendMessage( + 3, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + QuicStringPiece( + message_data.data(), + connection_.GetCurrentLargestMessagePayload() + 1), + &storage), + false)); } // Test to check that the path challenge/path response logic works @@ -8743,7 +8769,6 @@ TEST_P(QuicConnectionTest, StopProcessingGQuicPacketInIetfQuicConnection) { 0u, QuicStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); } - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Let connection process a Google QUIC packet. @@ -8832,6 +8857,8 @@ TEST_P(QuicConnectionTest, PeerAcksPacketsInWrongPacketNumberSpace) { use_tagging_decrypter(); connection_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique(0x01)); + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique(0x01)); connection_.SendCryptoStreamData(); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -8853,7 +8880,7 @@ TEST_P(QuicConnectionTest, PeerAcksPacketsInWrongPacketNumberSpace) { InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(4)}}); EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); ProcessFramePacketAtLevel(300, QuicFrame(&invalid_ack), ENCRYPTION_INITIAL); TestConnectionCloseQuicErrorCode(QUIC_INVALID_ACK_DATA); } @@ -9014,7 +9041,6 @@ TEST_P(QuicConnectionTest, UpdateClientConnectionIdFromFirstPacket) { if (!framer_.version().SupportsClientConnectionIds()) { return; } - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketHeader header = ConstructPacketHeader(1, ENCRYPTION_INITIAL); header.source_connection_id = TestConnectionId(0x33); @@ -9185,10 +9211,6 @@ TEST_P(QuicConnectionTest, CoalescedPacketThatSavesFrames) { // Regresstion test for b/138962304. TEST_P(QuicConnectionTest, RtoAndWriteBlocked) { - if (!QuicConnectionPeer::GetSentPacketManager(&connection_) - ->fix_rto_retransmission()) { - return; - } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); QuicStreamId stream_id = 2; @@ -9215,10 +9237,6 @@ TEST_P(QuicConnectionTest, RtoAndWriteBlocked) { // Regresstion test for b/138962304. TEST_P(QuicConnectionTest, TlpAndWriteBlocked) { - if (!QuicConnectionPeer::GetSentPacketManager(&connection_) - ->fix_rto_retransmission()) { - return; - } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); connection_.SetMaxTailLossProbes(1); @@ -9236,11 +9254,7 @@ TEST_P(QuicConnectionTest, TlpAndWriteBlocked) { EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1)); SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3); - if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - } + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); // Retransmission timer fires in TLP mode. connection_.GetRetransmissionAlarm()->Fire(); // Verify one packets is forced flushed when writer is blocked. @@ -9249,9 +9263,7 @@ TEST_P(QuicConnectionTest, TlpAndWriteBlocked) { // Regresstion test for b/139375344. TEST_P(QuicConnectionTest, RtoForcesSendingPing) { - if (!QuicConnectionPeer::GetSentPacketManager(&connection_) - ->fix_rto_retransmission() || - connection_.PtoEnabled()) { + if (connection_.PtoEnabled()) { return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -9289,12 +9301,7 @@ TEST_P(QuicConnectionTest, RtoForcesSendingPing) { } TEST_P(QuicConnectionTest, ProbeTimeout) { - if (!connection_.session_decides_what_to_write() || - !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - return; - } SetQuicReloadableFlag(quic_enable_pto, true); - SetQuicReloadableFlag(quic_fix_rto_retransmission3, true); QuicConfig config; QuicTagVector connection_options; connection_options.push_back(k2PTO); @@ -9322,10 +9329,6 @@ TEST_P(QuicConnectionTest, ProbeTimeout) { } TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { - if (!connection_.session_decides_what_to_write() || - !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - return; - } SetQuicReloadableFlag(quic_enable_pto, true); QuicConfig config; QuicTagVector connection_options; @@ -9342,7 +9345,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { 0, FIN, nullptr); // 5PTO + 1 connection close. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(6)); // Fire the retransmission alarm 5 times. for (int i = 0; i < 5; ++i) { @@ -9364,10 +9367,6 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { } TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { - if (!connection_.session_decides_what_to_write() || - !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - return; - } SetQuicReloadableFlag(quic_enable_pto, true); QuicConfig config; QuicTagVector connection_options; @@ -9397,7 +9396,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { // Closes connection on 7th PTO. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); @@ -9405,10 +9404,6 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { } TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { - if (!connection_.session_decides_what_to_write() || - !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - return; - } SetQuicReloadableFlag(quic_enable_pto, true); QuicConfig config; QuicTagVector connection_options; @@ -9438,7 +9433,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { // Closes connection on 8th PTO. EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); @@ -9482,7 +9477,6 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) { if (!connection_.version().SupportsAntiAmplificationLimit()) { return; } - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); set_perspective(Perspective::IS_SERVER); @@ -9558,9 +9552,7 @@ TEST_P(QuicConnectionTest, ConnectionCloseFrameType) { // Regression test for b/137401387 and b/138962304. TEST_P(QuicConnectionTest, RtoPacketAsTwo) { - if (!QuicConnectionPeer::GetSentPacketManager(&connection_) - ->fix_rto_retransmission() || - connection_.PtoEnabled()) { + if (connection_.PtoEnabled()) { return; } connection_.SetMaxTailLossProbes(1); @@ -9603,10 +9595,6 @@ TEST_P(QuicConnectionTest, RtoPacketAsTwo) { } TEST_P(QuicConnectionTest, PtoSkipsPacketNumber) { - if (!connection_.session_decides_what_to_write() || - !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - return; - } SetQuicReloadableFlag(quic_enable_pto, true); SetQuicReloadableFlag(quic_skip_packet_number_for_pto, true); QuicConfig config; @@ -9633,6 +9621,44 @@ TEST_P(QuicConnectionTest, PtoSkipsPacketNumber) { EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); } +TEST_P(QuicConnectionTest, SendCoalescedPackets) { + if (!connection_.version().CanSendCoalescedPackets()) { + return; + } + { + QuicConnection::ScopedPacketFlusher flusher(&connection_); + use_tagging_decrypter(); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique(0x01)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + connection_.SendCryptoDataWithString("foo", 0); + // Verify this packet is on hold. + EXPECT_EQ(0u, writer_->packets_write_attempts()); + + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + connection_.SendCryptoDataWithString("bar", 3); + EXPECT_EQ(0u, writer_->packets_write_attempts()); + + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique(0x03)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + SendStreamDataToPeer(2, "baz", 3, NO_FIN, nullptr); + } + // Verify all 3 packets are coalesced in the same UDP datagram. + EXPECT_EQ(1u, writer_->packets_write_attempts()); + EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet()); + // Verify the packet is padded to full. + EXPECT_EQ(connection_.max_packet_length(), writer_->last_packet_size()); + + // Verify packet process. + EXPECT_EQ(1u, writer_->crypto_frames().size()); + EXPECT_EQ(0u, writer_->stream_frames().size()); + // Verify there is coalesced packet. + EXPECT_NE(nullptr, writer_->coalesced_packet()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h index 3dc462ccb87..3264c1532ff 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h @@ -47,6 +47,9 @@ const QuicByteCount kMaxIncomingPacketSize = kMaxV4PacketSize; const QuicByteCount kMaxOutgoingPacketSize = kMaxV6PacketSize; // ETH_MAX_MTU - MAX(sizeof(iphdr), sizeof(ip6_hdr)) - sizeof(udphdr). const QuicByteCount kMaxGsoPacketSize = 65535 - 40 - 8; +// The maximal IETF DATAGRAM frame size we'll accept. Choosing 2^16 ensures +// that it is greater than the biggest frame we could ever fit in a QUIC packet. +const QuicByteCount kMaxAcceptedDatagramFrameSize = 65536; // Default maximum packet size used in the Linux TCP implementation. // Used in QUIC for congestion window computations in bytes. const QuicByteCount kDefaultTCPMSS = 1460; @@ -245,6 +248,15 @@ const int kInitialRttMs = 100; // packet is lost due to early retransmission by time based loss detection. static const int kDefaultLossDelayShift = 2; +// Maximum number of retransmittable packets received before sending an ack. +const QuicPacketCount kDefaultRetransmittablePacketsBeforeAck = 2; +// Wait for up to 10 retransmittable packets before sending an ack. +const QuicPacketCount kMaxRetransmittablePacketsBeforeAck = 10; +// Minimum number of packets received before ack decimation is enabled. +// This intends to avoid the beginning of slow start, when CWNDs may be +// rapidly increasing. +const QuicPacketCount kMinReceivedBeforeAckDecimation = 100; + // Packet number of first sending packet of a connection. Please note, this // cannot be used as first received packet because peer can choose its starting // packet number. 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 11efae85892..3eed5e8d7ca 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 @@ -26,14 +26,7 @@ QuicControlFrameManager::QuicControlFrameManager(QuicSession* session) : last_control_frame_id_(kInvalidControlFrameId), least_unacked_(1), least_unsent_(1), - session_(session), - add_upper_limit_(GetQuicReloadableFlag( - quic_add_upper_limit_of_buffered_control_frames3)) { - if (add_upper_limit_) { - QUIC_RELOADABLE_FLAG_COUNT( - quic_add_upper_limit_of_buffered_control_frames3); - } -} + session_(session) {} QuicControlFrameManager::~QuicControlFrameManager() { while (!control_frames_.empty()) { @@ -45,7 +38,7 @@ QuicControlFrameManager::~QuicControlFrameManager() { void QuicControlFrameManager::WriteOrBufferQuicFrame(QuicFrame frame) { const bool had_buffered_frames = HasBufferedFrames(); control_frames_.emplace_back(frame); - if (add_upper_limit_ && control_frames_.size() > kMaxNumControlFrames) { + if (control_frames_.size() > kMaxNumControlFrames) { session_->connection()->CloseConnection( QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES, QuicStrCat("More than ", kMaxNumControlFrames, @@ -125,7 +118,7 @@ void QuicControlFrameManager::WritePing() { } control_frames_.emplace_back( QuicFrame(QuicPingFrame(++last_control_frame_id_))); - if (add_upper_limit_ && control_frames_.size() > kMaxNumControlFrames) { + if (control_frames_.size() > kMaxNumControlFrames) { session_->connection()->CloseConnection( QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES, QuicStrCat("More than ", kMaxNumControlFrames, @@ -281,9 +274,7 @@ bool QuicControlFrameManager::RetransmitControlFrame(const QuicFrame& frame) { void QuicControlFrameManager::WriteBufferedFrames() { while (HasBufferedFrames()) { - if (session_->session_decides_what_to_write()) { - session_->SetTransmissionType(NOT_RETRANSMISSION); - } + session_->SetTransmissionType(NOT_RETRANSMISSION); QuicFrame frame_to_send = control_frames_.at(least_unsent_ - least_unacked_); QuicFrame copy = CopyRetransmittableControlFrame(frame_to_send); 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 735b73c07b2..a4c26780d40 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 @@ -146,9 +146,6 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager { // Last sent window update frame for each stream. QuicSmallMap window_update_frames_; - - // Latched value of quic_add_upper_limit_of_buffered_control_frames3. - const bool add_upper_limit_; }; } // namespace quic 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 d1723a1828c..e76e09ffb9a 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 @@ -291,7 +291,6 @@ TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) { } TEST_F(QuicControlFrameManagerTest, TooManyBufferedControlFrames) { - SetQuicReloadableFlag(quic_add_upper_limit_of_buffered_control_frames3, true); Initialize(); EXPECT_CALL(*connection_, SendControlFrame(_)) .Times(5) 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 1f63042d6ee..eaeabfec08f 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 @@ -56,6 +56,7 @@ QuicCryptoClientHandshaker::QuicCryptoClientHandshaker( : QuicCryptoHandshaker(stream, session), stream_(stream), session_(session), + delegate_(session), next_state_(STATE_IDLE), num_client_hellos_(0), crypto_config_(crypto_config), @@ -116,6 +117,13 @@ int QuicCryptoClientHandshaker::num_sent_client_hellos() const { return num_client_hellos_; } +bool QuicCryptoClientHandshaker::IsResumption() const { + QUIC_BUG_IF(!handshake_confirmed_); + // While 0-RTT handshakes could be considered to be like resumption, QUIC + // Crypto doesn't have the same notion of a resumption like TLS does. + return false; +} + int QuicCryptoClientHandshaker::num_scup_messages_received() const { return num_scup_messages_received_; } @@ -310,6 +318,17 @@ void QuicCryptoClientHandshaker::DoSendCHLO( crypto_config_->pad_full_hello()); SendHandshakeMessage(out); // Be prepared to decrypt with the new server write key. + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( + ENCRYPTION_ZERO_RTT, + std::move(crypto_negotiated_params_->initial_crypters.decrypter), + /*set_alternative_decrypter=*/true, + /*latch_once_used=*/true, + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); + encryption_established_ = true; + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + return; + } if (session()->connection()->version().KnowsWhichDecrypterToUse()) { session()->connection()->InstallDecrypter( ENCRYPTION_ZERO_RTT, @@ -369,7 +388,11 @@ void QuicCryptoClientHandshaker::DoReceiveREJ( // Receipt of a REJ message means that the server received the CHLO // so we can cancel and retransmissions. - session()->NeuterUnencryptedData(); + if (session()->use_handshake_delegate()) { + delegate_->NeuterUnencryptedData(); + } else { + session()->NeuterUnencryptedData(); + } std::string error_details; QuicErrorCode error = crypto_config_->ProcessRejection( @@ -529,6 +552,18 @@ void QuicCryptoClientHandshaker::DoReceiveSHLO( // has been floated that the server shouldn't send packets encrypted // with the FORWARD_SECURE key until it receives a FORWARD_SECURE // packet from the client. + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( + ENCRYPTION_FORWARD_SECURE, std::move(crypters->decrypter), + /*set_alternative_decrypter=*/true, + /*latch_once_used=*/false, std::move(crypters->encrypter)); + handshake_confirmed_ = true; + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + delegate_->NeuterHandshakeData(); + return; + } + if (session()->connection()->version().KnowsWhichDecrypterToUse()) { session()->connection()->InstallDecrypter(ENCRYPTION_FORWARD_SECURE, std::move(crypters->decrypter)); 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 d33ebfe32fe..467e5c87208 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 @@ -37,6 +37,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker // From QuicCryptoClientStream::HandshakerDelegate bool CryptoConnect() override; int num_sent_client_hellos() const override; + bool IsResumption() const override; int num_scup_messages_received() const override; std::string chlo_hash() const override; bool encryption_established() const override; @@ -60,7 +61,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof. // The ProofVerifier calls this class with the result of proof verification // when verification is performed asynchronously. - class ProofVerifierCallbackImpl : public ProofVerifierCallback { + class QUIC_EXPORT_PRIVATE ProofVerifierCallbackImpl + : public ProofVerifierCallback { public: explicit ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent); ~ProofVerifierCallbackImpl() override; @@ -130,6 +132,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker QuicCryptoClientStream* stream_; QuicSession* session_; + HandshakerDelegateInterface* delegate_; State next_state_; // num_client_hellos_ contains the number of client hello messages that this 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 12b538f7cab..b30cd3a5112 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 @@ -43,9 +43,8 @@ QuicCryptoClientStream::QuicCryptoClientStream( break; case PROTOCOL_TLS1_3: handshaker_ = std::make_unique( - this, session, server_id, crypto_config->proof_verifier(), - crypto_config->ssl_ctx(), std::move(verify_context), proof_handler, - crypto_config->user_agent_id()); + server_id, this, session, std::move(verify_context), crypto_config, + proof_handler); break; case PROTOCOL_UNSUPPORTED: QUIC_BUG << "Attempting to create QuicCryptoClientStream for unknown " @@ -63,6 +62,10 @@ int QuicCryptoClientStream::num_sent_client_hellos() const { return handshaker_->num_sent_client_hellos(); } +bool QuicCryptoClientStream::IsResumption() const { + return handshaker_->IsResumption(); +} + int QuicCryptoClientStream::num_scup_messages_received() const { return handshaker_->num_scup_messages_received(); } 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 89f0d2e28b7..3f9b0af7747 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 @@ -35,6 +35,13 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream { // than the number of round-trips needed for the handshake. virtual int num_sent_client_hellos() const = 0; + // Returns true if the handshake performed was a resumption instead of a full + // handshake. Resumption only makes sense for TLS handshakes - there is no + // concept of resumption for QUIC crypto even though it supports a 0-RTT + // handshake. This function only returns valid results once the handshake is + // complete. + virtual bool IsResumption() const = 0; + // The number of server config update messages received by the // client. Does not count update messages that were received prior // to handshake confirmation. @@ -79,6 +86,13 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream // than the number of round-trips needed for the handshake. virtual int num_sent_client_hellos() const = 0; + // Returns true if the handshake performed was a resumption instead of a + // full handshake. Resumption only makes sense for TLS handshakes - there is + // no concept of resumption for QUIC crypto even though it supports a 0-RTT + // handshake. This function only returns valid results once the handshake is + // complete. + virtual bool IsResumption() const = 0; + // The number of server config update messages received by the // client. Does not count update messages that were received prior // to handshake confirmation. @@ -137,6 +151,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream // From QuicCryptoClientStreamBase bool CryptoConnect() override; int num_sent_client_hellos() const override; + bool IsResumption() const override; int num_scup_messages_received() const override; @@ -146,6 +161,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; CryptoMessageParser* crypto_message_parser() override; + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; std::string chlo_hash() const; 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 8e1ef25ea01..827cb03e3a3 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 @@ -22,6 +22,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_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_quic_framer.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" using testing::_; @@ -37,7 +38,10 @@ class QuicCryptoClientStreamTest : public QuicTest { QuicCryptoClientStreamTest() : supported_versions_(AllSupportedVersions()), server_id_(kServerHostname, kServerPort, false), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + std::make_unique()), + server_crypto_config_( + crypto_test_utils::CryptoServerConfigForTesting()) { CreateConnection(); } @@ -56,17 +60,30 @@ class QuicCryptoClientStreamTest : public QuicTest { {AlpnForVersion(connection_->version())}))); } + void UseTlsHandshake() { + SetQuicReloadableFlag(quic_supports_tls_handshake, true); + supported_versions_.clear(); + for (ParsedQuicVersion version : AllSupportedVersions()) { + if (version.handshake_protocol != PROTOCOL_TLS1_3) { + continue; + } + supported_versions_.push_back(version); + } + } + void CompleteCryptoHandshake() { + int proof_verify_details_calls = 1; if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) { EXPECT_CALL(*session_, OnProofValid(testing::_)); + proof_verify_details_calls = 0; } EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_)) - .Times(testing::AnyNumber()); + .Times(testing::AtLeast(proof_verify_details_calls)); stream()->CryptoConnect(); QuicConfig config; crypto_test_utils::HandshakeWithFakeServer( - &config, &server_helper_, &alarm_factory_, connection_, stream(), - AlpnForVersion(connection_->version())); + &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_, + connection_, stream(), AlpnForVersion(connection_->version())); } QuicCryptoClientStream* stream() { @@ -82,6 +99,7 @@ class QuicCryptoClientStreamTest : public QuicTest { QuicServerId server_id_; CryptoHandshakeMessage message_; QuicCryptoClientConfig crypto_config_; + std::unique_ptr server_crypto_config_; }; TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { @@ -93,45 +111,57 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { CompleteCryptoHandshake(); EXPECT_TRUE(stream()->encryption_established()); EXPECT_TRUE(stream()->handshake_confirmed()); + EXPECT_FALSE(stream()->IsResumption()); } TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) { - SetQuicReloadableFlag(quic_supports_tls_handshake, true); - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_TLS1_3) { - continue; - } - supported_versions_.push_back(version); - } + UseTlsHandshake(); CreateConnection(); CompleteCryptoHandshake(); EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); EXPECT_TRUE(stream()->encryption_established()); EXPECT_TRUE(stream()->handshake_confirmed()); + EXPECT_FALSE(stream()->IsResumption()); } TEST_F(QuicCryptoClientStreamTest, ProofVerifyDetailsAvailableAfterTlsHandshake) { - SetQuicReloadableFlag(quic_supports_tls_handshake, true); - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_TLS1_3) { - continue; - } - supported_versions_.push_back(version); - } + UseTlsHandshake(); CreateConnection(); EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_)); stream()->CryptoConnect(); QuicConfig config; crypto_test_utils::HandshakeWithFakeServer( - &config, &server_helper_, &alarm_factory_, connection_, stream(), - AlpnForVersion(connection_->version())); + &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_, + connection_, stream(), AlpnForVersion(connection_->version())); + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->handshake_confirmed()); +} + +TEST_F(QuicCryptoClientStreamTest, TlsResumption) { + UseTlsHandshake(); + // Enable resumption on the server: + SSL_CTX_clear_options(server_crypto_config_->ssl_ctx(), SSL_OP_NO_TICKET); + CreateConnection(); + + // Finish establishing the first connection: + CompleteCryptoHandshake(); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->handshake_confirmed()); + EXPECT_FALSE(stream()->IsResumption()); + + // Create a second connection + CreateConnection(); + CompleteCryptoHandshake(); + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); EXPECT_TRUE(stream()->encryption_established()); EXPECT_TRUE(stream()->handshake_confirmed()); + EXPECT_TRUE(stream()->IsResumption()); } TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { @@ -359,14 +389,14 @@ TEST_F(QuicCryptoClientStreamTest, PreferredVersion) { // Verify preferred version is the highest version that session supports, and // is different from connection's version. QuicVersionLabel client_version_label; - EXPECT_EQ(QUIC_NO_ERROR, - session_->sent_crypto_handshake_messages()[0].GetVersionLabel( - kVER, &client_version_label)); + EXPECT_THAT(session_->sent_crypto_handshake_messages()[0].GetVersionLabel( + kVER, &client_version_label), + IsQuicNoError()); EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]), client_version_label); - EXPECT_EQ(QUIC_NO_ERROR, - session_->sent_crypto_handshake_messages()[1].GetVersionLabel( - kVER, &client_version_label)); + EXPECT_THAT(session_->sent_crypto_handshake_messages()[1].GetVersionLabel( + kVER, &client_version_label), + IsQuicNoError()); EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]), client_version_label); EXPECT_NE(CreateQuicVersionLabel(connection_->version()), diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc index 964c8ac5a46..755e35eb400 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc @@ -54,6 +54,7 @@ QuicCryptoServerHandshaker::QuicCryptoServerHandshaker( : QuicCryptoHandshaker(stream, session), stream_(stream), session_(session), + delegate_(session), crypto_config_(crypto_config), compressed_certs_cache_(compressed_certs_cache), signed_config_(new QuicSignedServerConfig), @@ -197,27 +198,52 @@ void QuicCryptoServerHandshaker:: // write key. // // NOTE: the SHLO will be encrypted with the new server write key. - session()->connection()->SetEncrypter( - ENCRYPTION_ZERO_RTT, - std::move(crypto_negotiated_params_->initial_crypters.encrypter)); - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); - // Set the decrypter immediately so that we no longer accept unencrypted - // packets. - if (session()->connection()->version().KnowsWhichDecrypterToUse()) { - session()->connection()->InstallDecrypter( + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( ENCRYPTION_ZERO_RTT, - std::move(crypto_negotiated_params_->initial_crypters.decrypter)); - session()->connection()->RemoveDecrypter(ENCRYPTION_INITIAL); + std::move(crypto_negotiated_params_->initial_crypters.decrypter), + /*set_alternative_decrypter=*/false, + /*latch_once_used=*/false, + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + delegate_->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); } else { - session()->connection()->SetDecrypter( + session()->connection()->SetEncrypter( ENCRYPTION_ZERO_RTT, - std::move(crypto_negotiated_params_->initial_crypters.decrypter)); + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); + session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + // Set the decrypter immediately so that we no longer accept unencrypted + // packets. + if (session()->connection()->version().KnowsWhichDecrypterToUse()) { + session()->connection()->InstallDecrypter( + ENCRYPTION_ZERO_RTT, + std::move(crypto_negotiated_params_->initial_crypters.decrypter)); + session()->connection()->RemoveDecrypter(ENCRYPTION_INITIAL); + } else { + session()->connection()->SetDecrypter( + ENCRYPTION_ZERO_RTT, + std::move(crypto_negotiated_params_->initial_crypters.decrypter)); + } } session()->connection()->SetDiversificationNonce(*diversification_nonce); session()->connection()->set_fully_pad_crypto_handshake_packets( crypto_config_->pad_shlo()); SendHandshakeMessage(*reply); + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( + ENCRYPTION_FORWARD_SECURE, + std::move(crypto_negotiated_params_->forward_secure_crypters.decrypter), + /*set_alternative_decrypter=*/true, + /*latch_once_used=*/false, + std::move( + crypto_negotiated_params_->forward_secure_crypters.encrypter)); + encryption_established_ = true; + handshake_confirmed_ = true; + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + return; + } session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, @@ -336,6 +362,12 @@ void QuicCryptoServerHandshaker::SetPreviousCachedNetworkParams( new CachedNetworkParameters(cached_network_params)); } +void QuicCryptoServerHandshaker::OnPacketDecrypted(EncryptionLevel level) { + if (level == ENCRYPTION_FORWARD_SECURE) { + delegate_->NeuterHandshakeData(); + } +} + bool QuicCryptoServerHandshaker::ShouldSendExpectCTHeader() const { return signed_config_->proof.send_expect_ct_header; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h index b24e9e95e90..4e1a1b895fd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h @@ -50,6 +50,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker bool ZeroRttAttempted() const override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; + void OnPacketDecrypted(EncryptionLevel level) override; bool ShouldSendExpectCTHeader() const override; // From QuicCryptoStream @@ -91,7 +92,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker private: friend class test::QuicCryptoServerStreamPeer; - class ValidateCallback : public ValidateClientHelloResultCallback { + class QUIC_EXPORT_PRIVATE ValidateCallback + : public ValidateClientHelloResultCallback { public: explicit ValidateCallback(QuicCryptoServerHandshaker* parent); ValidateCallback(const ValidateCallback&) = delete; @@ -161,6 +163,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker QuicCryptoServerStream* stream_; QuicSession* session_; + HandshakerDelegateInterface* delegate_; // crypto_config_ contains crypto parameters for the handshake. const QuicCryptoServerConfig* crypto_config_; 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 170e53baf01..bbc3b09d5c9 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 @@ -111,6 +111,10 @@ CryptoMessageParser* QuicCryptoServerStream::crypto_message_parser() { return handshaker()->crypto_message_parser(); } +void QuicCryptoServerStream::OnPacketDecrypted(EncryptionLevel level) { + handshaker()->OnPacketDecrypted(level); +} + size_t QuicCryptoServerStream::BufferSizeLimitForLevel( EncryptionLevel level) const { return handshaker()->BufferSizeLimitForLevel(level); 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 3a7d6e74b1a..d80c495e413 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 @@ -98,6 +98,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream virtual bool ZeroRttAttempted() const = 0; virtual void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) = 0; + virtual void OnPacketDecrypted(EncryptionLevel level) = 0; // NOTE: Indicating that the Expect-CT header should be sent here presents a // layering violation to some extent. The Expect-CT header only applies to @@ -125,7 +126,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const = 0; }; - class Helper { + class QUIC_EXPORT_PRIVATE Helper { public: virtual ~Helper() {} @@ -176,6 +177,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; CryptoMessageParser* crypto_message_parser() override; + void OnPacketDecrypted(EncryptionLevel level) override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; void OnSuccessfulVersionNegotiation( const ParsedQuicVersion& version) override; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc index 360c2684fc5..2f7055da328 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc @@ -100,8 +100,10 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam { crypto_test_utils::SetupCryptoServerConfigForTest( server_connection_->clock(), server_connection_->random_generator(), &server_crypto_config_); - server_session_->GetMutableCryptoStream()->OnSuccessfulVersionNegotiation( - supported_versions_.front()); + if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + server_session_->GetMutableCryptoStream()->OnSuccessfulVersionNegotiation( + supported_versions_.front()); + } } QuicCryptoServerStream* server_stream() { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc index d62417fbf51..e22e830d381 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc @@ -72,8 +72,15 @@ void QuicCryptoStream::OnCryptoFrame(const QuicCryptoFrame& frame) { << "Versions less than 47 shouldn't receive CRYPTO frames"; EncryptionLevel level = session()->connection()->last_decrypted_level(); substreams_[level].sequencer.OnCryptoFrame(frame); + EncryptionLevel frame_level; + if (GetQuicReloadableFlag(quic_use_connection_encryption_level)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_connection_encryption_level); + frame_level = level; + } else { + frame_level = frame.level; + } if (substreams_[level].sequencer.NumBytesBuffered() > - BufferSizeLimitForLevel(frame.level)) { + BufferSizeLimitForLevel(frame_level)) { CloseConnectionWithDetails(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, "Too much crypto data received"); } 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 12a36f894b6..357303a65bb 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 @@ -80,6 +80,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Provides the message parser to use when data is received on this stream. virtual CryptoMessageParser* crypto_message_parser() = 0; + // Called when a packet of encryption |level| has been successfully decrypted. + virtual void OnPacketDecrypted(EncryptionLevel level) = 0; + // Returns the maximum number of bytes that can be buffered at a particular // encryption level |level|. virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const; @@ -155,7 +158,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // levels. Some of the state for the single logical crypto stream is split // across encryption levels, and a CryptoSubstream is used to manage that // state for a particular encryption level. - struct CryptoSubstream { + struct QUIC_EXPORT_PRIVATE CryptoSubstream { CryptoSubstream(QuicCryptoStream* crypto_stream, EncryptionLevel); QuicStreamSequencer sequencer; 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 f5933d2fd89..25d9cc17ae1 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 @@ -56,6 +56,7 @@ class MockQuicCryptoStream : public QuicCryptoStream, CryptoMessageParser* crypto_message_parser() override { return QuicCryptoHandshaker::crypto_message_parser(); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} private: QuicReferenceCountedPointer params_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc index c9a76be8f57..17fb6cdafc3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc @@ -9,18 +9,19 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { QuicDataReader::QuicDataReader(QuicStringPiece data) - : QuicDataReader(data.data(), data.length(), NETWORK_BYTE_ORDER) {} + : QuicDataReader(data.data(), data.length(), quiche::NETWORK_BYTE_ORDER) {} QuicDataReader::QuicDataReader(const char* data, const size_t len) - : QuicDataReader(data, len, NETWORK_BYTE_ORDER) {} + : QuicDataReader(data, len, quiche::NETWORK_BYTE_ORDER) {} QuicDataReader::QuicDataReader(const char* data, const size_t len, - Endianness endianness) + quiche::Endianness endianness) : data_(data), len_(len), pos_(0), endianness_(endianness) {} bool QuicDataReader::ReadUInt8(uint8_t* result) { @@ -31,8 +32,8 @@ bool QuicDataReader::ReadUInt16(uint16_t* result) { if (!ReadBytes(result, sizeof(*result))) { return false; } - if (endianness_ == NETWORK_BYTE_ORDER) { - *result = QuicEndian::NetToHost16(*result); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + *result = quiche::QuicheEndian::NetToHost16(*result); } return true; } @@ -41,8 +42,8 @@ bool QuicDataReader::ReadUInt32(uint32_t* result) { if (!ReadBytes(result, sizeof(*result))) { return false; } - if (endianness_ == NETWORK_BYTE_ORDER) { - *result = QuicEndian::NetToHost32(*result); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + *result = quiche::QuicheEndian::NetToHost32(*result); } return true; } @@ -51,8 +52,8 @@ bool QuicDataReader::ReadUInt64(uint64_t* result) { if (!ReadBytes(result, sizeof(*result))) { return false; } - if (endianness_ == NETWORK_BYTE_ORDER) { - *result = QuicEndian::NetToHost64(*result); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + *result = quiche::QuicheEndian::NetToHost64(*result); } return true; } @@ -62,7 +63,7 @@ bool QuicDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) { if (num_bytes > sizeof(*result)) { return false; } - if (endianness_ == HOST_BYTE_ORDER) { + if (endianness_ == quiche::HOST_BYTE_ORDER) { return ReadBytes(result, num_bytes); } @@ -70,7 +71,7 @@ bool QuicDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) { num_bytes)) { return false; } - *result = QuicEndian::NetToHost64(*result); + *result = quiche::QuicheEndian::NetToHost64(*result); return true; } @@ -217,7 +218,7 @@ bool QuicDataReader::IsDoneReading() const { } QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() { - DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); const unsigned char* next = reinterpret_cast(data_ + pos_); if (BytesRemaining() == 0) { @@ -275,7 +276,7 @@ uint8_t QuicDataReader::PeekByte() const { // Low-level optimization is useful here because this function will be // called frequently, leading to outsize benefits. bool QuicDataReader::ReadVarInt62(uint64_t* result) { - DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); size_t remaining = BytesRemaining(); const unsigned char* next = diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h index 74ed2269d0c..acd30fda100 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h @@ -9,9 +9,9 @@ #include #include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -39,7 +39,9 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { QuicDataReader(const char* data, const size_t len); // Constructs a reader using the specified endianness. // Caller must provide an underlying buffer to work on. - QuicDataReader(const char* data, const size_t len, Endianness endianness); + QuicDataReader(const char* data, + const size_t len, + quiche::Endianness endianness); QuicDataReader(const QuicDataReader&) = delete; QuicDataReader& operator=(const QuicDataReader&) = delete; @@ -152,8 +154,6 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { // DOES NOT forward the internal iterator. uint8_t PeekByte() const; - void set_endianness(Endianness endianness) { endianness_ = endianness; } - // Read an IETF-encoded Variable Length Integer and place the result // in |*result|. // Returns true if it works, false if not. The only error is that @@ -190,7 +190,7 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { size_t pos_; // The endianness to read integers and floating numbers. - Endianness endianness_; + quiche::Endianness endianness_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc index e01eb6c4d24..d2d71133fe7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc @@ -12,13 +12,16 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { QuicDataWriter::QuicDataWriter(size_t size, char* buffer) - : QuicDataWriter(size, buffer, NETWORK_BYTE_ORDER) {} + : QuicDataWriter(size, buffer, quiche::NETWORK_BYTE_ORDER) {} -QuicDataWriter::QuicDataWriter(size_t size, char* buffer, Endianness endianness) +QuicDataWriter::QuicDataWriter(size_t size, + char* buffer, + quiche::Endianness endianness) : buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {} QuicDataWriter::~QuicDataWriter() {} @@ -32,22 +35,22 @@ bool QuicDataWriter::WriteUInt8(uint8_t value) { } bool QuicDataWriter::WriteUInt16(uint16_t value) { - if (endianness_ == NETWORK_BYTE_ORDER) { - value = QuicEndian::HostToNet16(value); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + value = quiche::QuicheEndian::HostToNet16(value); } return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUInt32(uint32_t value) { - if (endianness_ == NETWORK_BYTE_ORDER) { - value = QuicEndian::HostToNet32(value); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + value = quiche::QuicheEndian::HostToNet32(value); } return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUInt64(uint64_t value) { - if (endianness_ == NETWORK_BYTE_ORDER) { - value = QuicEndian::HostToNet64(value); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + value = quiche::QuicheEndian::HostToNet64(value); } return WriteBytes(&value, sizeof(value)); } @@ -56,11 +59,11 @@ bool QuicDataWriter::WriteBytesToUInt64(size_t num_bytes, uint64_t value) { if (num_bytes > sizeof(value)) { return false; } - if (endianness_ == HOST_BYTE_ORDER) { + if (endianness_ == quiche::HOST_BYTE_ORDER) { return WriteBytes(&value, num_bytes); } - value = QuicEndian::HostToNet64(value); + value = quiche::QuicheEndian::HostToNet64(value); return WriteBytes(reinterpret_cast(&value) + sizeof(value) - num_bytes, num_bytes); } @@ -101,8 +104,8 @@ bool QuicDataWriter::WriteUFloat16(uint64_t value) { result = static_cast(value + (exponent << kUFloat16MantissaBits)); } - if (endianness_ == NETWORK_BYTE_ORDER) { - result = QuicEndian::HostToNet16(result); + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + result = quiche::QuicheEndian::HostToNet16(result); } return WriteBytes(&result, sizeof(result)); } @@ -227,7 +230,7 @@ bool QuicDataWriter::Seek(size_t length) { // Low-level optimization is useful here because this function will be // called frequently, leading to outsize benefits. bool QuicDataWriter::WriteVarInt62(uint64_t value) { - DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); size_t remaining = capacity_ - length_; char* next = buffer_ + length_; @@ -298,7 +301,7 @@ bool QuicDataWriter::WriteVarInt62(uint64_t value) { bool QuicDataWriter::WriteVarInt62( uint64_t value, QuicVariableLengthIntegerLength write_length) { - DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); size_t remaining = capacity_ - length_; if (remaining < write_length) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h index c43d0ffc743..8f1b21defd5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h @@ -9,9 +9,9 @@ #include #include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -42,7 +42,7 @@ class QUIC_EXPORT_PRIVATE QuicDataWriter { QuicDataWriter(size_t size, char* buffer); // Creates a QuicDataWriter where |buffer| is not owned // using the specified endianness. - QuicDataWriter(size_t size, char* buffer, Endianness endianness); + QuicDataWriter(size_t size, char* buffer, quiche::Endianness endianness); QuicDataWriter(const QuicDataWriter&) = delete; QuicDataWriter& operator=(const QuicDataWriter&) = delete; @@ -144,7 +144,7 @@ class QUIC_EXPORT_PRIVATE QuicDataWriter { size_t length_; // Current length of the buffer. // The endianness to write integers and floating numbers. - Endianness endianness_; + quiche::Endianness endianness_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc index 60abf961bc1..104df8d42ee 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace test { @@ -25,20 +26,22 @@ char* AsChars(unsigned char* data) { } struct TestParams { - explicit TestParams(Endianness endianness) : endianness(endianness) {} + explicit TestParams(quiche::Endianness endianness) : endianness(endianness) {} - Endianness endianness; + quiche::Endianness endianness; }; // Used by ::testing::PrintToStringParamName(). std::string PrintToString(const TestParams& p) { - return QuicStrCat((p.endianness == NETWORK_BYTE_ORDER ? "Network" : "Host"), - "ByteOrder"); + return QuicStrCat( + (p.endianness == quiche::NETWORK_BYTE_ORDER ? "Network" : "Host"), + "ByteOrder"); } std::vector GetTestParams() { std::vector params; - for (Endianness endianness : {NETWORK_BYTE_ORDER, HOST_BYTE_ORDER}) { + for (quiche::Endianness endianness : + {quiche::NETWORK_BYTE_ORDER, quiche::HOST_BYTE_ORDER}) { params.push_back(TestParams(endianness)); } return params; @@ -135,8 +138,8 @@ TEST_P(QuicDataWriterTest, WriteUFloat16) { QuicDataWriter writer(2, buffer, GetParam().endianness); EXPECT_TRUE(writer.WriteUFloat16(test_cases[i].decoded)); uint16_t result = *reinterpret_cast(writer.data()); - if (GetParam().endianness == NETWORK_BYTE_ORDER) { - result = QuicEndian::HostToNet16(result); + if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { + result = quiche::QuicheEndian::HostToNet16(result); } EXPECT_EQ(test_cases[i].encoded, result); } @@ -196,8 +199,8 @@ TEST_P(QuicDataWriterTest, ReadUFloat16) { for (int i = 0; i < num_test_cases; ++i) { uint16_t encoded_ufloat = test_cases[i].encoded; - if (GetParam().endianness == NETWORK_BYTE_ORDER) { - encoded_ufloat = QuicEndian::HostToNet16(encoded_ufloat); + if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { + encoded_ufloat = quiche::QuicheEndian::HostToNet16(encoded_ufloat); } QuicDataReader reader(reinterpret_cast(&encoded_ufloat), 2, GetParam().endianness); @@ -213,8 +216,8 @@ TEST_P(QuicDataWriterTest, RoundTripUFloat16) { for (uint16_t i = 1; i < 0xFFFF; ++i) { // Read the two bytes. uint16_t read_number = i; - if (GetParam().endianness == NETWORK_BYTE_ORDER) { - read_number = QuicEndian::HostToNet16(read_number); + if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { + read_number = quiche::QuicheEndian::HostToNet16(read_number); } QuicDataReader reader(reinterpret_cast(&read_number), 2, GetParam().endianness); @@ -243,10 +246,10 @@ TEST_P(QuicDataWriterTest, RoundTripUFloat16) { uint16_t encoded1 = *reinterpret_cast(writer.data()); uint16_t encoded2 = *reinterpret_cast(writer.data() + 2); uint16_t encoded3 = *reinterpret_cast(writer.data() + 4); - if (GetParam().endianness == NETWORK_BYTE_ORDER) { - encoded1 = QuicEndian::NetToHost16(encoded1); - encoded2 = QuicEndian::NetToHost16(encoded2); - encoded3 = QuicEndian::NetToHost16(encoded3); + if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { + encoded1 = quiche::QuicheEndian::NetToHost16(encoded1); + encoded2 = quiche::QuicheEndian::NetToHost16(encoded2); + encoded3 = quiche::QuicheEndian::NetToHost16(encoded3); } EXPECT_EQ(i - 1, encoded1); // Check roundtrip. @@ -384,8 +387,8 @@ TEST_P(QuicDataWriterTest, Write16BitUnsignedIntegers) { writer.WriteUInt16(in_memory16); test::CompareCharArraysWithHexError( "uint16_t", buffer16, 2, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian16 - : little_endian16, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16 + : little_endian16, 2); uint16_t read_number16; @@ -400,8 +403,8 @@ TEST_P(QuicDataWriterTest, Write16BitUnsignedIntegers) { writer.WriteBytesToUInt64(2, in_memory16); test::CompareCharArraysWithHexError( "uint16_t", buffer16, 2, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian16 - : little_endian16, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16 + : little_endian16, 2); uint64_t read_number16; @@ -420,8 +423,8 @@ TEST_P(QuicDataWriterTest, Write24BitUnsignedIntegers) { writer.WriteBytesToUInt64(3, in_memory24); test::CompareCharArraysWithHexError( "uint24", buffer24, 3, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian24 - : little_endian24, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian24 + : little_endian24, 3); uint64_t read_number24; @@ -440,8 +443,8 @@ TEST_P(QuicDataWriterTest, Write32BitUnsignedIntegers) { writer.WriteUInt32(in_memory32); test::CompareCharArraysWithHexError( "uint32_t", buffer32, 4, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian32 - : little_endian32, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32 + : little_endian32, 4); uint32_t read_number32; @@ -456,8 +459,8 @@ TEST_P(QuicDataWriterTest, Write32BitUnsignedIntegers) { writer.WriteBytesToUInt64(4, in_memory32); test::CompareCharArraysWithHexError( "uint32_t", buffer32, 4, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian32 - : little_endian32, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32 + : little_endian32, 4); uint64_t read_number32; @@ -476,8 +479,8 @@ TEST_P(QuicDataWriterTest, Write40BitUnsignedIntegers) { writer.WriteBytesToUInt64(5, in_memory40); test::CompareCharArraysWithHexError( "uint40", buffer40, 5, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian40 - : little_endian40, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian40 + : little_endian40, 5); uint64_t read_number40; @@ -495,8 +498,8 @@ TEST_P(QuicDataWriterTest, Write48BitUnsignedIntegers) { writer.WriteBytesToUInt64(6, in_memory48); test::CompareCharArraysWithHexError( "uint48", buffer48, 6, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian48 - : little_endian48, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian48 + : little_endian48, 6); uint64_t read_number48; @@ -514,8 +517,8 @@ TEST_P(QuicDataWriterTest, Write56BitUnsignedIntegers) { writer.WriteBytesToUInt64(7, in_memory56); test::CompareCharArraysWithHexError( "uint56", buffer56, 7, - GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian56 - : little_endian56, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian56 + : little_endian56, 7); uint64_t read_number56; @@ -535,8 +538,9 @@ TEST_P(QuicDataWriterTest, Write64BitUnsignedIntegers) { writer.WriteBytesToUInt64(8, in_memory64); test::CompareCharArraysWithHexError( "uint64_t", buffer64, 8, - GetParam().endianness == NETWORK_BYTE_ORDER ? AsChars(big_endian64) - : AsChars(little_endian64), + GetParam().endianness == quiche::NETWORK_BYTE_ORDER + ? AsChars(big_endian64) + : AsChars(little_endian64), 8); uint64_t read_number64; @@ -548,8 +552,9 @@ TEST_P(QuicDataWriterTest, Write64BitUnsignedIntegers) { writer2.WriteUInt64(in_memory64); test::CompareCharArraysWithHexError( "uint64_t", buffer64, 8, - GetParam().endianness == NETWORK_BYTE_ORDER ? AsChars(big_endian64) - : AsChars(little_endian64), + GetParam().endianness == quiche::NETWORK_BYTE_ORDER + ? AsChars(big_endian64) + : AsChars(little_endian64), 8); read_number64 = 0u; QuicDataReader reader2(buffer64, 8, GetParam().endianness); @@ -674,7 +679,8 @@ bool EncodeDecodeValue(uint64_t value_in, char* buffer, size_t size_of_buffer) { // make a writer. Note that for IETF encoding // we do not care about endianness... It's always big-endian, // but the c'tor expects to be told what endianness is in force... - QuicDataWriter writer(size_of_buffer, buffer, Endianness::NETWORK_BYTE_ORDER); + QuicDataWriter writer(size_of_buffer, buffer, + quiche::Endianness::NETWORK_BYTE_ORDER); // Try to write the value. if (writer.WriteVarInt62(value_in) != true) { @@ -699,7 +705,7 @@ bool EncodeDecodeValue(uint64_t value_in, char* buffer, size_t size_of_buffer) { // set up a reader, just the length we've used, no more, no less. QuicDataReader reader(buffer, expected_length, - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); uint64_t value_out; if (reader.ReadVarInt62(&value_out) == false) { @@ -721,7 +727,7 @@ TEST_P(QuicDataWriterTest, VarInt8Layout) { // are always encoded big endian... memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); EXPECT_EQ(static_cast(*(writer.data() + 0)), (0x31 + 0xc0)); // 0xc0 for encoding @@ -743,7 +749,7 @@ TEST_P(QuicDataWriterTest, VarInt4Layout) { // are always encoded big endian... memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer.WriteVarInt62(0x3243f4e5)); EXPECT_EQ(static_cast(*(writer.data() + 0)), (0x32 + 0x80)); // 0x80 for encoding @@ -761,7 +767,7 @@ TEST_P(QuicDataWriterTest, VarInt2Layout) { // are always encoded big endian... memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer.WriteVarInt62(0x3647)); EXPECT_EQ(static_cast(*(writer.data() + 0)), (0x36 + 0x40)); // 0x40 for encoding @@ -777,7 +783,7 @@ TEST_P(QuicDataWriterTest, VarInt1Layout) { // is correct. Bytes are always encoded big endian... memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer.WriteVarInt62(0x3f)); EXPECT_EQ(static_cast(*(writer.data() + 0)), 0x3f); } @@ -883,7 +889,7 @@ TEST_P(QuicDataWriterTest, MultiVarInt8) { char buffer[8 * kMultiVarCount]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); // Put N values into the buffer. Adding i to the value ensures that // each value is different so we can detect if we overwrite values, // or read the same value over and over. @@ -897,7 +903,8 @@ TEST_P(QuicDataWriterTest, MultiVarInt8) { // Now we should be able to read out the N values that were // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); for (int i = 0; i < kMultiVarCount; i++) { EXPECT_TRUE(reader.ReadVarInt62(&test_val)); EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4d5c6b7a8) + i)); @@ -912,7 +919,7 @@ TEST_P(QuicDataWriterTest, MultiVarInt4) { char buffer[4 * kMultiVarCount]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); // Put N values into the buffer. Adding i to the value ensures that // each value is different so we can detect if we overwrite values, // or read the same value over and over. @@ -926,7 +933,8 @@ TEST_P(QuicDataWriterTest, MultiVarInt4) { // Now we should be able to read out the N values that were // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); for (int i = 0; i < kMultiVarCount; i++) { EXPECT_TRUE(reader.ReadVarInt62(&test_val)); EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4) + i)); @@ -941,7 +949,7 @@ TEST_P(QuicDataWriterTest, MultiVarInt2) { char buffer[2 * kMultiVarCount]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); // Put N values into the buffer. Adding i to the value ensures that // each value is different so we can detect if we overwrite values, // or read the same value over and over. @@ -955,7 +963,8 @@ TEST_P(QuicDataWriterTest, MultiVarInt2) { // Now we should be able to read out the N values that were // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); for (int i = 0; i < kMultiVarCount; i++) { EXPECT_TRUE(reader.ReadVarInt62(&test_val)); EXPECT_EQ(test_val, (UINT64_C(0x3142) + i)); @@ -970,7 +979,7 @@ TEST_P(QuicDataWriterTest, MultiVarInt1) { char buffer[1 * kMultiVarCount]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); // Put N values into the buffer. Adding i to the value ensures that // each value is different so we can detect if we overwrite values, // or read the same value over and over. &0xf ensures we do not @@ -985,7 +994,8 @@ TEST_P(QuicDataWriterTest, MultiVarInt1) { // Now we should be able to read out the N values that were // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); for (int i = 0; i < kMultiVarCount; i++) { EXPECT_TRUE(reader.ReadVarInt62(&test_val)); EXPECT_EQ(test_val, (UINT64_C(0x30) + (i & 0xf))); @@ -999,7 +1009,7 @@ TEST_P(QuicDataWriterTest, VarIntFixedLength) { char buffer[90]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_1); writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_2); @@ -1027,7 +1037,8 @@ TEST_P(QuicDataWriterTest, VarIntFixedLength) { writer.WriteVarInt62(1073741824, VARIABLE_LENGTH_INTEGER_LENGTH_8); - QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); uint64_t test_val = 0; for (int i = 0; i < 4; ++i) { @@ -1071,10 +1082,11 @@ void EncodeDecodeStreamId(uint64_t value_in, bool expected_decode_result) { // Encode the given Stream ID. QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer.WriteVarInt62(value_in)); - QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); QuicStreamId received_stream_id; bool read_result = reader.ReadVarIntU32(&received_stream_id); EXPECT_EQ(expected_decode_result, read_result); @@ -1124,28 +1136,28 @@ TEST_P(QuicDataWriterTest, WriteRandomBytes) { TEST_P(QuicDataWriterTest, PeekVarInt62Length) { // In range [0, 63], variable length should be 1 byte. char buffer[20]; - QuicDataWriter writer(20, buffer, NETWORK_BYTE_ORDER); + QuicDataWriter writer(20, buffer, quiche::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer.WriteVarInt62(50)); - QuicDataReader reader(buffer, 20, NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, 20, quiche::NETWORK_BYTE_ORDER); EXPECT_EQ(1, reader.PeekVarInt62Length()); // In range (63-16383], variable length should be 2 byte2. char buffer2[20]; - QuicDataWriter writer2(20, buffer2, NETWORK_BYTE_ORDER); + QuicDataWriter writer2(20, buffer2, quiche::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer2.WriteVarInt62(100)); - QuicDataReader reader2(buffer2, 20, NETWORK_BYTE_ORDER); + QuicDataReader reader2(buffer2, 20, quiche::NETWORK_BYTE_ORDER); EXPECT_EQ(2, reader2.PeekVarInt62Length()); // In range (16383, 1073741823], variable length should be 4 bytes. char buffer3[20]; - QuicDataWriter writer3(20, buffer3, NETWORK_BYTE_ORDER); + QuicDataWriter writer3(20, buffer3, quiche::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer3.WriteVarInt62(20000)); - QuicDataReader reader3(buffer3, 20, NETWORK_BYTE_ORDER); + QuicDataReader reader3(buffer3, 20, quiche::NETWORK_BYTE_ORDER); EXPECT_EQ(4, reader3.PeekVarInt62Length()); // In range (1073741823, 4611686018427387903], variable length should be 8 // bytes. char buffer4[20]; - QuicDataWriter writer4(20, buffer4, NETWORK_BYTE_ORDER); + QuicDataWriter writer4(20, buffer4, quiche::NETWORK_BYTE_ORDER); EXPECT_TRUE(writer4.WriteVarInt62(2000000000)); - QuicDataReader reader4(buffer4, 20, NETWORK_BYTE_ORDER); + QuicDataReader reader4(buffer4, 20, quiche::NETWORK_BYTE_ORDER); EXPECT_EQ(8, reader4.PeekVarInt62Length()); } @@ -1171,7 +1183,7 @@ TEST_P(QuicDataWriterTest, ValidU32) { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); QuicDataReader reader(buffer, sizeof(buffer)); const QuicStreamCount write_stream_count = 0xffeeddcc; EXPECT_TRUE(writer.WriteVarInt62(write_stream_count)); @@ -1184,7 +1196,7 @@ TEST_P(QuicDataWriterTest, InvalidU32) { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); QuicDataWriter writer(sizeof(buffer), static_cast(buffer), - Endianness::NETWORK_BYTE_ORDER); + quiche::Endianness::NETWORK_BYTE_ORDER); QuicDataReader reader(buffer, sizeof(buffer)); EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x1ffeeddcc))); QuicStreamCount read_stream_count = 123456; 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 acc5cb3bbdb..a1adda4c1b6 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 @@ -135,10 +135,7 @@ class StatelessConnectionTerminator { creator_(server_connection_id, &framer_, &collector_), time_wait_list_manager_(time_wait_list_manager) { framer_.set_data_producer(&collector_); - if (framer_.framer_doesnt_create_initial_encrypter() || - version.UsesInitialObfuscators()) { - framer_.SetInitialObfuscators(server_connection_id); - } + framer_.SetInitialObfuscators(server_connection_id); } ~StatelessConnectionTerminator() { @@ -179,7 +176,7 @@ class StatelessConnectionTerminator { framer_.transport_version(), error_code, error_details, /*transport_close_frame_type=*/0); - if (!creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)) { + if (!creator_.AddFrame(QuicFrame(frame), NOT_RETRANSMISSION)) { QUIC_BUG << "Unable to add frame to an empty packet"; delete frame; return; @@ -454,12 +451,10 @@ bool QuicDispatcher::MaybeDispatchPacket( return true; } - if (GetQuicReloadableFlag(quic_donot_process_small_initial_packets) && - crypto_config()->validate_chlo_size() && + if (crypto_config()->validate_chlo_size() && packet_info.form == IETF_QUIC_LONG_HEADER_PACKET && packet_info.long_packet_type == INITIAL && packet_info.packet.length() < kMinClientInitialPacketLength) { - QUIC_RELOADABLE_FLAG_COUNT(quic_donot_process_small_initial_packets); StatelessConnectionTerminator terminator( packet_info.destination_connection_id, packet_info.version, helper_.get(), time_wait_list_manager_.get()); @@ -530,8 +525,6 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( const ReceivedPacketInfo& packet_info) { if (!packet_info.version_flag) { - if (GetQuicReloadableFlag(quic_reply_to_old_android_conformance_test)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_reply_to_old_android_conformance_test); // The Android network conformance test contains a UDP test that sends a // 12-byte packet with the following format: // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number) @@ -559,17 +552,12 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( /*ietf_quic=*/false, GetPerPacketContext()); return kFateDrop; } - } QUIC_DLOG(INFO) << "Packet without version arrived for unknown connection ID " << packet_info.destination_connection_id; - if (GetQuicReloadableFlag(quic_reject_unprocessable_packets_statelessly)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_reject_unprocessable_packets_statelessly); - MaybeResetPacketsWithNoVersion(packet_info); - return kFateDrop; - } - return kFateTimeWait; + MaybeResetPacketsWithNoVersion(packet_info); + return kFateDrop; } // Let the connection parse and validate packet number. @@ -586,7 +574,7 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it, !connection->termination_packets()->empty()) { action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; } else { - if (!connection->IsHandshakeConfirmed()) { + if (!connection->IsHandshakeComplete()) { if (!VersionHasIetfInvariantHeader(connection->transport_version())) { QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed); } else { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h index abcd4f2f733..7dbdea65339 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h @@ -34,9 +34,10 @@ class QuicDispatcherPeer; class QuicConfig; class QuicCryptoServerConfig; -class QuicDispatcher : public QuicTimeWaitListManager::Visitor, - public ProcessPacketInterface, - public QuicBufferedPacketStore::VisitorInterface { +class QUIC_NO_EXPORT QuicDispatcher + : public QuicTimeWaitListManager::Visitor, + public ProcessPacketInterface, + public QuicBufferedPacketStore::VisitorInterface { public: // Ideally we'd have a linked_hash_set: the boolean is unused. typedef QuicLinkedHashMap WriteBlockedList; @@ -313,11 +314,6 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // connection ID according to the packet's size. void MaybeResetPacketsWithNoVersion(const ReceivedPacketInfo& packet_info); - void set_new_sessions_allowed_per_event_loop( - int16_t new_sessions_allowed_per_event_loop) { - new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop; - } - const QuicConfig* config_; const QuicCryptoServerConfig* crypto_config_; 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 3240ceb2557..896438a2b73 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 @@ -417,7 +417,7 @@ class QuicDispatcherTest : public QuicTest { TEST_F(QuicDispatcherTest, TlsClientHelloCreatesSession) { if (!QuicVersionUsesCryptoFrames( CurrentSupportedVersions().front().transport_version)) { - // TLS is only supported in versions 47 and greater. + // TLS is only supported in versions with crypto frames. return; } SetQuicReloadableFlag(quic_supports_tls_handshake, true); @@ -684,23 +684,14 @@ TEST_F(QuicDispatcherTest, NoVersionPacketToTimeWaitListManager) { // list manager. EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq"), _)) .Times(0); - if (GetQuicReloadableFlag(quic_reject_unprocessable_packets_statelessly)) { - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(_, _, _, _, _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) - .Times(1); - } else { - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) - .Times(1); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(_, _, _, _, _)) - .Times(1); - } + EXPECT_CALL(*time_wait_list_manager_, + ProcessPacket(_, _, connection_id, _, _)) + .Times(0); + EXPECT_CALL(*time_wait_list_manager_, + AddConnectionIdToTimeWait(_, _, _, _, _)) + .Times(0); + EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) + .Times(1); ProcessPacket(client_address, connection_id, false, SerializeCHLO()); } @@ -714,29 +705,16 @@ TEST_F(QuicDispatcherTest, char valid_size_packet[23] = {0x70, 0xa7, 0x02, 0x6c}; QuicReceivedPacket packet2(valid_size_packet, 23, QuicTime::Zero()); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); - if (GetQuicReloadableFlag(quic_reject_unprocessable_packets_statelessly)) { - EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(_, _, _, _, _)) - .Times(0); - } else { - EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)) - .Times(2); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(_, _, _, _, _)) - .Times(2); - } - if (GetQuicReloadableFlag(quic_reject_unprocessable_packets_statelessly)) { - // Verify small packet is silently dropped. - EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) - .Times(0); - } + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0); + EXPECT_CALL(*time_wait_list_manager_, + AddConnectionIdToTimeWait(_, _, _, _, _)) + .Times(0); + // Verify small packet is silently dropped. + EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) + .Times(0); dispatcher_->ProcessPacket(server_address_, client_address, packet); - if (GetQuicReloadableFlag(quic_reject_unprocessable_packets_statelessly)) { - EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) - .Times(1); - } + EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) + .Times(1); dispatcher_->ProcessPacket(server_address_, client_address, packet2); } @@ -886,8 +864,8 @@ TEST_F(QuicDispatcherTest, ProcessPacketWithZeroPort) { } TEST_F(QuicDispatcherTest, ProcessPacketWithInvalidShortInitialConnectionId) { - // Enable v47 otherwise we cannot create a packet with a short connection ID. - SetQuicReloadableFlag(quic_enable_version_47, true); + // Enable a version that supports connection IDs of length different than 8. + SetQuicReloadableFlag(quic_enable_version_50, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -931,12 +909,8 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) { } TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, true); - SetQuicReloadableFlag(quic_enable_version_48_2, true); - SetQuicReloadableFlag(quic_enable_version_49, true); SetQuicReloadableFlag(quic_enable_version_50, true); SetQuicReloadableFlag(quic_enable_version_99, true); @@ -955,73 +929,52 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { SetQuicReloadableFlag(quic_enable_version_50, true); VerifyVersionSupported( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); - - // Turn off version 49. - SetQuicReloadableFlag(quic_enable_version_49, false); - VerifyVersionNotSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); - - // Turn on version 49. - SetQuicReloadableFlag(quic_enable_version_49, true); - VerifyVersionSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); - - // Turn off version 48. - SetQuicReloadableFlag(quic_enable_version_48_2, false); - VerifyVersionNotSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)); - - // Turn on version 48. - SetQuicReloadableFlag(quic_enable_version_48_2, true); - VerifyVersionSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)); - - // Turn off version 47. - SetQuicReloadableFlag(quic_enable_version_47, false); - VerifyVersionNotSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47)); - - // Turn on version 47. - SetQuicReloadableFlag(quic_enable_version_47, true); - VerifyVersionSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47)); - - // Turn off version 39. - SetQuicReloadableFlag(quic_disable_version_39, true); - VerifyVersionNotSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39)); - - // Turn on version 39. - SetQuicReloadableFlag(quic_disable_version_39, false); - VerifyVersionSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39)); } TEST_F(QuicDispatcherTest, RejectDeprecatedVersionsWithVersionNegotiation) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Please add deprecated versions to this test"); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); CreateTimeWaitListManager(); - char packet45[kMinPacketSizeForVersionNegotiation] = { - 0xC0, 'Q', '0', '4', '5', /*connection ID length byte*/ 0x50}; - QuicReceivedPacket packet(packet45, kMinPacketSizeForVersionNegotiation, - QuicTime::Zero()); - EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) - .Times(1); - dispatcher_->ProcessPacket(server_address_, client_address, packet); + { + char packet47[kMinPacketSizeForVersionNegotiation] = { + 0xC0, 'Q', '0', '4', '7', /*connection ID length byte*/ 0x50}; + QuicReceivedPacket received_packet47( + packet47, kMinPacketSizeForVersionNegotiation, QuicTime::Zero()); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); + EXPECT_CALL(*time_wait_list_manager_, + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) + .Times(1); + dispatcher_->ProcessPacket(server_address_, client_address, + received_packet47); + } - char packet44[kMinPacketSizeForVersionNegotiation] = { - 0xFF, 'Q', '0', '4', '4', /*connection ID length byte*/ 0x50}; - QuicReceivedPacket packet2(packet44, kMinPacketSizeForVersionNegotiation, - QuicTime::Zero()); - EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) - .Times(1); - dispatcher_->ProcessPacket(server_address_, client_address, packet2); + { + char packet45[kMinPacketSizeForVersionNegotiation] = { + 0xC0, 'Q', '0', '4', '5', /*connection ID length byte*/ 0x50}; + QuicReceivedPacket received_packet45( + packet45, kMinPacketSizeForVersionNegotiation, QuicTime::Zero()); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); + EXPECT_CALL(*time_wait_list_manager_, + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) + .Times(1); + dispatcher_->ProcessPacket(server_address_, client_address, + received_packet45); + } + + { + char packet44[kMinPacketSizeForVersionNegotiation] = { + 0xFF, 'Q', '0', '4', '4', /*connection ID length byte*/ 0x50}; + QuicReceivedPacket received_packet44( + packet44, kMinPacketSizeForVersionNegotiation, QuicTime::Zero()); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); + EXPECT_CALL(*time_wait_list_manager_, + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) + .Times(1); + dispatcher_->ProcessPacket(server_address_, client_address, + received_packet44); + } } TEST_F(QuicDispatcherTest, VersionNegotiationProbeOld) { @@ -1196,8 +1149,6 @@ TEST_F(QuicDispatcherTest, VersionNegotiationProbeEndToEnd) { TEST_F(QuicDispatcherTest, AndroidConformanceTestOld) { // TODO(b/139691956) Remove this test once the workaround is removed. - // This test requires the workaround behind this flag to pass. - SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, true); SavingWriter* saving_writer = new SavingWriter(); // dispatcher_ takes ownership of saving_writer. QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); @@ -1242,63 +1193,9 @@ TEST_F(QuicDispatcherTest, AndroidConformanceTestOld) { sizeof(connection_id_bytes)); } -TEST_F(QuicDispatcherTest, AndroidConformanceTestNewWithWorkaround) { - // TODO(b/139691956) Remove this test once the workaround is removed. - // This test doesn't need the workaround but we make sure that it passes even - // when the flag is true, also see AndroidConformanceTest below. - SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, true); - SavingWriter* saving_writer = new SavingWriter(); - // dispatcher_ takes ownership of saving_writer. - QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); - - QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager( - saving_writer, dispatcher_.get(), mock_helper_.GetClock(), - &mock_alarm_factory_); - // dispatcher_ takes ownership of time_wait_list_manager. - QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(), - time_wait_list_manager); - // clang-format off - static const unsigned char packet[1200] = { - // Android UDP network conformance test packet as it was after this change: - // https://android-review.googlesource.com/c/platform/cts/+/1104285 - 0x0d, // public flags: version, 8-byte connection ID, 1-byte packet number - 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID - 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number - 0x01, // 1-byte packet number - 0x00, // private flags - 0x07, // PING frame - }; - // clang-format on - - QuicEncryptedPacket encrypted(reinterpret_cast(packet), - sizeof(packet), false); - std::unique_ptr received_packet( - ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now())); - EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); - - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - dispatcher_->ProcessPacket(server_address_, client_address, *received_packet); - ASSERT_EQ(1u, saving_writer->packets()->size()); - - // The Android UDP network conformance test directly checks that bytes 1-9 - // of the response match the connection ID that was sent. - static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74, - 0x75, 0x76, 0x77, 0x78}; - ASSERT_GE((*(saving_writer->packets()))[0]->length(), - 1u + sizeof(connection_id_bytes)); - test::CompareCharArraysWithHexError( - "response connection ID", &(*(saving_writer->packets()))[0]->data()[1], - sizeof(connection_id_bytes), connection_id_bytes, - sizeof(connection_id_bytes)); -} - TEST_F(QuicDispatcherTest, AndroidConformanceTest) { // WARNING: do not remove or modify this test without making sure that we // still have adequate coverage for the Android conformance test. - - // Set the flag to false to make sure this test passes even when the - // workaround is disabled. - SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, false); SavingWriter* saving_writer = new SavingWriter(); // dispatcher_ takes ownership of saving_writer. QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); @@ -1345,7 +1242,6 @@ TEST_F(QuicDispatcherTest, AndroidConformanceTest) { } TEST_F(QuicDispatcherTest, DoNotProcessSmallPacket) { - SetQuicReloadableFlag(quic_donot_process_small_initial_packets, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -2161,8 +2057,8 @@ TEST_F(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { /*connection_id=*/TestConnectionId(1))); // CHLO on connection 1 should still be buffered. - ProcessPacket(client_addr_, /*connection_id=*/TestConnectionId(1), true, - SerializeFullCHLO()); + ProcessPacket(client_addr_, /*server_connection_id=*/TestConnectionId(1), + true, SerializeFullCHLO()); EXPECT_TRUE(store->HasChloForConnection( /*connection_id=*/TestConnectionId(1))); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h b/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h index fc9b45c393f..5c04e3d4cd5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h @@ -13,7 +13,7 @@ namespace quic { // Creates alarms that use the supplied EpollServer for timing and firing. -class QuicEpollAlarmFactory : public QuicAlarmFactory { +class QUIC_EXPORT_PRIVATE QuicEpollAlarmFactory : public QuicAlarmFactory { public: explicit QuicEpollAlarmFactory(QuicEpollServer* eps); QuicEpollAlarmFactory(const QuicEpollAlarmFactory&) = delete; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h b/chromium/net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h index 7041454f907..ce68cfbb756 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h @@ -27,7 +27,8 @@ class QuicRandom; enum class QuicAllocator { SIMPLE, BUFFER_POOL }; -class QuicEpollConnectionHelper : public QuicConnectionHelperInterface { +class QUIC_EXPORT_PRIVATE QuicEpollConnectionHelper + : public QuicConnectionHelperInterface { public: QuicEpollConnectionHelper(QuicEpollServer* eps, QuicAllocator allocator); QuicEpollConnectionHelper(const QuicEpollConnectionHelper&) = delete; 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 b1e8ed298f9..ae17f099a96 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 @@ -160,6 +160,11 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM); RETURN_STRING_LITERAL(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES); RETURN_STRING_LITERAL(QUIC_TRANSPORT_INVALID_CLIENT_INDICATION); + RETURN_STRING_LITERAL(QUIC_QPACK_DECOMPRESSION_FAILED); + RETURN_STRING_LITERAL(QUIC_QPACK_ENCODER_STREAM_ERROR); + RETURN_STRING_LITERAL(QUIC_QPACK_DECODER_STREAM_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET); + RETURN_STRING_LITERAL(QUIC_STREAM_MULTIPLE_OFFSET); RETURN_STRING_LITERAL(QUIC_LAST_ERROR); // Intentionally have no default case, so we'll break the build 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 ce5c7216b31..b6c2d50ca5f 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 @@ -342,8 +342,19 @@ enum QuicErrorCode { // QuicTransport received invalid client indication. QUIC_TRANSPORT_INVALID_CLIENT_INDICATION = 125, + // Internal error codes for QPACK errors. + QUIC_QPACK_DECOMPRESSION_FAILED = 126, + QUIC_QPACK_ENCODER_STREAM_ERROR = 127, + QUIC_QPACK_DECODER_STREAM_ERROR = 128, + + // Received stream data beyond close offset. + QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET = 129, + + // Received multiple close offset. + QUIC_STREAM_MULTIPLE_OFFSET = 130, + // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 126, + QUIC_LAST_ERROR = 131, }; // 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 @@ -357,7 +368,15 @@ QUIC_EXPORT_PRIVATE const char* QuicRstStreamErrorCodeToString( QuicRstStreamErrorCode error); // Returns the name of the QuicErrorCode as a char* -QUIC_EXPORT const char* QuicErrorCodeToString(QuicErrorCode error); +QUIC_EXPORT_PRIVATE const char* QuicErrorCodeToString(QuicErrorCode error); + +// Wire values for QPACK errors. +// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#error-code-registration +enum QuicHttpQpackErrorCode { + IETF_QUIC_HTTP_QPACK_DECOMPRESSION_FAILED = 0x200, + IETF_QUIC_HTTP_QPACK_ENCODER_STREAM_ERROR = 0x201, + IETF_QUIC_HTTP_QPACK_DECODER_STREAM_ERROR = 0x202 +}; QUIC_EXPORT_PRIVATE inline std::string HistogramEnumString( QuicErrorCode enum_value) { 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 2d4d4a5af82..c5708b94995 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 @@ -148,14 +148,6 @@ uint64_t ClosestTo(uint64_t target, uint64_t a, uint64_t b) { return (Delta(target, a) < Delta(target, b)) ? a : b; } -uint64_t PacketNumberIntervalLength( - const QuicInterval& interval) { - if (interval.Empty()) { - return 0u; - } - return interval.max() - interval.min(); -} - QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) { switch (flags & PACKET_FLAGS_8BYTE_PACKET) { case PACKET_FLAGS_8BYTE_PACKET: @@ -424,22 +416,12 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, expected_server_connection_id_length), expected_client_connection_id_length_(0), supports_multiple_packet_number_spaces_(false), - framer_doesnt_create_initial_encrypter_( - GetQuicReloadableFlag(quic_framer_doesnt_create_initial_encrypter)), last_written_packet_number_length_(0), peer_ack_delay_exponent_(kDefaultAckDelayExponent), local_ack_delay_exponent_(kDefaultAckDelayExponent), current_received_frame_type_(0) { DCHECK(!supported_versions.empty()); version_ = supported_versions_[0]; - if (!framer_doesnt_create_initial_encrypter_) { - decrypter_[ENCRYPTION_INITIAL] = - std::make_unique(perspective); - encrypter_[ENCRYPTION_INITIAL] = - std::make_unique(perspective); - } else { - QUIC_RELOADABLE_FLAG_COUNT(quic_framer_doesnt_create_initial_encrypter); - } } QuicFramer::~QuicFramer() {} @@ -449,7 +431,7 @@ size_t QuicFramer::GetMinStreamFrameSize(QuicTransportVersion version, QuicStreamId stream_id, QuicStreamOffset offset, bool last_frame_in_packet, - QuicPacketLength data_length) { + size_t data_length) { if (VersionHasIetfQuicFrames(version)) { return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_id) + (last_frame_in_packet @@ -564,13 +546,11 @@ size_t QuicFramer::GetWindowUpdateFrameSize( } if (frame.stream_id == QuicUtils::GetInvalidStreamId(version)) { // Frame would be a MAX DATA frame, which has only a Maximum Data field. - return kQuicFrameTypeSize + - QuicDataWriter::GetVarInt62Len(frame.byte_offset); + return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.max_data); } // Frame would be MAX STREAM DATA, has Maximum Stream Data and Stream ID // fields. - return kQuicFrameTypeSize + - QuicDataWriter::GetVarInt62Len(frame.byte_offset) + + return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.max_data) + QuicDataWriter::GetVarInt62Len(frame.stream_id); } @@ -1275,33 +1255,26 @@ std::unique_ptr QuicFramer::BuildVersionNegotiationPacket( bool use_length_prefix, const ParsedQuicVersionVector& versions) { ParsedQuicVersionVector wire_versions = versions; - if (!GetQuicReloadableFlag(quic_version_negotiation_grease)) { - if (wire_versions.empty()) { - wire_versions = {QuicVersionReservedForNegotiation()}; - } + // Add a version reserved for negotiation as suggested by the + // "Using Reserved Versions" section of draft-ietf-quic-transport. + if (wire_versions.empty()) { + // Ensure that version negotiation packets we send have at least two + // versions. This guarantees that, under all circumstances, all QUIC + // packets we send are at least 14 bytes long. + wire_versions = {QuicVersionReservedForNegotiation(), + QuicVersionReservedForNegotiation()}; } else { - // Add a version reserved for negotiation as suggested by the - // "Using Reserved Versions" section of draft-ietf-quic-transport. - QUIC_RELOADABLE_FLAG_COUNT_N(quic_version_negotiation_grease, 1, 2); - if (wire_versions.empty()) { - // Ensure that version negotiation packets we send have at least two - // versions. This guarantees that, under all circumstances, all QUIC - // packets we send are at least 14 bytes long. - wire_versions = {QuicVersionReservedForNegotiation(), - QuicVersionReservedForNegotiation()}; - } else { - // This is not uniformely distributed but is acceptable since no security - // depends on this randomness. - size_t version_index = 0; - const bool disable_randomness = - GetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness); - if (!disable_randomness) { - version_index = QuicRandom::GetInstance()->RandUint64() % - (wire_versions.size() + 1); - } - wire_versions.insert(wire_versions.begin() + version_index, - QuicVersionReservedForNegotiation()); - } + // This is not uniformely distributed but is acceptable since no security + // depends on this randomness. + size_t version_index = 0; + const bool disable_randomness = + GetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness); + if (!disable_randomness) { + version_index = + QuicRandom::GetInstance()->RandUint64() % (wire_versions.size() + 1); + } + wire_versions.insert(wire_versions.begin() + version_index, + QuicVersionReservedForNegotiation()); } if (ietf_quic) { return BuildIetfVersionNegotiationPacket( @@ -1322,7 +1295,6 @@ std::unique_ptr QuicFramer::BuildVersionNegotiationPacket( uint8_t flags = static_cast( PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID | - // TODO(rch): Remove this QUIC_VERSION_32 is retired. PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD); if (!writer.WriteUInt8(flags)) { return nullptr; @@ -1699,12 +1671,11 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, return true; } if (hp_removal_failed) { - const EncryptionLevel decryption_level = GetEncryptionLevel(*header); - const bool has_decryption_key = - decrypter_[decryption_level] != nullptr; - visitor_->OnUndecryptablePacket( - QuicEncryptedPacket(encrypted_reader->FullPayload()), - decryption_level, has_decryption_key); + const EncryptionLevel decryption_level = GetEncryptionLevel(*header); + const bool has_decryption_key = decrypter_[decryption_level] != nullptr; + visitor_->OnUndecryptablePacket( + QuicEncryptedPacket(encrypted_reader->FullPayload()), + decryption_level, has_decryption_key); set_detailed_error("Unable to decrypt header protection."); return RaiseError(QUIC_DECRYPTION_FAILURE); } @@ -1763,12 +1734,12 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, visitor_->OnAuthenticatedIetfStatelessResetPacket(packet); return true; } - const EncryptionLevel decryption_level = GetEncryptionLevel(*header); - const bool has_decryption_key = version_.KnowsWhichDecrypterToUse() && - decrypter_[decryption_level] != nullptr; - visitor_->OnUndecryptablePacket( - QuicEncryptedPacket(encrypted_reader->FullPayload()), - decryption_level, has_decryption_key); + const EncryptionLevel decryption_level = GetEncryptionLevel(*header); + const bool has_decryption_key = version_.KnowsWhichDecrypterToUse() && + decrypter_[decryption_level] != nullptr; + visitor_->OnUndecryptablePacket( + QuicEncryptedPacket(encrypted_reader->FullPayload()), decryption_level, + has_decryption_key); set_detailed_error("Unable to decrypt payload."); RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE); return RaiseError(QUIC_DECRYPTION_FAILURE); @@ -1850,13 +1821,13 @@ bool QuicFramer::ProcessDataPacket(QuicDataReader* encrypted_reader, EncryptionLevel decrypted_level; if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer, buffer_length, &decrypted_length, &decrypted_level)) { - const EncryptionLevel decryption_level = decrypter_level_; - // This version uses trial decryption so we always report to our visitor - // that we are not certain we have the correct decryption key. - const bool has_decryption_key = false; - visitor_->OnUndecryptablePacket( - QuicEncryptedPacket(encrypted_reader->FullPayload()), - decryption_level, has_decryption_key); + const EncryptionLevel decryption_level = decrypter_level_; + // This version uses trial decryption so we always report to our visitor + // that we are not certain we have the correct decryption key. + const bool has_decryption_key = false; + visitor_->OnUndecryptablePacket( + QuicEncryptedPacket(encrypted_reader->FullPayload()), decryption_level, + has_decryption_key); RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE); set_detailed_error("Unable to decrypt payload."); return RaiseError(QUIC_DECRYPTION_FAILURE); @@ -1904,7 +1875,7 @@ bool QuicFramer::ProcessPublicResetPacket(QuicDataReader* reader, std::unique_ptr reset( CryptoFramer::ParseMessage(reader->ReadRemainingPayload())); - if (!reset.get()) { + if (!reset) { set_detailed_error("Unable to read reset message."); RecordDroppedPacketReason(DroppedPacketReason::INVALID_PUBLIC_RESET_PACKET); return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET); @@ -2346,7 +2317,7 @@ QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo( new_ack_info.first_block_length = frame.packets.LastIntervalLength(); auto itr = frame.packets.rbegin(); QuicPacketNumber previous_start = itr->min(); - new_ack_info.max_block_length = PacketNumberIntervalLength(*itr); + new_ack_info.max_block_length = itr->Length(); ++itr; // Don't do any more work after getting information for 256 ACK blocks; any @@ -2359,8 +2330,8 @@ QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo( new_ack_info.num_ack_blocks += (total_gap + std::numeric_limits::max() - 1) / std::numeric_limits::max(); - new_ack_info.max_block_length = std::max( - new_ack_info.max_block_length, PacketNumberIntervalLength(interval)); + new_ack_info.max_block_length = + std::max(new_ack_info.max_block_length, interval.Length()); } return new_ack_info; } @@ -3246,12 +3217,12 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader, } break; } - case IETF_EXTENSION_MESSAGE_NO_LENGTH: + case IETF_EXTENSION_MESSAGE_NO_LENGTH_V99: QUIC_FALLTHROUGH_INTENDED; - case IETF_EXTENSION_MESSAGE: { + case IETF_EXTENSION_MESSAGE_V99: { QuicMessageFrame message_frame; if (!ProcessMessageFrame( - reader, frame_type == IETF_EXTENSION_MESSAGE_NO_LENGTH, + reader, frame_type == IETF_EXTENSION_MESSAGE_NO_LENGTH_V99, &message_frame)) { return RaiseError(QUIC_INVALID_MESSAGE_DATA); } @@ -3685,7 +3656,7 @@ bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader, return false; } - if (ack_delay_time_in_us == kVarInt62MaxValue) { + if (ack_delay_time_in_us >= (kVarInt62MaxValue >> peer_ack_delay_exponent_)) { ack_frame->ack_delay_time = QuicTime::Delta::Infinite(); } else { ack_delay_time_in_us = (ack_delay_time_in_us << peer_ack_delay_exponent_); @@ -3941,7 +3912,7 @@ bool QuicFramer::ProcessWindowUpdateFrame(QuicDataReader* reader, return false; } - if (!reader->ReadUInt64(&frame->byte_offset)) { + if (!reader->ReadUInt64(&frame->max_data)) { set_detailed_error("Unable to read window byte_offset."); return false; } @@ -5190,8 +5161,8 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, total_gap - (num_encoded_gaps - 1) * std::numeric_limits::max(); // Append the final ACK block with a non-empty size. - if (!AppendAckBlock(last_gap, ack_block_length, - PacketNumberIntervalLength(interval), writer)) { + if (!AppendAckBlock(last_gap, ack_block_length, interval.Length(), + writer)) { return false; } ++num_ack_blocks_written; @@ -5541,7 +5512,7 @@ bool QuicFramer::AppendWindowUpdateFrame(const QuicWindowUpdateFrame& frame, if (!writer->WriteUInt32(stream_id)) { return false; } - if (!writer->WriteUInt64(frame.byte_offset)) { + if (!writer->WriteUInt64(frame.max_data)) { return false; } return true; @@ -5579,8 +5550,14 @@ bool QuicFramer::AppendPaddingFrame(const QuicPaddingFrame& frame, bool QuicFramer::AppendMessageFrameAndTypeByte(const QuicMessageFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer) { - uint8_t type_byte = last_frame_in_packet ? IETF_EXTENSION_MESSAGE_NO_LENGTH - : IETF_EXTENSION_MESSAGE; + uint8_t type_byte; + if (VersionHasIetfQuicFrames(version_.transport_version)) { + type_byte = last_frame_in_packet ? IETF_EXTENSION_MESSAGE_NO_LENGTH_V99 + : IETF_EXTENSION_MESSAGE_V99; + } else { + type_byte = last_frame_in_packet ? IETF_EXTENSION_MESSAGE_NO_LENGTH + : IETF_EXTENSION_MESSAGE; + } if (!writer->WriteUInt8(type_byte)) { return false; } @@ -5840,7 +5817,7 @@ bool QuicFramer::AppendStopSendingFrame( // Append/process IETF-Format MAX_DATA Frame bool QuicFramer::AppendMaxDataFrame(const QuicWindowUpdateFrame& frame, QuicDataWriter* writer) { - if (!writer->WriteVarInt62(frame.byte_offset)) { + if (!writer->WriteVarInt62(frame.max_data)) { set_detailed_error("Can not write MAX_DATA byte-offset"); return false; } @@ -5850,7 +5827,7 @@ bool QuicFramer::AppendMaxDataFrame(const QuicWindowUpdateFrame& frame, bool QuicFramer::ProcessMaxDataFrame(QuicDataReader* reader, QuicWindowUpdateFrame* frame) { frame->stream_id = QuicUtils::GetInvalidStreamId(transport_version()); - if (!reader->ReadVarInt62(&frame->byte_offset)) { + if (!reader->ReadVarInt62(&frame->max_data)) { set_detailed_error("Can not read MAX_DATA byte-offset"); return false; } @@ -5864,7 +5841,7 @@ bool QuicFramer::AppendMaxStreamDataFrame(const QuicWindowUpdateFrame& frame, set_detailed_error("Can not write MAX_STREAM_DATA stream id"); return false; } - if (!writer->WriteVarInt62(frame.byte_offset)) { + if (!writer->WriteVarInt62(frame.max_data)) { set_detailed_error("Can not write MAX_STREAM_DATA byte-offset"); return false; } @@ -5877,7 +5854,7 @@ bool QuicFramer::ProcessMaxStreamDataFrame(QuicDataReader* reader, set_detailed_error("Can not read MAX_STREAM_DATA stream id"); return false; } - if (!reader->ReadVarInt62(&frame->byte_offset)) { + if (!reader->ReadVarInt62(&frame->max_data)) { set_detailed_error("Can not read MAX_STREAM_DATA byte-count"); return false; } @@ -6256,9 +6233,7 @@ inline bool ParseLongHeaderConnectionIds( return false; } if (!reader->ReadLengthPrefixedConnectionId(source_connection_id)) { - if (GetQuicReloadableFlag(quic_parse_prox_source_connection_id) && - version_label == kProxVersionLabel) { - QUIC_RELOADABLE_FLAG_COUNT(quic_parse_prox_source_connection_id); + if (version_label == kProxVersionLabel) { // The "PROX" version does not follow the length-prefixed invariants, // and can therefore attempt to read a payload byte and interpret it // as the source connection ID length, which could fail to parse. 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 65a0b3becb3..cd2e2c7c438 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 @@ -288,7 +288,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer { QuicStreamId stream_id, QuicStreamOffset offset, bool last_frame_in_packet, - QuicPacketLength data_length); + size_t data_length); // Returns the overhead of framing a CRYPTO frame with the specific offset and // data length provided, but not counting the size of the data payload. static size_t GetMinCryptoFrameSize(QuicStreamOffset offset, @@ -636,16 +636,12 @@ class QUIC_EXPORT_PRIVATE QuicFramer { } uint32_t peer_ack_delay_exponent() const { return peer_ack_delay_exponent_; } - bool framer_doesnt_create_initial_encrypter() const { - return framer_doesnt_create_initial_encrypter_; - } - private: friend class test::QuicFramerPeer; typedef std::map NackRangeMap; - struct AckFrameInfo { + struct QUIC_EXPORT_PRIVATE AckFrameInfo { AckFrameInfo(); AckFrameInfo(const AckFrameInfo& other); ~AckFrameInfo(); @@ -1056,10 +1052,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Indicates whether this framer supports multiple packet number spaces. bool supports_multiple_packet_number_spaces_; - // Latched value of reloadable flag - // quic_framer_doesnt_create_initial_encrypter. - const bool framer_doesnt_create_initial_encrypter_; - // The length in bytes of the last packet number written to an IETF-framed // packet. size_t last_written_packet_number_length_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc index 8aa96152875..ff9653d3827 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 @@ -365,9 +365,9 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { message_frames_.push_back( std::make_unique(frame.data, frame.message_length)); if (VersionHasIetfQuicFrames(transport_version_)) { - EXPECT_TRUE(IETF_EXTENSION_MESSAGE_NO_LENGTH == + EXPECT_TRUE(IETF_EXTENSION_MESSAGE_NO_LENGTH_V99 == framer_->current_received_frame_type() || - IETF_EXTENSION_MESSAGE == + IETF_EXTENSION_MESSAGE_V99 == framer_->current_received_frame_type()); } else { EXPECT_EQ(0u, framer_->current_received_frame_type()); @@ -929,7 +929,7 @@ TEST_P(QuicFramerTest, EmptyPacket) { char packet[] = {0x00}; QuicEncryptedPacket encrypted(packet, 0, false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); } TEST_P(QuicFramerTest, LargePacket) { @@ -977,7 +977,7 @@ TEST_P(QuicFramerTest, LargePacket) { EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); // Make sure the correct error is propagated. - EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_PACKET_TOO_LARGE)); EXPECT_EQ("Packet too large.", framer_.detailed_error()); } @@ -1006,7 +1006,7 @@ TEST_P(QuicFramerTest, PacketHeader) { AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); @@ -1032,7 +1032,7 @@ TEST_P(QuicFramerTest, PacketHeader) { &retry_token, &detailed_error); EXPECT_FALSE(retry_token_present); EXPECT_FALSE(use_length_prefix); - EXPECT_EQ(QUIC_NO_ERROR, error_code); + EXPECT_THAT(error_code, IsQuicNoError()); EXPECT_EQ(GOOGLE_QUIC_PACKET, format); EXPECT_FALSE(version_flag); EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); @@ -1071,7 +1071,7 @@ TEST_P(QuicFramerTest, LongPacketHeader) { AssemblePacketFromFragments(packet46)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); @@ -1095,7 +1095,7 @@ TEST_P(QuicFramerTest, LongPacketHeader) { &version_flag, &use_length_prefix, &version_label, &parsed_version, &destination_connection_id, &source_connection_id, &retry_token_present, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, error_code); + EXPECT_THAT(error_code, IsQuicNoError()); EXPECT_EQ("", detailed_error); EXPECT_FALSE(retry_token_present); EXPECT_FALSE(use_length_prefix); @@ -1175,7 +1175,7 @@ TEST_P(QuicFramerTest, LongPacketHeaderWithBothConnectionIds) { &version_flag, &use_length_prefix, &version_label, &parsed_version, &destination_connection_id, &source_connection_id, &retry_token_present, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, error_code); + EXPECT_THAT(error_code, IsQuicNoError()); EXPECT_FALSE(retry_token_present); EXPECT_EQ(framer_.version().HasLengthPrefixedConnectionIds(), use_length_prefix); @@ -1270,7 +1270,7 @@ TEST_P(QuicFramerTest, ParsePublicHeader) { &parsed_version, &destination_connection_id, &source_connection_id, &long_packet_type, &retry_token_length_length, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, parse_error); + EXPECT_THAT(parse_error, IsQuicNoError()); EXPECT_EQ("", detailed_error); EXPECT_EQ(p[0], first_byte); EXPECT_TRUE(version_present); @@ -1294,7 +1294,6 @@ TEST_P(QuicFramerTest, ParsePublicHeaderProxBadSourceConnectionIdLength) { if (!framer_.version().HasLengthPrefixedConnectionIds()) { return; } - SetQuicReloadableFlag(quic_parse_prox_source_connection_id, true); // clang-format off unsigned char packet[] = { // public flags (long header with packet type HANDSHAKE and @@ -1339,7 +1338,7 @@ TEST_P(QuicFramerTest, ParsePublicHeaderProxBadSourceConnectionIdLength) { &has_length_prefix, &version_label, &parsed_version, &destination_connection_id, &source_connection_id, &long_packet_type, &retry_token_length_length, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, parse_error); + EXPECT_THAT(parse_error, IsQuicNoError()); EXPECT_EQ("", detailed_error); EXPECT_EQ(p[0], first_byte); EXPECT_TRUE(version_present); @@ -1376,7 +1375,7 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) { // clang-format on QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); EXPECT_EQ("", framer_.detailed_error()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), @@ -1410,7 +1409,7 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToServer) { // clang-format on QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); EXPECT_EQ("", framer_.detailed_error()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), @@ -1464,7 +1463,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { std::unique_ptr encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->source_connection_id); EXPECT_FALSE(visitor_.header_->reset_flag); @@ -1545,7 +1544,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { std::unique_ptr encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); @@ -1607,7 +1606,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { std::unique_ptr encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); @@ -1671,10 +1670,10 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { AssemblePacketFromFragments(fragments)); if (framer_.version().HasHeaderProtection()) { EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); } else { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); } ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), @@ -1741,10 +1740,10 @@ TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) { AssemblePacketFromFragments(fragments)); if (framer_.version().HasHeaderProtection()) { EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); } else { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); } ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), @@ -1986,7 +1985,7 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(0, visitor_.frame_count_); EXPECT_EQ(1, visitor_.version_mismatch_); @@ -2090,7 +2089,7 @@ TEST_P(QuicFramerTest, PaddingFrame) { QuicEncryptedPacket encrypted(AsChars(p), p_size, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2210,7 +2209,7 @@ TEST_P(QuicFramerTest, StreamFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2265,7 +2264,7 @@ TEST_P(QuicFramerTest, EmptyStreamFrame) { AssemblePacketFromFragments(packet)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2360,14 +2359,14 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) { QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); if (framer_.version().HasHeaderProtection()) { - EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); EXPECT_EQ("Unable to decrypt header protection.", framer_.detailed_error()); } else if (framer_.transport_version() >= QUIC_VERSION_46) { // Cannot read diversification nonce. - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Unable to read nonce.", framer_.detailed_error()); } else { - EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); } } @@ -2413,7 +2412,7 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2533,7 +2532,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2653,7 +2652,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2855,7 +2854,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, kIncludeVersion, !kIncludeDiversificationNonce, @@ -2939,7 +2938,7 @@ TEST_P(QuicFramerTest, RejectPacket) { false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -2978,7 +2977,7 @@ TEST_P(QuicFramerTest, RejectPublicHeader) { false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_FALSE(visitor_.header_->packet_number.IsInitialized()); } @@ -3087,7 +3086,7 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -3580,7 +3579,7 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_ACK_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_ACK_DATA)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( @@ -3689,7 +3688,7 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -3914,7 +3913,7 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) { framer_.set_process_timestamps(true); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4126,7 +4125,7 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && version_.transport_version >= QUIC_VERSION_46) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_STOP_WAITING_DATA)); EXPECT_EQ("STOP WAITING not supported in version 44+.", framer_.detailed_error()); return; @@ -4134,7 +4133,7 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4192,7 +4191,7 @@ TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { : QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_STOP_WAITING_DATA)); EXPECT_EQ("Invalid unacked delta.", framer_.detailed_error()); } @@ -4283,7 +4282,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4394,7 +4393,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4407,8 +4406,8 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { if (VersionHasIetfQuicFrames(framer_.transport_version())) { EXPECT_EQ(0x1234u, visitor_.connection_close_frame_.transport_close_frame_type); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, - visitor_.connection_close_frame_.extracted_error_code); + EXPECT_THAT(visitor_.connection_close_frame_.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); } else { // For Google QUIC closes, the error code is copied into // extracted_error_code. @@ -4528,7 +4527,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithExtractedInfoIgnoreGCuic) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4598,7 +4597,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4660,7 +4659,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4757,7 +4756,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4830,14 +4829,14 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + 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_.window_update_frame_.stream_id); - EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); + EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.max_data); CheckFramingBoundaries(fragments, QUIC_INVALID_WINDOW_UPDATE_DATA); } @@ -4873,7 +4872,7 @@ TEST_P(QuicFramerTest, MaxDataFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -4881,7 +4880,7 @@ TEST_P(QuicFramerTest, MaxDataFrame) { EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()), visitor_.window_update_frame_.stream_id); - EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); + EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.max_data); CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_DATA_FRAME_DATA); } @@ -4920,14 +4919,14 @@ TEST_P(QuicFramerTest, MaxStreamDataFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + 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_.window_update_frame_.stream_id); - EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); + EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.max_data); CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA); } @@ -5002,7 +5001,7 @@ TEST_P(QuicFramerTest, BlockedFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -5075,7 +5074,7 @@ TEST_P(QuicFramerTest, PingFrame) { false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -5087,7 +5086,7 @@ TEST_P(QuicFramerTest, PingFrame) { } TEST_P(QuicFramerTest, MessageFrame) { - if (framer_.transport_version() <= QUIC_VERSION_43) { + if (!VersionSupportsMessageFrames(framer_.transport_version())) { return; } SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); @@ -5118,13 +5117,43 @@ TEST_P(QuicFramerTest, MessageFrame) { {{}, {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}}, }; + 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}}, + // message frame type. + {"", + { 0x31 }}, + // message length + {"Unable to read message length", + {0x07}}, + // message data + {"Unable to read message data", + {'m', 'e', 's', 's', 'a', 'g', 'e'}}, + // message frame no length. + {"", + { 0x30 }}, + // message data + {{}, + {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}}, + }; // clang-format on - std::unique_ptr encrypted( - AssemblePacketFromFragments(packet46)); + std::unique_ptr encrypted; + if (VersionHasIetfQuicFrames(framer_.transport_version())) { + encrypted = AssemblePacketFromFragments(packet99); + } else { + encrypted = AssemblePacketFromFragments(packet46); + } EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -5134,7 +5163,11 @@ TEST_P(QuicFramerTest, MessageFrame) { EXPECT_EQ(7u, visitor_.message_frames_[0]->message_length); EXPECT_EQ(8u, visitor_.message_frames_[1]->message_length); - CheckFramingBoundaries(packet46, QUIC_INVALID_MESSAGE_DATA); + if (VersionHasIetfQuicFrames(framer_.transport_version())) { + CheckFramingBoundaries(packet99, QUIC_INVALID_MESSAGE_DATA); + } else { + CheckFramingBoundaries(packet46, QUIC_INVALID_MESSAGE_DATA); + } } TEST_P(QuicFramerTest, PublicResetPacketV33) { @@ -5177,7 +5210,7 @@ TEST_P(QuicFramerTest, PublicResetPacketV33) { std::unique_ptr encrypted( AssemblePacketFromFragments(packet)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.public_reset_packet_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.public_reset_packet_->connection_id); @@ -5232,7 +5265,7 @@ TEST_P(QuicFramerTest, PublicResetPacket) { std::unique_ptr encrypted( AssemblePacketFromFragments(packet)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.public_reset_packet_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.public_reset_packet_->connection_id); @@ -5279,7 +5312,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) { QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - ASSERT_EQ(QUIC_INVALID_PUBLIC_RST_PACKET, framer_.error()); + ASSERT_THAT(framer_.error(), IsError(QUIC_INVALID_PUBLIC_RST_PACKET)); EXPECT_EQ("Unable to read reset message.", framer_.detailed_error()); } @@ -5331,7 +5364,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) { std::unique_ptr encrypted( AssemblePacketFromFragments(packet)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.public_reset_packet_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.public_reset_packet_->connection_id); @@ -5380,7 +5413,7 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacket) { // This packet cannot be decrypted because diversification nonce is missing. QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.stateless_reset_packet_.get()); EXPECT_EQ(kTestStatelessResetToken, visitor_.stateless_reset_packet_->stateless_reset_token); @@ -5423,7 +5456,7 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacketInvalidStatelessResetToken) { // This packet cannot be decrypted because diversification nonce is missing. QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); ASSERT_FALSE(visitor_.stateless_reset_packet_); } @@ -5490,7 +5523,7 @@ TEST_P(QuicFramerTest, VersionNegotiationPacketClient) { std::unique_ptr encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.version_negotiation_packet_.get()); EXPECT_EQ(1u, visitor_.version_negotiation_packet_->versions.size()); EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]); @@ -5549,7 +5582,8 @@ TEST_P(QuicFramerTest, VersionNegotiationPacketServer) { QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, framer_.error()); + EXPECT_THAT(framer_.error(), + IsError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET)); EXPECT_EQ("Server received version negotiation packet.", framer_.detailed_error()); EXPECT_FALSE(visitor_.version_negotiation_packet_.get()); @@ -5580,7 +5614,7 @@ TEST_P(QuicFramerTest, OldVersionNegotiationPacket) { std::unique_ptr encrypted( AssemblePacketFromFragments(packet)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.version_negotiation_packet_.get()); EXPECT_EQ(1u, visitor_.version_negotiation_packet_->versions.size()); EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]); @@ -5646,7 +5680,7 @@ TEST_P(QuicFramerTest, ParseIetfRetryPacket) { QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); ASSERT_TRUE(visitor_.retry_original_connection_id_.get()); @@ -5687,7 +5721,7 @@ TEST_P(QuicFramerTest, RejectIetfRetryPacketAsServer) { QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Client-initiated RETRY is invalid.", framer_.detailed_error()); } @@ -6483,7 +6517,7 @@ TEST_P(QuicFramerTest, CryptoFrame) { AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -6498,7 +6532,6 @@ TEST_P(QuicFramerTest, CryptoFrame) { } TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { - SetQuicReloadableFlag(quic_version_negotiation_grease, true); SetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness, true); // clang-format off unsigned char packet[] = { @@ -6565,7 +6598,6 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) { return; } - SetQuicReloadableFlag(quic_version_negotiation_grease, true); SetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness, true); // clang-format off @@ -8131,7 +8163,7 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { QuicWindowUpdateFrame window_update_frame; window_update_frame.stream_id = kStreamId; - window_update_frame.byte_offset = 0x1122334455667788; + window_update_frame.max_data = 0x1122334455667788; QuicFrames frames = {QuicFrame(&window_update_frame)}; @@ -8219,7 +8251,7 @@ TEST_P(QuicFramerTest, BuildMaxStreamDataPacket) { QuicWindowUpdateFrame window_update_frame; window_update_frame.stream_id = kStreamId; - window_update_frame.byte_offset = 0x1122334455667788; + window_update_frame.max_data = 0x1122334455667788; QuicFrames frames = {QuicFrame(&window_update_frame)}; @@ -8265,7 +8297,7 @@ TEST_P(QuicFramerTest, BuildMaxDataPacket) { QuicWindowUpdateFrame window_update_frame; window_update_frame.stream_id = QuicUtils::GetInvalidStreamId(framer_.transport_version()); - window_update_frame.byte_offset = 0x1122334455667788; + window_update_frame.max_data = 0x1122334455667788; QuicFrames frames = {QuicFrame(&window_update_frame)}; @@ -8442,7 +8474,7 @@ TEST_P(QuicFramerTest, BuildPingPacket) { } TEST_P(QuicFramerTest, BuildMessagePacket) { - if (framer_.transport_version() <= QUIC_VERSION_43) { + if (!VersionSupportsMessageFrames(framer_.transport_version())) { return; } QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); @@ -8487,13 +8519,13 @@ TEST_P(QuicFramerTest, BuildMessagePacket) { 0x12, 0x34, 0x56, 0x78, // frame type (IETF_MESSAGE frame) - 0x21, + 0x31, // Length 0x07, // Message Data 'm', 'e', 's', 's', 'a', 'g', 'e', // frame type (message frame no length) - 0x20, + 0x30, // Message Data 'm', 'e', 's', 's', 'a', 'g', 'e', '2' }; @@ -9205,7 +9237,7 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); } static char kTestString[] = "At least 20 characters."; @@ -9260,7 +9292,7 @@ TEST_P(QuicFramerTest, ConstructEncryptedPacket) { EXPECT_CALL(visitor, OnPacketComplete()).Times(1); EXPECT_TRUE(framer_.ProcessPacket(*packet)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); } // Verify that the packet returned by ConstructMisFramedEncryptedPacket() @@ -9278,12 +9310,10 @@ TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) { } framer_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique(framer_.perspective())); - ParsedQuicVersionVector versions; - versions.push_back(framer_.version()); std::unique_ptr packet(ConstructMisFramedEncryptedPacket( TestConnectionId(), EmptyQuicConnectionId(), false, false, kTestQuicStreamId, kTestString, CONNECTION_ID_PRESENT, - CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER, &versions, + CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER, framer_.version(), Perspective::IS_CLIENT)); MockFramerVisitor visitor; @@ -9302,7 +9332,7 @@ TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) { EXPECT_CALL(visitor, OnPacketComplete()).Times(0); EXPECT_FALSE(framer_.ProcessPacket(*packet)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_FRAME_DATA)); } TEST_P(QuicFramerTest, IetfBlockedFrame) { @@ -9336,7 +9366,7 @@ TEST_P(QuicFramerTest, IetfBlockedFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9421,7 +9451,7 @@ TEST_P(QuicFramerTest, IetfStreamBlockedFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9507,7 +9537,7 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9548,7 +9578,7 @@ TEST_P(QuicFramerTest, UniDiMaxStreamsFrame) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9590,7 +9620,7 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9631,7 +9661,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9676,7 +9706,7 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrameTooBig) { QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9715,7 +9745,7 @@ TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9754,7 +9784,7 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) { false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9793,7 +9823,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9862,7 +9892,7 @@ TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9905,7 +9935,7 @@ TEST_P(QuicFramerTest, BiDiStreamsBlockedFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9948,7 +9978,7 @@ TEST_P(QuicFramerTest, UniDiStreamsBlockedFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -9989,7 +10019,7 @@ TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10033,7 +10063,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_STREAMS_BLOCKED_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_STREAMS_BLOCKED_DATA)); EXPECT_EQ(framer_.detailed_error(), "STREAMS_BLOCKED stream count exceeds implementation limit."); } @@ -10071,7 +10101,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10293,7 +10323,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10352,7 +10382,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrameVariableLength) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10419,7 +10449,7 @@ TEST_P(QuicFramerTest, InvalidLongNewConnectionIdFrame) { std::unique_ptr encrypted( AssemblePacketFromFragments(packet99)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_NEW_CONNECTION_ID_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_NEW_CONNECTION_ID_DATA)); EXPECT_EQ("Unable to read new connection ID frame connection id.", framer_.detailed_error()); } @@ -10464,7 +10494,7 @@ TEST_P(QuicFramerTest, InvalidRetirePriorToNewConnectionIdFrame) { std::unique_ptr encrypted( AssemblePacketFromFragments(packet99)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_NEW_CONNECTION_ID_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_NEW_CONNECTION_ID_DATA)); EXPECT_EQ("Retire_prior_to > sequence_number.", framer_.detailed_error()); } @@ -10557,7 +10587,7 @@ TEST_P(QuicFramerTest, NewTokenFrame) { AssemblePacketFromFragments(packet)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10650,7 +10680,7 @@ TEST_P(QuicFramerTest, IetfStopSendingFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10736,7 +10766,7 @@ TEST_P(QuicFramerTest, IetfPathChallengeFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10819,7 +10849,7 @@ TEST_P(QuicFramerTest, IetfPathResponseFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -10981,7 +11011,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown1Byte) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); } @@ -11014,7 +11044,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown2Bytes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); } @@ -11047,7 +11077,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown4Bytes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); } @@ -11079,7 +11109,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown8Bytes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_FRAME_DATA)); EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); } @@ -11116,7 +11146,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown2Bytes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(IETF_QUIC_PROTOCOL_VIOLATION)); EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); } @@ -11149,7 +11179,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown4Bytes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(IETF_QUIC_PROTOCOL_VIOLATION)); EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); } @@ -11181,7 +11211,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown8Bytes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(IETF_QUIC_PROTOCOL_VIOLATION)); EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); } @@ -11585,7 +11615,7 @@ TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown2BytesAllTypes) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(IETF_QUIC_PROTOCOL_VIOLATION)); EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); } } @@ -11620,7 +11650,7 @@ TEST_P(QuicFramerTest, RetireConnectionIdFrame) { AssemblePacketFromFragments(packet99)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, @@ -12083,7 +12113,7 @@ TEST_P(QuicFramerTest, CoalescedPacket) { QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); ASSERT_EQ(1u, visitor_.stream_frames_.size()); @@ -12098,7 +12128,7 @@ TEST_P(QuicFramerTest, CoalescedPacket) { ASSERT_EQ(visitor_.coalesced_packets_.size(), 1u); EXPECT_TRUE(framer_.ProcessPacket(*visitor_.coalesced_packets_[0].get())); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); ASSERT_EQ(2u, visitor_.stream_frames_.size()); @@ -12197,18 +12227,18 @@ TEST_P(QuicFramerTest, UndecryptablePacketWithoutDecrypter) { // First attempt decryption without the handshake crypter. EXPECT_FALSE( framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false))); - EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); - ASSERT_EQ(1u, visitor_.undecryptable_packets_.size()); - ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size()); - ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size()); - CompareCharArraysWithHexError( - "undecryptable packet", visitor_.undecryptable_packets_[0]->data(), - visitor_.undecryptable_packets_[0]->length(), AsChars(p), p_length); - if (framer_.version().KnowsWhichDecrypterToUse()) { - EXPECT_EQ(ENCRYPTION_HANDSHAKE, - visitor_.undecryptable_decryption_levels_[0]); - } - EXPECT_FALSE(visitor_.undecryptable_has_decryption_keys_[0]); + EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); + ASSERT_EQ(1u, visitor_.undecryptable_packets_.size()); + ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size()); + ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size()); + CompareCharArraysWithHexError( + "undecryptable packet", visitor_.undecryptable_packets_[0]->data(), + visitor_.undecryptable_packets_[0]->length(), AsChars(p), p_length); + if (framer_.version().KnowsWhichDecrypterToUse()) { + EXPECT_EQ(ENCRYPTION_HANDSHAKE, + visitor_.undecryptable_decryption_levels_[0]); + } + EXPECT_FALSE(visitor_.undecryptable_has_decryption_keys_[0]); } TEST_P(QuicFramerTest, UndecryptablePacketWithDecrypter) { @@ -12299,19 +12329,19 @@ TEST_P(QuicFramerTest, UndecryptablePacketWithDecrypter) { EXPECT_FALSE( framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false))); - EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); - ASSERT_EQ(1u, visitor_.undecryptable_packets_.size()); - ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size()); - ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size()); - CompareCharArraysWithHexError( - "undecryptable packet", visitor_.undecryptable_packets_[0]->data(), - visitor_.undecryptable_packets_[0]->length(), AsChars(p), p_length); - if (framer_.version().KnowsWhichDecrypterToUse()) { - EXPECT_EQ(ENCRYPTION_HANDSHAKE, - visitor_.undecryptable_decryption_levels_[0]); - } - EXPECT_EQ(framer_.version().KnowsWhichDecrypterToUse(), - visitor_.undecryptable_has_decryption_keys_[0]); + EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); + ASSERT_EQ(1u, visitor_.undecryptable_packets_.size()); + ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size()); + ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size()); + CompareCharArraysWithHexError( + "undecryptable packet", visitor_.undecryptable_packets_[0]->data(), + visitor_.undecryptable_packets_[0]->length(), AsChars(p), p_length); + if (framer_.version().KnowsWhichDecrypterToUse()) { + EXPECT_EQ(ENCRYPTION_HANDSHAKE, + visitor_.undecryptable_decryption_levels_[0]); + } + EXPECT_EQ(framer_.version().KnowsWhichDecrypterToUse(), + visitor_.undecryptable_has_decryption_keys_[0]); } TEST_P(QuicFramerTest, UndecryptableCoalescedPacket) { @@ -12462,20 +12492,19 @@ TEST_P(QuicFramerTest, UndecryptableCoalescedPacket) { EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); - - ASSERT_EQ(1u, visitor_.undecryptable_packets_.size()); - ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size()); - ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size()); - // Make sure we only receive the first undecryptable packet and not the - // full packet including the second coalesced packet. - CompareCharArraysWithHexError("undecryptable packet", - visitor_.undecryptable_packets_[0]->data(), - visitor_.undecryptable_packets_[0]->length(), - AsChars(p), length_of_first_coalesced_packet); - EXPECT_EQ(ENCRYPTION_HANDSHAKE, - visitor_.undecryptable_decryption_levels_[0]); - EXPECT_TRUE(visitor_.undecryptable_has_decryption_keys_[0]); + EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); + + ASSERT_EQ(1u, visitor_.undecryptable_packets_.size()); + ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size()); + ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size()); + // Make sure we only receive the first undecryptable packet and not the + // full packet including the second coalesced packet. + CompareCharArraysWithHexError("undecryptable packet", + visitor_.undecryptable_packets_[0]->data(), + visitor_.undecryptable_packets_[0]->length(), + AsChars(p), length_of_first_coalesced_packet); + EXPECT_EQ(ENCRYPTION_HANDSHAKE, visitor_.undecryptable_decryption_levels_[0]); + EXPECT_TRUE(visitor_.undecryptable_has_decryption_keys_[0]); // Make sure the second coalesced packet is parsed correctly. ASSERT_EQ(visitor_.coalesced_packets_.size(), 1u); @@ -12631,7 +12660,7 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) { EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), "Server: Received mismatched coalesced header.*"); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); ASSERT_EQ(1u, visitor_.stream_frames_.size()); @@ -12737,7 +12766,7 @@ TEST_P(QuicFramerTest, InvalidCoalescedPacket) { EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), "Server: Failed to parse received coalesced header.*"); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); ASSERT_EQ(1u, visitor_.stream_frames_.size()); @@ -12835,7 +12864,7 @@ TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) { QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_INVALID_VERSION, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_VERSION)); EXPECT_EQ("Client received unexpected version.", framer_.detailed_error()); } @@ -12887,10 +12916,10 @@ TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { AssemblePacketFromFragments(fragments)); if (framer_.version().HasHeaderProtection()) { EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); } else { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); } ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(connection_id, visitor_.header_->destination_connection_id); @@ -12963,7 +12992,7 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) { QUIC_ARRAYSIZE(long_header_packet99), false))); } - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); EXPECT_FALSE( QuicFramerPeer::GetLargestDecryptedPacketNumber(&framer_, INITIAL_DATA) .IsInitialized()); @@ -12998,7 +13027,7 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) { } EXPECT_TRUE(framer_.ProcessPacket(short_header_encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); EXPECT_FALSE( QuicFramerPeer::GetLargestDecryptedPacketNumber(&framer_, INITIAL_DATA) .IsInitialized()); @@ -13033,7 +13062,7 @@ TEST_P(QuicFramerTest, IetfRetryPacketRejected) { AssemblePacketFromFragments(packet46)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); CheckFramingBoundaries(packet46, QUIC_INVALID_PACKET_HEADER); } @@ -13062,7 +13091,7 @@ TEST_P(QuicFramerTest, RetryPacketRejectedWithMultiplePacketNumberSpaces) { AssemblePacketFromFragments(packet)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); } @@ -13101,7 +13130,7 @@ TEST_P(QuicFramerTest, ProcessPublicHeaderNoVersionInferredType) { AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Invalid public header type for expected version.", framer_.detailed_error()); CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); @@ -13138,7 +13167,7 @@ TEST_P(QuicFramerTest, ProcessMismatchedHeaderVersion) { framer_.ProcessPacket(*encrypted); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Invalid public header type for expected version.", framer_.detailed_error()); CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); @@ -13229,7 +13258,7 @@ TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacketOld) { &version_present, &has_length_prefix, &version_label, &parsed_version, &destination_connection_id, &source_connection_id, &retry_token_present, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, parse_result); + EXPECT_THAT(parse_result, IsQuicNoError()); EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_present); EXPECT_FALSE(has_length_prefix); @@ -13380,7 +13409,7 @@ TEST_P(QuicFramerTest, DispatcherParseOldClientVersionNegotiationProbePacket) { &version_present, &has_length_prefix, &version_label, &parsed_version, &destination_connection_id, &source_connection_id, &retry_token_present, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, header_parse_result); + EXPECT_THAT(header_parse_result, IsQuicNoError()); EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_present); EXPECT_FALSE(has_length_prefix); @@ -13459,7 +13488,7 @@ TEST_P(QuicFramerTest, DispatcherParseClientVersionNegotiationProbePacket) { &version_present, &has_length_prefix, &version_label, &parsed_version, &destination_connection_id, &source_connection_id, &retry_token_present, &retry_token, &detailed_error); - EXPECT_EQ(QUIC_NO_ERROR, header_parse_result); + EXPECT_THAT(header_parse_result, IsQuicNoError()); EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_present); EXPECT_TRUE(has_length_prefix); @@ -13587,12 +13616,12 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) { if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( framer_.transport_version())) { EXPECT_FALSE(parse_success); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Invalid ConnectionId length.", framer_.detailed_error()); return; } EXPECT_TRUE(parse_success); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); EXPECT_EQ("", framer_.detailed_error()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), @@ -13653,19 +13682,19 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToServer) { if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( framer_.transport_version())) { EXPECT_FALSE(parse_success); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Invalid ConnectionId length.", framer_.detailed_error()); return; } if (!framer_.version().SupportsClientConnectionIds()) { EXPECT_FALSE(parse_success); - EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); EXPECT_EQ("Client connection ID not supported in this version.", framer_.detailed_error()); return; } EXPECT_TRUE(parse_success); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_THAT(framer_.error(), IsQuicNoError()); EXPECT_EQ("", framer_.detailed_error()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), @@ -13757,17 +13786,20 @@ TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) { frame.error_details = "this has no error code info in it"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("this has no error code info in it", frame.error_details); frame.error_details = "1234this does not have the colon in it"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("1234this does not have the colon in it", frame.error_details); frame.error_details = "1a234:this has a colon, but a malformed error number"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("1a234:this has a colon, but a malformed error number", frame.error_details); @@ -13779,14 +13811,16 @@ TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) { frame.error_details = "1234 :this is not good, space between last digit and colon"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("1234 :this is not good, space between last digit and colon", frame.error_details); frame.error_details = "123456789"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, - frame.extracted_error_code); // Not good, all numbers, no : + EXPECT_THAT( + frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); // Not good, all numbers, no : EXPECT_EQ("123456789", frame.error_details); frame.error_details = "1234:"; @@ -13803,23 +13837,26 @@ TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) { frame.error_details = "12345 6789:"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, - frame.extracted_error_code); // Not good + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); // Not good EXPECT_EQ("12345 6789:", frame.error_details); frame.error_details = ":no numbers, is not good"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ(":no numbers, is not good", frame.error_details); frame.error_details = "qwer:also no numbers, is not good"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("qwer:also no numbers, is not good", frame.error_details); frame.error_details = " 1234:this is not good, space before first digit"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code); + EXPECT_THAT(frame.extracted_error_code, + IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ(" 1234:this is not good, space before first digit", frame.error_details); @@ -13830,6 +13867,42 @@ TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) { EXPECT_EQ("", frame.error_details); } +// Regression test for crbug/1029636. +TEST_P(QuicFramerTest, OverlyLargeAckDelay) { + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + return; + } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); + // clang-format off + unsigned char 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_ACK frame) + 0x02, + // largest acked + kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x78, + // ack delay time. + kVarInt62EightBytes + 0x31, 0x00, 0x00, 0x00, 0xF3, 0xA0, 0x81, 0xE0, + // Nr. of additional ack blocks + kVarInt62OneByte + 0x00, + // first ack block length. + kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x77, + }; + // clang-format on + + framer_.ProcessPacket( + QuicEncryptedPacket(AsChars(packet99), QUIC_ARRAYSIZE(packet99), false)); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + // Verify ack_delay_time is set correctly. + EXPECT_EQ(QuicTime::Delta::Infinite(), + visitor_.ack_frames_[0]->ack_delay_time); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc index 90ae8b9d8d7..e4feb471131 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc @@ -247,8 +247,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { // initialize a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(packet_buffer_size, packet_buffer, - NETWORK_BYTE_ORDER); // do not really care - // about endianness. + quiche::NETWORK_BYTE_ORDER); // do not really care + // about endianness. // set up to define the source frame we wish to send. QuicStreamFrame source_stream_frame( stream_id, fin_bit, offset, xmit_packet_data, xmit_packet_data_size); @@ -259,7 +259,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { // Better have something in the packet buffer. EXPECT_NE(0u, writer.length()); // Now set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // A StreamFrame to hold the results... we know the frame type, // put it into the QuicIetfStreamFrame @@ -323,7 +324,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { // Make a writer so that the serialized packet is placed in // packet_buffer. - QuicDataWriter writer(expected_size, packet_buffer, NETWORK_BYTE_ORDER); + QuicDataWriter writer(expected_size, packet_buffer, + quiche::NETWORK_BYTE_ORDER); // Write the frame to the packet buffer. EXPECT_TRUE(QuicFramerPeer::AppendIetfAckFrameAndTypeByte( @@ -338,7 +340,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { // and what is in the buffer should be the expected size. EXPECT_EQ(expected_size, writer.length()) << "Frame is " << transmit_frame; // Now set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // read in the frame type uint8_t received_frame_type; @@ -384,7 +387,7 @@ class QuicIetfFramerTest : public QuicTestWithParam { // Make a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(packet_buffer_size, packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicPathChallengeFrame transmit_frame(0, data); @@ -396,7 +399,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { EXPECT_EQ(kQuicPathChallengeFrameSize, writer.length()); // now set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicPathChallengeFrame receive_frame; @@ -417,7 +421,7 @@ class QuicIetfFramerTest : public QuicTestWithParam { // Make a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(packet_buffer_size, packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicPathResponseFrame transmit_frame(0, data); @@ -429,7 +433,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { EXPECT_EQ(kQuicPathResponseFrameSize, writer.length()); // Set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicPathResponseFrame receive_frame; @@ -452,7 +457,7 @@ class QuicIetfFramerTest : public QuicTestWithParam { // Initialize a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(packet_buffer_size, packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicRstStreamFrame transmit_frame(static_cast(1), stream_id, error_code, final_offset); @@ -465,7 +470,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { EXPECT_LT(2u, writer.length()); EXPECT_GT(25u, writer.length()); // Now set up a reader to read in the thing in. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // A QuicRstStreamFrame to hold the results QuicRstStreamFrame receive_frame; @@ -487,7 +493,7 @@ class QuicIetfFramerTest : public QuicTestWithParam { Perspective old_perspective = framer_.perspective(); // Set up the writer and transmit QuicMaxStreamsFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); // Set the perspective of the sender. If the stream id is supposed to // be server-initiated, then the sender of the MAX_STREAMS should be @@ -512,7 +518,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { : Perspective::IS_CLIENT); // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicMaxStreamsFrame receive_frame; // Deframe it @@ -537,7 +544,7 @@ class QuicIetfFramerTest : public QuicTestWithParam { Perspective old_perspective = framer_.perspective(); // Set up the writer and transmit QuicStreamsBlockedFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); // Set the perspective of the sender. If the stream id is supposed to // be server-initiated, then the sender of the STREAMS_BLOCKED should be @@ -562,7 +569,8 @@ class QuicIetfFramerTest : public QuicTestWithParam { : Perspective::IS_SERVER); // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicStreamsBlockedFrame receive_frame; // Deframe it @@ -762,13 +770,14 @@ TEST_F(QuicIetfFramerTest, CryptoFrame) { data_producer.SaveCryptoData(ENCRYPTION_INITIAL, offset, frame_data); QuicDataWriter writer(QUIC_ARRAYSIZE(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); // Write the frame. EXPECT_TRUE(QuicFramerPeer::AppendCryptoFrame(&framer_, frame, &writer)); EXPECT_NE(0u, writer.length()); // Read it back. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicCryptoFrame read_frame; EXPECT_TRUE( QuicFramerPeer::ProcessCryptoFrame(&framer_, &reader, &read_frame)); @@ -787,7 +796,7 @@ TEST_F(QuicIetfFramerTest, ConnectionClose) { // initialize a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); std::string test_string = "Ich Bin Ein Jelly Donut?"; QuicConnectionCloseFrame sent_frame(QUIC_VERSION_99, QUIC_NO_ERROR, @@ -802,7 +811,8 @@ TEST_F(QuicIetfFramerTest, ConnectionClose) { EXPECT_NE(0u, writer.length()); // now set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // a QuicConnectionCloseFrame to hold the results. QuicConnectionCloseFrame sink_frame; @@ -812,7 +822,7 @@ TEST_F(QuicIetfFramerTest, ConnectionClose) { // Now check that received == sent EXPECT_EQ(sent_frame.quic_error_code, sink_frame.quic_error_code); - EXPECT_EQ(sink_frame.quic_error_code, QUIC_NO_ERROR); + EXPECT_THAT(sink_frame.quic_error_code, IsQuicNoError()); EXPECT_EQ(sink_frame.error_details, test_string); EXPECT_EQ(sink_frame.close_type, sent_frame.close_type); EXPECT_EQ(sent_frame.close_type, IETF_QUIC_TRANSPORT_CONNECTION_CLOSE); @@ -824,7 +834,7 @@ TEST_F(QuicIetfFramerTest, ApplicationClose) { // initialize a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); std::string test_string = "Ich Bin Ein Jelly Donut?"; QuicConnectionCloseFrame sent_frame(QUIC_VERSION_99, QUIC_LAST_ERROR, @@ -839,7 +849,8 @@ TEST_F(QuicIetfFramerTest, ApplicationClose) { EXPECT_NE(0u, writer.length()); // now set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // a QuicConnectionCloseFrame to hold the results. QuicConnectionCloseFrame sink_frame; @@ -1061,7 +1072,7 @@ TEST_F(QuicIetfFramerTest, AckFrameNoRanges) { // Make a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicAckFrame transmit_frame; transmit_frame.largest_acked = QuicPacketNumber(1); @@ -1085,7 +1096,8 @@ TEST_F(QuicIetfFramerTest, AckFrameNoRanges) { EXPECT_EQ(0, memcmp(packet, packet_buffer, writer.length())); // Now set up a reader to read in the frame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // an AckFrame to hold the results QuicAckFrame receive_frame; @@ -1150,7 +1162,7 @@ TEST_F(QuicIetfFramerTest, StopSendingFrame) { // Make a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicStopSendingFrame transmit_frame; transmit_frame.stream_id = 12345; @@ -1164,7 +1176,8 @@ TEST_F(QuicIetfFramerTest, StopSendingFrame) { EXPECT_LE(3u, writer.length()); EXPECT_GE(10u, writer.length()); - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); // A frame to hold the results QuicStopSendingFrame receive_frame; @@ -1190,7 +1203,7 @@ TEST_F(QuicIetfFramerTest, MaxDataFrame) { // Set up the writer and transmit QuicWindowUpdateFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicWindowUpdateFrame transmit_frame(0, 99, window_size); // Add the frame. @@ -1202,7 +1215,8 @@ TEST_F(QuicIetfFramerTest, MaxDataFrame) { EXPECT_GE(8u, writer.length()); // Set up reader and an empty QuicWindowUpdateFrame - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicWindowUpdateFrame receive_frame; // Deframe it @@ -1210,8 +1224,8 @@ TEST_F(QuicIetfFramerTest, MaxDataFrame) { QuicFramerPeer::ProcessMaxDataFrame(&framer_, &reader, &receive_frame)); // Now check that the received data equals the sent data. - EXPECT_EQ(transmit_frame.byte_offset, window_size); - EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); + EXPECT_EQ(transmit_frame.max_data, window_size); + EXPECT_EQ(transmit_frame.max_data, receive_frame.max_data); EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()), receive_frame.stream_id); } @@ -1231,7 +1245,7 @@ TEST_F(QuicIetfFramerTest, MaxStreamDataFrame) { // Set up the writer and transmit QuicWindowUpdateFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicWindowUpdateFrame transmit_frame(0, stream_id, window_size); // Add the frame. @@ -1243,7 +1257,8 @@ TEST_F(QuicIetfFramerTest, MaxStreamDataFrame) { EXPECT_GE(16u, writer.length()); // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicWindowUpdateFrame receive_frame; // Deframe it @@ -1251,8 +1266,8 @@ TEST_F(QuicIetfFramerTest, MaxStreamDataFrame) { &receive_frame)); // Now check that received data and sent data are equal. - EXPECT_EQ(transmit_frame.byte_offset, window_size); - EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); + EXPECT_EQ(transmit_frame.max_data, window_size); + EXPECT_EQ(transmit_frame.max_data, receive_frame.max_data); EXPECT_EQ(stream_id, receive_frame.stream_id); EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); } @@ -1286,7 +1301,7 @@ TEST_F(QuicIetfFramerTest, BlockedFrame) { // Set up the writer and transmit QuicBlockedFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicBlockedFrame transmit_frame( 0, QuicUtils::GetInvalidStreamId(framer_.transport_version()), offset); @@ -1299,7 +1314,8 @@ TEST_F(QuicIetfFramerTest, BlockedFrame) { EXPECT_GE(8u, writer.length()); // Set up reader and empty receive QuicFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicBlockedFrame receive_frame; // Deframe it @@ -1328,7 +1344,7 @@ TEST_F(QuicIetfFramerTest, StreamBlockedFrame) { // Set up the writer and transmit QuicWindowUpdateFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); QuicBlockedFrame transmit_frame(0, stream_id, offset); // Add the frame. @@ -1340,7 +1356,8 @@ TEST_F(QuicIetfFramerTest, StreamBlockedFrame) { EXPECT_GE(16u, writer.length()); // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicBlockedFrame receive_frame; // Deframe it @@ -1398,7 +1415,7 @@ TEST_F(QuicIetfFramerTest, NewConnectionIdFrame) { // Set up the writer and transmit a QuicNewConnectionIdFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); // Add the frame. EXPECT_TRUE(QuicFramerPeer::AppendNewConnectionIdFrame( @@ -1424,7 +1441,8 @@ TEST_F(QuicIetfFramerTest, NewConnectionIdFrame) { EXPECT_EQ(0, memcmp(packet_buffer, packet, sizeof(packet))); // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicNewConnectionIdFrame receive_frame; // Deframe it @@ -1449,7 +1467,7 @@ TEST_F(QuicIetfFramerTest, RetireConnectionIdFrame) { // Set up the writer and transmit QuicRetireConnectionIdFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + quiche::NETWORK_BYTE_ORDER); // Add the frame. EXPECT_TRUE(QuicFramerPeer::AppendRetireConnectionIdFrame( @@ -1466,7 +1484,8 @@ TEST_F(QuicIetfFramerTest, RetireConnectionIdFrame) { EXPECT_EQ(0, memcmp(packet_buffer, packet, sizeof(packet))); // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicDataReader reader(packet_buffer, writer.length(), + quiche::NETWORK_BYTE_ORDER); QuicRetireConnectionIdFrame receive_frame; // Deframe it diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_interval.h b/chromium/net/third_party/quiche/src/quic/core/quic_interval.h index c860e88e15e..9e87ecd051f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_interval.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_interval.h @@ -63,17 +63,19 @@ #include #include +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + namespace quic { template -class QuicInterval { +class QUIC_NO_EXPORT QuicInterval { private: // Type trait for deriving the return type for QuicInterval::Length. If // operator-() is not defined for T, then the return type is void. This makes // the signature for Length compile so that the class can be used for such T, // but code that calls Length would still generate a compilation error. template - class DiffTypeOrVoid { + class QUIC_NO_EXPORT DiffTypeOrVoid { private: template static auto f(const V* v) -> decltype(*v - *v); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_interval_set.h b/chromium/net/third_party/quiche/src/quic/core/quic_interval_set.h index 47225287120..28153c19088 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_interval_set.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_interval_set.h @@ -65,14 +65,15 @@ namespace quic { template -class QuicIntervalSet { +class QUIC_NO_EXPORT QuicIntervalSet { public: typedef QuicInterval value_type; private: - struct IntervalLess { + struct QUIC_NO_EXPORT IntervalLess { bool operator()(const value_type& a, const value_type& b) const; }; + // TODO(wub): Switch to absl::btree_set when it is available in Chromium. typedef std::set Set; public: @@ -152,6 +153,49 @@ class QuicIntervalSet { // TODO(wub): Similar to AddOptimizedForAppend, we can also have a // AddOptimizedForPrepend if there is a use case. + // Remove the first interval. + // REQUIRES: !Empty() + void PopFront() { + DCHECK(!Empty()); + intervals_.erase(intervals_.begin()); + } + + // Trim all values that is smaller than |value|. Which means + // a) If all values in an interval is smaller than |value|, the entire + // interval is removed. + // b) If some but not all values in an interval is smaller than |value|, the + // min of that interval is raised to |value|. + // Returns true if some intervals are trimmed. + bool TrimLessThan(const T& value) { + // Number of intervals that are fully or partially trimmed. + size_t num_intervals_trimmed = 0; + + while (!intervals_.empty()) { + const_iterator first_interval = intervals_.begin(); + if (first_interval->min() >= value) { + break; + } + + ++num_intervals_trimmed; + + if (first_interval->max() <= value) { + // a) Trim the entire interval. + intervals_.erase(first_interval); + continue; + } + + // b) Trim a prefix of the interval. + // + // Set does not allow in-place updates due to the potential of violating + // its ordering requirements. But increasing the min of the first interval + // will not break the ordering, hence the const_cast. + const_cast(&(*first_interval))->SetMin(value); + break; + } + + return num_intervals_trimmed != 0; + } + // Returns true if this QuicIntervalSet is empty. bool Empty() const { return intervals_.empty(); } @@ -320,7 +364,7 @@ class QuicIntervalSet { private: // Simple member-wise equality, since all intervals are non-empty. - struct NonemptyIntervalEq { + struct QUIC_NO_EXPORT NonemptyIntervalEq { bool operator()(const value_type& a, const value_type& b) const { return a.min() == b.min() && a.max() == b.max(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_interval_set_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_interval_set_test.cc index 3fb483aa82a..efa8fe7e960 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_interval_set_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_interval_set_test.cc @@ -191,6 +191,47 @@ TEST_F(QuicIntervalSetTest, AddOptimizedForAppend) { EXPECT_TRUE(Check(iset, 3, 100, 150, 199, 250, 251, 350)); } +TEST_F(QuicIntervalSetTest, PopFront) { + QuicIntervalSet iset{{100, 200}, {400, 500}, {700, 800}}; + EXPECT_TRUE(Check(iset, 3, 100, 200, 400, 500, 700, 800)); + + iset.PopFront(); + EXPECT_TRUE(Check(iset, 2, 400, 500, 700, 800)); + + iset.PopFront(); + EXPECT_TRUE(Check(iset, 1, 700, 800)); + + iset.PopFront(); + EXPECT_TRUE(iset.Empty()); +} + +TEST_F(QuicIntervalSetTest, TrimLessThan) { + QuicIntervalSet iset{{100, 200}, {400, 500}, {700, 800}}; + EXPECT_TRUE(Check(iset, 3, 100, 200, 400, 500, 700, 800)); + + EXPECT_FALSE(iset.TrimLessThan(99)); + EXPECT_FALSE(iset.TrimLessThan(100)); + EXPECT_TRUE(Check(iset, 3, 100, 200, 400, 500, 700, 800)); + + EXPECT_TRUE(iset.TrimLessThan(101)); + EXPECT_TRUE(Check(iset, 3, 101, 200, 400, 500, 700, 800)); + + EXPECT_TRUE(iset.TrimLessThan(199)); + EXPECT_TRUE(Check(iset, 3, 199, 200, 400, 500, 700, 800)); + + EXPECT_TRUE(iset.TrimLessThan(450)); + EXPECT_TRUE(Check(iset, 2, 450, 500, 700, 800)); + + EXPECT_TRUE(iset.TrimLessThan(500)); + EXPECT_TRUE(Check(iset, 1, 700, 800)); + + EXPECT_TRUE(iset.TrimLessThan(801)); + EXPECT_TRUE(iset.Empty()); + + EXPECT_FALSE(iset.TrimLessThan(900)); + EXPECT_TRUE(iset.Empty()); +} + TEST_F(QuicIntervalSetTest, QuicIntervalSetBasic) { // Test Add, Get, Contains and Find QuicIntervalSet iset; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_lru_cache.h b/chromium/net/third_party/quiche/src/quic/core/quic_lru_cache.h index b8c78c6fd58..2ec089c820c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_lru_cache.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_lru_cache.h @@ -8,6 +8,7 @@ #include #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_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" @@ -18,7 +19,7 @@ namespace quic { // Value* returned by Lookup() can be invalid if the entry is evicted by other // threads. template -class QuicLRUCache { +class QUIC_NO_EXPORT QuicLRUCache { public: explicit QuicLRUCache(size_t capacity) : capacity_(capacity) {} QuicLRUCache(const QuicLRUCache&) = delete; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.cc b/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.cc index c89b41a92b4..bbf18b6d7a6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.cc @@ -77,10 +77,8 @@ QuicPacketLength QuicConnectionMtuDiscoverer::GetUpdatedMtuProbeSize( // The next probe packet is as big as the previous one. Assuming the // previous one exceeded MTU, we need to decrease the probe packet length. max_probe_length_ = probe_packet_length; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_mtu_discovery_v2, 1, 3); } else { DCHECK_GT(probe_packet_length, last_probe_length_); - QUIC_RELOADABLE_FLAG_COUNT_N(quic_mtu_discovery_v2, 2, 3); } last_probe_length_ = next_probe_packet_length(); @@ -125,7 +123,6 @@ void QuicConnectionMtuDiscoverer::OnMaxPacketLengthUpdated( DCHECK_EQ(old_value, min_probe_length_); min_probe_length_ = new_value; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_mtu_discovery_v2, 3, 3); } std::ostream& operator<<(std::ostream& os, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h index c76a70f2f8a..41842f35963 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h @@ -20,7 +20,7 @@ namespace quic { template -class QuicOneBlockArena { +class QUIC_EXPORT_PRIVATE QuicOneBlockArena { static const uint32_t kMaxAlign = 8; public: 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 07fa4b15a5c..f95fe638ada 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 @@ -11,7 +11,9 @@ #include #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" #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" @@ -51,6 +53,38 @@ QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) { } } +// ScopedPacketContextSwitcher saves |packet|'s states and change states +// during its construction. When the switcher goes out of scope, it restores +// saved states. +class ScopedPacketContextSwitcher { + public: + ScopedPacketContextSwitcher(QuicPacketNumber packet_number, + QuicPacketNumberLength packet_number_length, + EncryptionLevel encryption_level, + SerializedPacket* packet) + + : saved_packet_number_(packet->packet_number), + saved_packet_number_length_(packet->packet_number_length), + saved_encryption_level_(packet->encryption_level), + packet_(packet) { + packet_->packet_number = packet_number, + packet_->packet_number_length = packet_number_length; + packet_->encryption_level = encryption_level; + } + + ~ScopedPacketContextSwitcher() { + packet_->packet_number = saved_packet_number_; + packet_->packet_number_length = saved_packet_number_length_; + packet_->encryption_level = saved_encryption_level_; + } + + private: + const QuicPacketNumber saved_packet_number_; + const QuicPacketNumberLength saved_packet_number_length_; + const EncryptionLevel saved_encryption_level_; + SerializedPacket* packet_; +}; + } // namespace #define ENDPOINT \ @@ -87,16 +121,11 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id, false), pending_padding_bytes_(0), needs_full_padding_(false), - can_set_transmission_type_(false), next_transmission_type_(NOT_RETRANSMISSION), flusher_attached_(false), fully_pad_crypto_handshake_packets_(true), - combine_generator_and_creator_( - GetQuicReloadableFlag(quic_combine_generator_and_creator)) { + latched_hard_max_packet_length_(0) { SetMaxPacketLength(kDefaultMaxPacketSize); - if (combine_generator_and_creator_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_combine_generator_and_creator); - } } QuicPacketCreator::~QuicPacketCreator() { @@ -130,6 +159,25 @@ void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { << "Attempted to set max packet length too small"; } +void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { + DCHECK(CanSetMaxPacketLength()); + if (length > max_packet_length_) { + QUIC_BUG << ENDPOINT + << "Try to increase max_packet_length_ in " + "SetSoftMaxPacketLength, use SetMaxPacketLength instead."; + return; + } + if (framer_->GetMaxPlaintextSize(length) < + PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) { + QUIC_DLOG(INFO) << length << " is too small to fit packet header"; + return; + } + QUIC_DVLOG(1) << "Setting soft max packet length to: " << length; + latched_hard_max_packet_length_ = max_packet_length_; + max_packet_length_ = length; + max_plaintext_size_ = framer_->GetMaxPlaintextSize(length); +} + // Stops serializing version of the protocol in packets sent after this call. // A packet that is already open might send kQuicVersionSize bytes less than the // maximum packet size if we stop sending version before it is serialized. @@ -216,8 +264,7 @@ bool QuicPacketCreator::ConsumeCryptoDataToFillCurrentPacket( if (needs_full_padding) { needs_full_padding_ = true; } - return AddFrame(*frame, /*save_retransmittable_frames*/ true, - transmission_type); + return AddFrame(*frame, transmission_type); } bool QuicPacketCreator::ConsumeDataToFillCurrentPacket( @@ -244,8 +291,7 @@ bool QuicPacketCreator::ConsumeDataToFillCurrentPacket( delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details); return false; } - if (!AddFrame(*frame, /*save_retransmittable_frames=*/true, - transmission_type)) { + if (!AddFrame(*frame, transmission_type)) { // Fails if we try to write unencrypted stream data. return false; } @@ -259,14 +305,28 @@ bool QuicPacketCreator::ConsumeDataToFillCurrentPacket( bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset, size_t data_size) { - return BytesFree() > - QuicFramer::GetMinStreamFrameSize(framer_->transport_version(), id, - offset, true, data_size); + const size_t min_stream_frame_size = QuicFramer::GetMinStreamFrameSize( + framer_->transport_version(), id, offset, /*last_frame_in_packet=*/true, + data_size); + if (BytesFree() > min_stream_frame_size) { + return true; + } + if (!RemoveSoftMaxPacketLength()) { + return false; + } + return BytesFree() > min_stream_frame_size; } bool QuicPacketCreator::HasRoomForMessageFrame(QuicByteCount length) { - return BytesFree() >= QuicFramer::GetMessageFrameSize( - framer_->transport_version(), true, length); + const size_t message_frame_size = QuicFramer::GetMessageFrameSize( + framer_->transport_version(), /*last_frame_in_packet=*/true, length); + if (BytesFree() >= message_frame_size) { + return true; + } + if (!RemoveSoftMaxPacketLength()) { + return false; + } + return BytesFree() >= message_frame_size; } // TODO(fkastenholz): this method should not use constant values for @@ -352,7 +412,8 @@ bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level, QuicFrame* frame) { size_t min_frame_size = QuicFramer::GetMinCryptoFrameSize(write_length, offset); - if (BytesFree() <= min_frame_size) { + if (BytesFree() <= min_frame_size && + (!RemoveSoftMaxPacketLength() || BytesFree() <= min_frame_size)) { return false; } size_t max_write_length = BytesFree() - min_frame_size; @@ -361,49 +422,6 @@ bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level, return true; } -void QuicPacketCreator::ReserializeAllFrames( - const QuicPendingRetransmission& retransmission, - char* buffer, - size_t buffer_len) { - DCHECK(queued_frames_.empty()); - DCHECK_EQ(0, packet_.num_padding_bytes); - QUIC_BUG_IF(retransmission.retransmittable_frames.empty()) - << "Attempt to serialize empty packet"; - const EncryptionLevel default_encryption_level = packet_.encryption_level; - - // Temporarily set the packet number length and change the encryption level. - packet_.packet_number_length = retransmission.packet_number_length; - if (retransmission.num_padding_bytes == -1) { - // Only retransmit padding when original packet needs full padding. Padding - // from pending_padding_bytes_ are not retransmitted. - needs_full_padding_ = true; - } - // Only preserve the original encryption level if it's a handshake packet or - // if we haven't gone forward secure. - if (retransmission.has_crypto_handshake || - packet_.encryption_level != ENCRYPTION_FORWARD_SECURE) { - packet_.encryption_level = retransmission.encryption_level; - } - - // Serialize the packet and restore packet number length state. - for (const QuicFrame& frame : retransmission.retransmittable_frames) { - bool success = AddFrame(frame, false, retransmission.transmission_type); - QUIC_BUG_IF(!success) << " Failed to add frame of type:" << frame.type - << " num_frames:" - << retransmission.retransmittable_frames.size() - << " retransmission.packet_number_length:" - << retransmission.packet_number_length - << " packet_.packet_number_length:" - << packet_.packet_number_length; - } - packet_.transmission_type = retransmission.transmission_type; - SerializePacket(buffer, buffer_len); - packet_.original_packet_number = retransmission.packet_number; - OnSerializedPacket(); - // Restore old values. - packet_.encryption_level = default_encryption_level; -} - void QuicPacketCreator::FlushCurrentPacket() { if (!HasPendingFrames() && pending_padding_bytes_ == 0) { return; @@ -430,6 +448,7 @@ void QuicPacketCreator::OnSerializedPacket() { SerializedPacket packet(std::move(packet_)); ClearPacket(); + RemoveSoftMaxPacketLength(); delegate_->OnSerializedPacket(&packet); } @@ -438,15 +457,62 @@ void QuicPacketCreator::ClearPacket() { packet_.has_stop_waiting = false; packet_.has_crypto_handshake = NOT_HANDSHAKE; packet_.num_padding_bytes = 0; - packet_.original_packet_number.Clear(); packet_.transmission_type = NOT_RETRANSMISSION; packet_.encrypted_buffer = nullptr; packet_.encrypted_length = 0; DCHECK(packet_.retransmittable_frames.empty()); + DCHECK(packet_.nonretransmittable_frames.empty()); packet_.largest_acked.Clear(); needs_full_padding_ = false; } +size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( + const SerializedPacket& packet, + size_t padding_size, + char* buffer, + size_t buffer_len) { + QUIC_BUG_IF(packet.encryption_level != ENCRYPTION_INITIAL); + QUIC_BUG_IF(packet.nonretransmittable_frames.empty() && + packet.retransmittable_frames.empty()) + << "Attempt to serialize empty ENCRYPTION_INITIAL packet in coalesced " + "packet"; + ScopedPacketContextSwitcher switcher( + packet.packet_number - + 1, // -1 because serialize packet increase packet number. + packet.packet_number_length, packet.encryption_level, &packet_); + for (const QuicFrame& frame : packet.nonretransmittable_frames) { + if (!AddFrame(frame, packet.transmission_type)) { + QUIC_BUG << "Failed to serialize frame: " << frame; + return 0; + } + } + for (const QuicFrame& frame : packet.retransmittable_frames) { + if (!AddFrame(frame, packet.transmission_type)) { + QUIC_BUG << "Failed to serialize frame: " << frame; + return 0; + } + } + // Add necessary padding. + if (padding_size > 0) { + QUIC_DVLOG(2) << ENDPOINT << "Add padding of size: " << padding_size; + if (!AddFrame(QuicFrame(QuicPaddingFrame(padding_size)), + packet.transmission_type)) { + QUIC_BUG << "Failed to add padding of size " << padding_size + << " when serializing ENCRYPTION_INITIAL " + "packet in coalesced packet"; + return 0; + } + } + SerializePacket(buffer, buffer_len); + const size_t encrypted_length = packet_.encrypted_length; + // Clear frames in packet_. No need to DeleteFrames since frames are owned by + // initial_packet. + packet_.retransmittable_frames.clear(); + packet_.nonretransmittable_frames.clear(); + ClearPacket(); + return encrypted_length; +} + void QuicPacketCreator::CreateAndSerializeStreamFrame( QuicStreamId id, size_t write_length, @@ -530,9 +596,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( return; } - if (can_set_transmission_type()) { - packet_.transmission_type = transmission_type; - } + packet_.transmission_type = transmission_type; size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, @@ -606,17 +670,10 @@ size_t QuicPacketCreator::PacketSize() { return packet_size_; } -bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame, - TransmissionType transmission_type) { - return AddFrame(frame, /*save_retransmittable_frames=*/true, - transmission_type); -} - bool QuicPacketCreator::AddPaddedSavedFrame( const QuicFrame& frame, TransmissionType transmission_type) { - if (AddFrame(frame, /*save_retransmittable_frames=*/true, - transmission_type)) { + if (AddFrame(frame, transmission_type)) { needs_full_padding_ = true; return true; } @@ -635,7 +692,8 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, MaybeAddPadding(); QUIC_DVLOG(2) << ENDPOINT << "Serializing packet " << header - << QuicFramesToString(queued_frames_); + << QuicFramesToString(queued_frames_) << " at encryption_level " + << EncryptionLevelToString(packet_.encryption_level); DCHECK_GE(max_plaintext_size_, packet_size_); // Use the packet_size_ instead of the buffer size to ensure smaller @@ -694,6 +752,7 @@ OwningSerializedPacketPointer QuicPacketCreator::SerializeConnectivityProbingPacket() { QUIC_BUG_IF(VersionHasIetfQuicFrames(framer_->transport_version())) << "Must not be version 99 to serialize padded ping connectivity probe"; + RemoveSoftMaxPacketLength(); QuicPacketHeader header; // FillPacketHeader increments packet_number_. FillPacketHeader(&header); @@ -729,6 +788,7 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( << "Must be version 99 to serialize path challenge connectivity probe, " "is version " << framer_->transport_version(); + RemoveSoftMaxPacketLength(); QuicPacketHeader header; // FillPacketHeader increments packet_number_. FillPacketHeader(&header); @@ -765,6 +825,7 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket( << "Must be version 99 to serialize path response connectivity probe, is " "version " << framer_->transport_version(); + RemoveSoftMaxPacketLength(); QuicPacketHeader header; // FillPacketHeader increments packet_number_. FillPacketHeader(&header); @@ -879,6 +940,44 @@ size_t QuicPacketCreator::BuildConnectivityProbingPacket( return framer_->BuildDataPacket(header, frames, buffer, packet_length, level); } +size_t QuicPacketCreator::SerializeCoalescedPacket( + const QuicCoalescedPacket& coalesced, + char* buffer, + size_t buffer_len) { + QUIC_BUG_IF(packet_.num_padding_bytes != 0); + if (HasPendingFrames()) { + QUIC_BUG << "Try to serialize coalesced packet with pending frames"; + return 0; + } + RemoveSoftMaxPacketLength(); + QUIC_BUG_IF(coalesced.length() == 0) + << "Attempt to serialize empty coalesced packet"; + size_t packet_length = 0; + if (coalesced.initial_packet() != nullptr) { + size_t initial_length = ReserializeInitialPacketInCoalescedPacket( + *coalesced.initial_packet(), + /*padding_size=*/coalesced.max_packet_length() - coalesced.length(), + buffer, buffer_len); + if (initial_length == 0) { + QUIC_BUG << "Failed to reserialize ENCRYPTION_INITIAL packet in " + "coalesced packet"; + return 0; + } + buffer += initial_length; + buffer_len -= initial_length; + packet_length += initial_length; + } + size_t length_copied = 0; + if (!coalesced.CopyEncryptedBuffers(buffer, buffer_len, &length_copied)) { + return 0; + } + packet_length += length_copied; + QUIC_DVLOG(1) << ENDPOINT + << "Successfully serialized coalesced packet of length: " + << packet_length; + return packet_length; +} + // TODO(b/74062209): Make this a public method of framer? SerializedPacket QuicPacketCreator::NoPacket() { return SerializedPacket(QuicPacketNumber(), PACKET_1BYTE_PACKET_NUMBER, @@ -985,13 +1084,12 @@ void QuicPacketCreator::SetRetryToken(QuicStringPiece retry_token) { bool QuicPacketCreator::ConsumeRetransmittableControlFrame( const QuicFrame& frame) { - DCHECK(combine_generator_and_creator_); QUIC_BUG_IF(IsControlFrame(frame.type) && !GetControlFrameId(frame)) << "Adding a control frame with no control frame id: " << frame; DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) << frame; MaybeBundleAckOpportunistically(); if (HasPendingFrames()) { - if (AddSavedFrame(frame, next_transmission_type_)) { + if (AddFrame(frame, next_transmission_type_)) { // There is pending frames and current frame fits. return true; } @@ -1003,7 +1101,7 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame( // Do not check congestion window for ping or connection close frames. return false; } - const bool success = AddSavedFrame(frame, next_transmission_type_); + const bool success = AddFrame(frame, next_transmission_type_); QUIC_BUG_IF(!success) << "Failed to add frame:" << frame << " transmission_type:" << next_transmission_type_; return success; @@ -1013,7 +1111,6 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, size_t write_length, QuicStreamOffset offset, StreamSendingState state) { - DCHECK(combine_generator_and_creator_); QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write stream data."; bool has_handshake = QuicUtils::IsCryptoStreamId(transport_version(), id); @@ -1042,7 +1139,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, // the slow path loop. bool run_fast_path = !has_handshake && state != FIN_AND_PADDING && !HasPendingFrames() && - write_length - total_bytes_consumed > kMaxOutgoingPacketSize; + write_length - total_bytes_consumed > kMaxOutgoingPacketSize && + latched_hard_max_packet_length_ == 0; while (!run_fast_path && delegate_->ShouldGeneratePacket( HAS_RETRANSMITTABLE_DATA, @@ -1081,7 +1179,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, run_fast_path = !has_handshake && state != FIN_AND_PADDING && !HasPendingFrames() && - write_length - total_bytes_consumed > kMaxOutgoingPacketSize; + write_length - total_bytes_consumed > kMaxOutgoingPacketSize && + latched_hard_max_packet_length_ == 0; } if (run_fast_path) { @@ -1103,7 +1202,6 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( QuicStreamOffset offset, bool fin, size_t total_bytes_consumed) { - DCHECK(combine_generator_and_creator_); DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); while (total_bytes_consumed < write_length && @@ -1114,6 +1212,19 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( CreateAndSerializeStreamFrame(id, write_length, total_bytes_consumed, offset + total_bytes_consumed, fin, next_transmission_type_, &bytes_consumed); + if (GetQuicReloadableFlag( + quic_close_connection_on_failed_consume_data_fast_path)) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_close_connection_on_failed_consume_data_fast_path); + if (bytes_consumed == 0) { + const std::string error_details = + "Failed in CreateAndSerializeStreamFrame."; + QUIC_BUG << error_details; + delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, + error_details); + break; + } + } total_bytes_consumed += bytes_consumed; } @@ -1124,7 +1235,6 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset) { - DCHECK(combine_generator_and_creator_); QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write crypto data."; MaybeBundleAckOpportunistically(); @@ -1162,7 +1272,6 @@ size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, } void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { - DCHECK(combine_generator_and_creator_); // MTU discovery frames must be sent by themselves. if (!CanSetMaxPacketLength()) { QUIC_BUG << "MTU discovery packets should only be sent when no other " @@ -1190,7 +1299,6 @@ void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { } void QuicPacketCreator::MaybeBundleAckOpportunistically() { - DCHECK(combine_generator_and_creator_); if (has_ack()) { // Ack already queued, nothing to do. return; @@ -1206,13 +1314,12 @@ void QuicPacketCreator::MaybeBundleAckOpportunistically() { } bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) { - DCHECK(combine_generator_and_creator_); QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to send ACK frame."; for (const auto& frame : frames) { DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME); if (HasPendingFrames()) { - if (AddSavedFrame(frame, next_transmission_type_)) { + if (AddFrame(frame, next_transmission_type_)) { // There is pending frames and current frame fits. continue; } @@ -1224,19 +1331,17 @@ bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) { NOT_HANDSHAKE)) { return false; } - const bool success = AddSavedFrame(frame, next_transmission_type_); + const bool success = AddFrame(frame, next_transmission_type_); QUIC_BUG_IF(!success) << "Failed to flush " << frame; } return true; } void QuicPacketCreator::AddRandomPadding() { - DCHECK(combine_generator_and_creator_); AddPendingPadding(random_->RandUint64() % kMaxNumRandomPaddingBytes + 1); } void QuicPacketCreator::AttachPacketFlusher() { - DCHECK(combine_generator_and_creator_); flusher_attached_ = true; if (!write_start_packet_number_.IsInitialized()) { write_start_packet_number_ = NextSendingPacketNumber(); @@ -1244,7 +1349,6 @@ void QuicPacketCreator::AttachPacketFlusher() { } void QuicPacketCreator::Flush() { - DCHECK(combine_generator_and_creator_); FlushCurrentPacket(); SendRemainingPendingPadding(); flusher_attached_ = false; @@ -1262,7 +1366,6 @@ void QuicPacketCreator::Flush() { } void QuicPacketCreator::SendRemainingPendingPadding() { - DCHECK(combine_generator_and_creator_); while ( pending_padding_bytes() > 0 && !HasPendingFrames() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) { @@ -1271,7 +1374,6 @@ void QuicPacketCreator::SendRemainingPendingPadding() { } void QuicPacketCreator::SetServerConnectionIdLength(uint32_t length) { - DCHECK(combine_generator_and_creator_); if (length == 0) { SetServerConnectionIdIncluded(CONNECTION_ID_ABSENT); } else { @@ -1280,16 +1382,11 @@ void QuicPacketCreator::SetServerConnectionIdLength(uint32_t length) { } void QuicPacketCreator::SetTransmissionType(TransmissionType type) { - DCHECK(combine_generator_and_creator_); - SetTransmissionTypeOfNextPackets(type); - if (can_set_transmission_type()) { - next_transmission_type_ = type; - } + next_transmission_type_ = type; } MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id, QuicMemSliceSpan message) { - DCHECK(combine_generator_and_creator_); QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to add message frame."; MaybeBundleAckOpportunistically(); @@ -1301,7 +1398,7 @@ MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id, FlushCurrentPacket(); } QuicMessageFrame* frame = new QuicMessageFrame(message_id, message); - const bool success = AddSavedFrame(QuicFrame(frame), next_transmission_type_); + const bool success = AddFrame(QuicFrame(frame), next_transmission_type_); if (!success) { QUIC_BUG << "Failed to send message " << message_id; delete frame; @@ -1352,7 +1449,6 @@ void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { } bool QuicPacketCreator::AddFrame(const QuicFrame& frame, - bool save_retransmittable_frames, TransmissionType transmission_type) { QUIC_DVLOG(1) << ENDPOINT << "Adding frame with transmission type " << TransmissionTypeToString(transmission_type) << ": " << frame; @@ -1369,9 +1465,23 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details); return false; } + + if (GetQuicRestartFlag(quic_coalesce_stream_frames_2) && + frame.type == STREAM_FRAME && + MaybeCoalesceStreamFrame(frame.stream_frame)) { + QUIC_RESTART_FLAG_COUNT_N(quic_coalesce_stream_frames_2, 1, 3); + return true; + } + size_t frame_len = framer_->GetSerializedFrameLength( frame, BytesFree(), queued_frames_.empty(), /* last_frame_in_packet= */ true, GetPacketNumberLength()); + if (frame_len == 0 && RemoveSoftMaxPacketLength()) { + // Remove soft max_packet_length and retry. + frame_len = framer_->GetSerializedFrameLength( + frame, BytesFree(), queued_frames_.empty(), + /* last_frame_in_packet= */ true, GetPacketNumberLength()); + } if (frame_len == 0) { // Current open packet is full. FlushCurrentPacket(); @@ -1381,14 +1491,22 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, packet_size_ += ExpansionOnNewFrame() + frame_len; - if (save_retransmittable_frames && - QuicUtils::IsRetransmittableFrame(frame.type)) { + if (QuicUtils::IsRetransmittableFrame(frame.type)) { packet_.retransmittable_frames.push_back(frame); queued_frames_.push_back(frame); if (QuicUtils::IsHandshakeFrame(frame, framer_->transport_version())) { packet_.has_crypto_handshake = IS_HANDSHAKE; } } else { + if (frame.type == PADDING_FRAME && + frame.padding_frame.num_padding_bytes == -1) { + // Populate the actual length of full padding frame, such that one can + // know how much padding is actually added. + packet_.nonretransmittable_frames.push_back( + QuicFrame(QuicPaddingFrame(frame_len))); + } else { + packet_.nonretransmittable_frames.push_back(frame); + } queued_frames_.push_back(frame); } @@ -1405,13 +1523,57 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, // Packet transmission type is determined by the last added retransmittable // frame. - if (can_set_transmission_type() && - QuicUtils::IsRetransmittableFrame(frame.type)) { + if (QuicUtils::IsRetransmittableFrame(frame.type)) { packet_.transmission_type = transmission_type; } return true; } +bool QuicPacketCreator::MaybeCoalesceStreamFrame(const QuicStreamFrame& frame) { + if (queued_frames_.empty() || queued_frames_.back().type != STREAM_FRAME) { + return false; + } + QuicStreamFrame* candidate = &queued_frames_.back().stream_frame; + if (candidate->stream_id != frame.stream_id || + candidate->offset + candidate->data_length != frame.offset || + frame.data_length > BytesFree()) { + return false; + } + candidate->data_length += frame.data_length; + candidate->fin = frame.fin; + + // The back of retransmittable frames must be the same as the original + // queued frames' back. + DCHECK_EQ(packet_.retransmittable_frames.back().type, STREAM_FRAME); + QuicStreamFrame* retransmittable = + &packet_.retransmittable_frames.back().stream_frame; + DCHECK_EQ(retransmittable->stream_id, frame.stream_id); + DCHECK_EQ(retransmittable->offset + retransmittable->data_length, + frame.offset); + retransmittable->data_length = candidate->data_length; + retransmittable->fin = candidate->fin; + packet_size_ += frame.data_length; + if (debug_delegate_ != nullptr) { + debug_delegate_->OnStreamFrameCoalesced(*candidate); + } + return true; +} + +bool QuicPacketCreator::RemoveSoftMaxPacketLength() { + if (latched_hard_max_packet_length_ == 0) { + return false; + } + if (!CanSetMaxPacketLength()) { + return false; + } + QUIC_DVLOG(1) << "Restoring max packet length to: " + << latched_hard_max_packet_length_; + SetMaxPacketLength(latched_hard_max_packet_length_); + // Reset latched_max_packet_length_. + latched_hard_max_packet_length_ = 0; + return true; +} + void QuicPacketCreator::MaybeAddPadding() { // The current packet should have no padding bytes because padding is only // added when this method is called just before the packet is serialized. @@ -1425,6 +1587,25 @@ void QuicPacketCreator::MaybeAddPadding() { needs_full_padding_ = true; } + // 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; + } + } + // Header protection requires a minimum plaintext packet size. size_t extra_padding_bytes = 0; if (framer_->version().HasHeaderProtection()) { @@ -1456,7 +1637,7 @@ void QuicPacketCreator::MaybeAddPadding() { std::max(packet_.num_padding_bytes, extra_padding_bytes); } - bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)), false, + bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)), packet_.transmission_type); QUIC_BUG_IF(!success) << "Failed to add padding_bytes: " << padding_bytes << " transmission_type: " @@ -1511,19 +1692,6 @@ void QuicPacketCreator::SetClientConnectionId( client_connection_id_ = client_connection_id; } -void QuicPacketCreator::SetTransmissionTypeOfNextPackets( - TransmissionType type) { - DCHECK(can_set_transmission_type_); - - if (!can_set_transmission_type()) { - QUIC_DVLOG_IF(1, type != packet_.transmission_type) - << ENDPOINT << "Setting Transmission type to " - << TransmissionTypeToString(type); - - packet_.transmission_type = type; - } -} - QuicPacketLength QuicPacketCreator::GetCurrentLargestMessagePayload() const { if (!VersionSupportsMessageFrames(framer_->transport_version())) { return 0; @@ -1536,8 +1704,12 @@ QuicPacketLength QuicPacketCreator::GetCurrentLargestMessagePayload() const { VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, GetLengthLength()); // This is the largest possible message payload when the length field is // omitted. - return max_plaintext_size_ - - std::min(max_plaintext_size_, packet_header_size + kQuicFrameTypeSize); + size_t max_plaintext_size = + latched_hard_max_packet_length_ == 0 + ? max_plaintext_size_ + : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_); + return max_plaintext_size - + std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize); } QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const { @@ -1566,9 +1738,13 @@ QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const { VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, length_length); // This is the largest possible message payload when the length field is // omitted. + size_t max_plaintext_size = + latched_hard_max_packet_length_ == 0 + ? max_plaintext_size_ + : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_); const QuicPacketLength largest_payload = - max_plaintext_size_ - - std::min(max_plaintext_size_, packet_header_size + kQuicFrameTypeSize); + max_plaintext_size - + std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize); // This must always be less than or equal to GetCurrentLargestMessagePayload. DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload()); return largest_payload; @@ -1615,7 +1791,6 @@ QuicPacketNumber QuicPacketCreator::NextSendingPacketNumber() const { } bool QuicPacketCreator::PacketFlusherAttached() const { - DCHECK(combine_generator_and_creator_); return flusher_attached_; } 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 f202af0cc47..eb7b6274af3 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 @@ -2,8 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Accumulates frames for the next packet until more frames no longer fit or -// it's time to create a packet from them. +// Responsible for creating packets on behalf of a QuicConnection. +// Packets are serialized just-in-time. Stream data and control frames will be +// requested from the Connection just-in-time. Frames are accumulated into +// "current" packet until no more frames can fit, then current packet gets +// serialized and passed to connection via OnSerializedPacket(). +// +// Whether a packet should be serialized is determined by whether delegate is +// writable. If the Delegate is not writable, then no operations will cause +// a packet to be serialized. #ifndef QUICHE_QUIC_CORE_QUIC_PACKET_CREATOR_H_ #define QUICHE_QUIC_CORE_QUIC_PACKET_CREATOR_H_ @@ -13,9 +20,10 @@ #include #include +#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_coalesced_packet.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -60,6 +68,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Called when a frame has been added to the current packet. virtual void OnFrameAddedToPacket(const QuicFrame& /*frame*/) {} + + // Called when a stream frame is coalesced with an existing stream frame. + // |frame| is the new stream frame. + virtual void OnStreamFrameCoalesced(const QuicStreamFrame& /*frame*/) {} }; QuicPacketCreator(QuicConnectionId server_connection_id, @@ -137,12 +149,6 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // |length|. bool HasRoomForMessageFrame(QuicByteCount length); - // Re-serializes frames with the original packet's packet number length. - // Used for retransmitting packets to ensure they aren't too long. - void ReserializeAllFrames(const QuicPendingRetransmission& retransmission, - char* buffer, - size_t buffer_len); - // Serializes all added frames into a single packet and invokes the delegate_ // to further process the SerializedPacket. void FlushCurrentPacket(); @@ -189,8 +195,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // 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 // packet and returns false. - bool AddSavedFrame(const QuicFrame& frame, - TransmissionType transmission_type); + bool AddFrame(const QuicFrame& frame, TransmissionType transmission_type); // Identical to AddSavedFrame, but allows the frame to be padded. bool AddPaddedSavedFrame(const QuicFrame& frame, @@ -271,13 +276,15 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Sets the maximum packet length. void SetMaxPacketLength(QuicByteCount length); + // Set a soft maximum packet length in the creator. If a packet cannot be + // successfully created, creator will remove the soft limit and use the actual + // max packet length. + void SetSoftMaxPacketLength(QuicByteCount length); + // Increases pending_padding_bytes by |size|. Pending padding will be sent by // MaybeAddPadding(). void AddPendingPadding(QuicByteCount size); - // Sets transmission type of next constructed packets. - void SetTransmissionTypeOfNextPackets(TransmissionType type); - // Sets the retry token to be sent over the wire in IETF Initial packets. void SetRetryToken(QuicStringPiece retry_token); @@ -363,12 +370,6 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { debug_delegate_ = debug_delegate; } - void set_can_set_transmission_type(bool can_set_transmission_type) { - can_set_transmission_type_ = can_set_transmission_type; - } - - bool can_set_transmission_type() const { return can_set_transmission_type_; } - QuicByteCount pending_padding_bytes() const { return pending_padding_bytes_; } QuicTransportVersion transport_version() const { @@ -382,19 +383,13 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { bool PacketFlusherAttached() const; void set_fully_pad_crypto_handshake_packets(bool new_value) { - DCHECK(combine_generator_and_creator_); fully_pad_crypto_handshake_packets_ = new_value; } bool fully_pad_crypto_handshake_packets() const { - DCHECK(combine_generator_and_creator_); return fully_pad_crypto_handshake_packets_; } - bool combine_generator_and_creator() const { - return combine_generator_and_creator_; - } - // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also // fills the packet with padding. size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header, @@ -422,6 +417,12 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { size_t packet_length, EncryptionLevel level); + // Serializes |coalesced| to provided |buffer|, returns coalesced packet + // length if serialization succeeds. Otherwise, returns 0. + size_t SerializeCoalescedPacket(const QuicCoalescedPacket& coalesced, + char* buffer, + size_t buffer_len); + private: friend class test::QuicPacketCreatorPeer; @@ -444,13 +445,6 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { void FillPacketHeader(QuicPacketHeader* header); - // Adds a |frame| if there is space and returns false and flushes all pending - // frames if there isn't room. If |save_retransmittable_frames| is true, - // saves the |frame| in the next SerializedPacket. - bool AddFrame(const QuicFrame& frame, - bool save_retransmittable_frames, - TransmissionType transmission_type); - // Adds a padding frame to the current packet (if there is space) when (1) // current packet needs full padding or (2) there are pending paddings. void MaybeAddPadding(); @@ -468,6 +462,27 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Clears all fields of packet_ that should be cleared between serializations. void ClearPacket(); + // Re-serialzes frames of ENCRYPTION_INITIAL packet in coalesced packet with + // the original packet's packet number and packet number length. + // |padding_size| indicates the size of necessary padding. Returns 0 if + // serialization fails. + size_t ReserializeInitialPacketInCoalescedPacket( + const SerializedPacket& packet, + size_t padding_size, + char* buffer, + size_t buffer_len); + + // Tries to coalesce |frame| with the back of |queued_frames_|. + // Returns true on success. + bool MaybeCoalesceStreamFrame(const QuicStreamFrame& frame); + + // Called to remove the soft max_packet_length and restores + // latched_hard_max_packet_length_ if the packet cannot accommodate a single + // frame. Returns true if the soft limit is successfully removed. Returns + // false if either there is no current soft limit or there are queued frames + // (such that the packet length cannot be changed). + bool RemoveSoftMaxPacketLength(); + // Returns true if a diversification nonce should be included in the current // packet's header. bool IncludeNonceInPublicHeader() const; @@ -553,10 +568,6 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // bytes. bool needs_full_padding_; - // If true, packet_'s transmission type is only set by - // SetPacketTransmissionType and does not get cleared in ClearPacket. - bool can_set_transmission_type_; - // Transmission type of the next serialized packet. TransmissionType next_transmission_type_; @@ -571,8 +582,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // flusher detaches. QuicPacketNumber write_start_packet_number_; - // Latched value of quic_combine_generator_and_creator. - const bool combine_generator_and_creator_; + // If not 0, this latches the actual max_packet_length when + // SetSoftMaxPacketLength is called and max_packet_length_ gets + // set to a soft value. + QuicByteCount latched_hard_max_packet_length_; }; } // 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 a647994fc8a..6ca369cd5ec 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 @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" #include +#include #include #include #include @@ -14,13 +15,15 @@ #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" +#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.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_arraysize.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_ptr_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_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -28,6 +31,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_packet_creator_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" using testing::_; using testing::DoAll; @@ -44,8 +48,9 @@ namespace { const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678)); // Use fields in which each byte is distinct to ensure that every byte is // framed correctly. The values are otherwise arbitrary. -const QuicConnectionId kTestConnectionId = - TestConnectionId(UINT64_C(0xFEDCBA9876543210)); +QuicConnectionId CreateTestConnectionId() { + return TestConnectionId(UINT64_C(0xFEDCBA9876543210)); +} // Run tests with combinations of {ParsedQuicVersion, // ToggleVersionSerialization}. @@ -79,6 +84,8 @@ class MockDebugDelegate : public QuicPacketCreator::DebugDelegate { ~MockDebugDelegate() override = default; MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame& frame)); + + MOCK_METHOD1(OnStreamFrameCoalesced, void(const QuicStreamFrame& frame)); }; class TestPacketCreator : public QuicPacketCreator { @@ -222,7 +229,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam { EXPECT_EQ(STREAM_FRAME, frame.type); EXPECT_EQ(stream_id, frame.stream_frame.stream_id); char buf[kMaxOutgoingPacketSize]; - QuicDataWriter writer(kMaxOutgoingPacketSize, buf, HOST_BYTE_ORDER); + QuicDataWriter writer(kMaxOutgoingPacketSize, buf, quiche::HOST_BYTE_ORDER); if (frame.stream_frame.data_length > 0) { producer_.WriteStreamData(stream_id, frame.stream_frame.offset, frame.stream_frame.data_length, &writer); @@ -260,18 +267,6 @@ class QuicPacketCreatorTest : public QuicTestWithParam { /* data_length= */ 0); } - QuicPendingRetransmission CreateRetransmission( - const QuicFrames& retransmittable_frames, - bool has_crypto_handshake, - int num_padding_bytes, - EncryptionLevel encryption_level, - QuicPacketNumberLength packet_number_length) { - return QuicPendingRetransmission(QuicPacketNumber(1u), NOT_RETRANSMISSION, - retransmittable_frames, - has_crypto_handshake, num_padding_bytes, - encryption_level, packet_number_length); - } - bool IsDefaultTestConfiguration() { TestParams p = GetParam(); return p.version == AllSupportedVersions()[0] && p.version_serialization; @@ -318,8 +313,10 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) { if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) { frames_.push_back( QuicFrame(QuicStreamFrame(stream_id, false, 0u, QuicStringPiece()))); - frames_.push_back( - QuicFrame(QuicStreamFrame(stream_id, true, 0u, QuicStringPiece()))); + if (!GetQuicRestartFlag(quic_coalesce_stream_frames_2)) { + frames_.push_back( + QuicFrame(QuicStreamFrame(stream_id, true, 0u, QuicStringPiece()))); + } } SerializedPacket serialized = SerializeAllFrames(frames_); EXPECT_EQ(level, serialized.encryption_level); @@ -342,7 +339,9 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) { .WillOnce(Return(true)); if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + if (!GetQuicRestartFlag(quic_coalesce_stream_frames_2)) { + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + } } if (client_framer_.version().HasHeaderProtection()) { EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)) @@ -354,248 +353,6 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) { } } -TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) { - if (VersionHasIetfInvariantHeader(client_framer_.transport_version())) { - creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - } - // If the original packet number length, the current packet number - // length, and the configured send packet number length are different, the - // retransmit must sent with the original length and the others do not change. - QuicPacketCreatorPeer::SetPacketNumberLength(&creator_, - PACKET_2BYTE_PACKET_NUMBER); - QuicFrames frames; - std::string data("a"); - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), - /*fin=*/false, 0u, QuicStringPiece()); - frames.push_back(QuicFrame(stream_frame)); - } else { - producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); - frames.push_back( - QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length()))); - } - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, true /* has_crypto_handshake */, -1 /* needs full padding */, - ENCRYPTION_INITIAL, PACKET_4BYTE_PACKET_NUMBER)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - // The packet number length is updated after every packet is sent, - // so there is no need to restore the old length after sending. - EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)); - EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, - serialized_packet_.packet_number_length); - - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - } else { - EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)); - } - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteFrames(&frames); -} - -TEST_P(QuicPacketCreatorTest, ReserializeCryptoFrameWithForwardSecurity) { - QuicFrames frames; - std::string data("a"); - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), - /*fin=*/false, 0u, QuicStringPiece()); - frames.push_back(QuicFrame(stream_frame)); - } else { - producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); - frames.push_back( - QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length()))); - } - creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, true /* has_crypto_handshake */, -1 /* needs full padding */, - ENCRYPTION_INITIAL, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - EXPECT_EQ(ENCRYPTION_INITIAL, serialized_packet_.encryption_level); - DeleteFrames(&frames); -} - -TEST_P(QuicPacketCreatorTest, ReserializeFrameWithForwardSecurity) { - QuicStreamFrame stream_frame(0u, /*fin=*/false, 0u, QuicStringPiece()); - QuicFrames frames; - frames.push_back(QuicFrame(stream_frame)); - creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, false /* has_crypto_handshake */, 0 /* no padding */, - ENCRYPTION_INITIAL, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, serialized_packet_.encryption_level); -} - -TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPadding) { - QuicFrame frame; - std::string data = "fake handshake message data"; - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - MakeIOVector(data, &iov_); - producer_.SaveStreamData( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_, - 1u, 0u, iov_.iov_len); - QuicPacketCreatorPeer::CreateStreamFrame( - &creator_, - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), - iov_.iov_len, 0u, false, &frame); - } else { - producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); - EXPECT_TRUE(QuicPacketCreatorPeer::CreateCryptoFrame( - &creator_, ENCRYPTION_INITIAL, data.length(), 0, &frame)); - } - QuicFrames frames; - frames.push_back(frame); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, true /* has_crypto_handshake */, -1 /* needs full padding */, - ENCRYPTION_INITIAL, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length); - DeleteFrames(&frames); -} - -TEST_P(QuicPacketCreatorTest, DoNotRetransmitPendingPadding) { - QuicFrame frame; - std::string data = "fake message data"; - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - MakeIOVector(data, &iov_); - producer_.SaveStreamData( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_, - 1u, 0u, iov_.iov_len); - QuicPacketCreatorPeer::CreateStreamFrame( - &creator_, - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), - iov_.iov_len, 0u, false, &frame); - } else { - producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); - EXPECT_TRUE(QuicPacketCreatorPeer::CreateCryptoFrame( - &creator_, ENCRYPTION_INITIAL, data.length(), 0, &frame)); - } - - const int kNumPaddingBytes1 = 4; - int packet_size = 0; - { - QuicFrames frames; - frames.push_back(frame); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, false /* has_crypto_handshake */, - kNumPaddingBytes1 /* padding bytes */, ENCRYPTION_INITIAL, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, - kMaxOutgoingPacketSize); - packet_size = serialized_packet_.encrypted_length; - } - - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - if (QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)); - } else { - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - } - // Pending paddings are not retransmitted. - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(0); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - - const int kNumPaddingBytes2 = 44; - QuicFrames frames; - frames.push_back(frame); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, false /* has_crypto_handshake */, - kNumPaddingBytes2 /* padding bytes */, ENCRYPTION_INITIAL, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - - EXPECT_EQ(packet_size, serialized_packet_.encrypted_length); - DeleteFrames(&frames); -} - -TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) { - creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - const size_t overhead = - GetPacketHeaderOverhead(client_framer_.transport_version()) + - GetEncryptionOverhead() + - GetStreamFrameOverhead(client_framer_.transport_version()); - size_t capacity = kDefaultMaxPacketSize - overhead; - for (int delta = -5; delta <= 0; ++delta) { - std::string data(capacity + delta, 'A'); - size_t bytes_free = 0 - delta; - - QuicFrame frame; - SimpleDataProducer producer; - QuicPacketCreatorPeer::framer(&creator_)->set_data_producer(&producer); - MakeIOVector(data, &iov_); - QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( - client_framer_.transport_version(), Perspective::IS_CLIENT); - producer.SaveStreamData(stream_id, &iov_, 1u, 0u, iov_.iov_len); - QuicPacketCreatorPeer::CreateStreamFrame(&creator_, stream_id, iov_.iov_len, - kOffset, false, &frame); - QuicFrames frames; - frames.push_back(frame); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, false /* has_crypto_handshake */, -1 /* needs full padding */, - ENCRYPTION_FORWARD_SECURE, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, - kMaxOutgoingPacketSize); - - // If there is not enough space in the packet to fit a padding frame - // (1 byte) and to expand the stream frame (another 2 bytes) the packet - // will not be padded. - if (bytes_free < 3) { - EXPECT_EQ(kDefaultMaxPacketSize - bytes_free, - serialized_packet_.encrypted_length); - } else { - EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length); - } - - frames_.clear(); - } -} - TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) { QuicConnectionCloseFrame frame(creator_.transport_version(), QUIC_NO_ERROR, "error", @@ -784,8 +541,10 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) { // If there is not enough space in the packet to fit a padding frame // (1 byte) and to expand the stream frame (another 2 bytes) the packet // will not be padded. - if (bytes_free < 3 && - !QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { + // Padding is skipped when we try to send coalesced packets. + if ((bytes_free < 3 && + !QuicVersionUsesCryptoFrames(client_framer_.transport_version())) || + client_framer_.version().CanSendCoalescedPackets()) { EXPECT_EQ(kDefaultMaxPacketSize - bytes_free, serialized_packet_.encrypted_length); } else { @@ -861,7 +620,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathChallengePacket) { } QuicPacketHeader header; - header.destination_connection_id = kTestConnectionId; + header.destination_connection_id = CreateTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; @@ -908,7 +667,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathChallengePacket) { TEST_P(QuicPacketCreatorTest, BuildConnectivityProbingPacket) { QuicPacketHeader header; - header.destination_connection_id = kTestConnectionId; + header.destination_connection_id = CreateTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; @@ -995,7 +754,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponseUnpadded) { } QuicPacketHeader header; - header.destination_connection_id = kTestConnectionId; + header.destination_connection_id = CreateTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; @@ -1040,7 +799,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponsePadded) { } QuicPacketHeader header; - header.destination_connection_id = kTestConnectionId; + header.destination_connection_id = CreateTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; @@ -1087,7 +846,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesUnpadded) { } QuicPacketHeader header; - header.destination_connection_id = kTestConnectionId; + header.destination_connection_id = CreateTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; @@ -1139,7 +898,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesPadded) { } QuicPacketHeader header; - header.destination_connection_id = kTestConnectionId; + header.destination_connection_id = CreateTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; @@ -1705,8 +1464,7 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { // Add a variety of frame types and then a padding frame. QuicAckFrame ack_frame(InitAckFrame(10u)); EXPECT_CALL(debug, OnFrameAddedToPacket(_)); - EXPECT_TRUE( - creator_.AddSavedFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); @@ -1723,16 +1481,14 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { QuicPaddingFrame padding_frame; EXPECT_CALL(debug, OnFrameAddedToPacket(_)); - EXPECT_TRUE( - creator_.AddSavedFrame(QuicFrame(padding_frame), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(padding_frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); EXPECT_EQ(0u, creator_.BytesFree()); // Packet is full. Creator will flush. EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - EXPECT_FALSE( - creator_.AddSavedFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); + EXPECT_FALSE(creator_.AddFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); // Ensure the packet is successfully created. ASSERT_TRUE(serialized_packet_.encrypted_buffer); @@ -1841,7 +1597,7 @@ TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) { QuicStreamFrame stream_frame(GetNthClientInitiatedStreamId(0), /*fin=*/false, 0u, QuicStringPiece()); EXPECT_QUIC_BUG( - creator_.AddSavedFrame(QuicFrame(stream_frame), NOT_RETRANSMISSION), + creator_.AddFrame(QuicFrame(stream_frame), NOT_RETRANSMISSION), "Cannot send stream data with level: ENCRYPTION_INITIAL"); } @@ -1856,7 +1612,7 @@ TEST_P(QuicPacketCreatorTest, SendStreamDataWithEncryptionHandshake) { QuicStreamFrame stream_frame(GetNthClientInitiatedStreamId(0), /*fin=*/false, 0u, QuicStringPiece()); EXPECT_QUIC_BUG( - creator_.AddSavedFrame(QuicFrame(stream_frame), NOT_RETRANSMISSION), + creator_.AddFrame(QuicFrame(stream_frame), NOT_RETRANSMISSION), "Cannot send stream data with level: ENCRYPTION_HANDSHAKE"); } @@ -1936,99 +1692,6 @@ TEST_P(QuicPacketCreatorTest, FullPaddingDoesNotConsumePendingPadding) { EXPECT_EQ(kMaxNumRandomPaddingBytes, creator_.pending_padding_bytes()); } -TEST_P(QuicPacketCreatorTest, SendPendingPaddingInRetransmission) { - creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( - client_framer_.transport_version(), Perspective::IS_CLIENT); - QuicStreamFrame stream_frame(stream_id, - /*fin=*/false, 0u, QuicStringPiece()); - QuicFrames frames; - frames.push_back(QuicFrame(stream_frame)); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, true, /*num_padding_bytes=*/0, ENCRYPTION_FORWARD_SECURE, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.AddPendingPadding(kMaxNumRandomPaddingBytes); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - EXPECT_EQ(0u, creator_.pending_padding_bytes()); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); -} - -TEST_P(QuicPacketCreatorTest, SendPacketAfterFullPaddingRetransmission) { - // Making sure needs_full_padding gets reset after a full padding - // retransmission. - EXPECT_EQ(0u, creator_.pending_padding_bytes()); - creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicFrame frame; - std::string data = "fake handshake message data"; - MakeIOVector(data, &iov_); - QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( - client_framer_.transport_version(), Perspective::IS_CLIENT); - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - stream_id = - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()); - } - producer_.SaveStreamData(stream_id, &iov_, 1u, 0u, iov_.iov_len); - QuicPacketCreatorPeer::CreateStreamFrame(&creator_, stream_id, iov_.iov_len, - 0u, false, &frame); - QuicFrames frames; - frames.push_back(frame); - char buffer[kMaxOutgoingPacketSize]; - QuicPendingRetransmission retransmission(CreateRetransmission( - frames, true, /*num_padding_bytes=*/-1, ENCRYPTION_FORWARD_SECURE, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly( - Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.ReserializeAllFrames(retransmission, buffer, kMaxOutgoingPacketSize); - EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - // Full padding. - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - - creator_.ConsumeDataToFillCurrentPacket(stream_id, &iov_, 1u, iov_.iov_len, - 0u, 0u, false, false, - NOT_RETRANSMISSION, &frame); - creator_.FlushCurrentPacket(); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - // needs_full_padding gets reset. - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(0); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteFrames(&frames); -} - TEST_P(QuicPacketCreatorTest, ConsumeDataAndRandomPadding) { creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); const QuicByteCount kStreamFramePayloadSize = 100u; @@ -2125,20 +1788,19 @@ TEST_P(QuicPacketCreatorTest, AddMessageFrame) { std::string message(creator_.GetCurrentLargestMessagePayload(), 'a'); QuicMessageFrame* message_frame = new QuicMessageFrame(1, MakeSpan(&allocator_, message, &storage)); - EXPECT_TRUE( - creator_.AddSavedFrame(QuicFrame(message_frame), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(message_frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); creator_.FlushCurrentPacket(); QuicMessageFrame* frame2 = new QuicMessageFrame(2, MakeSpan(&allocator_, "message", &storage)); - EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame2), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(frame2), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); // Verify if a new frame is added, 1 byte message length will be added. EXPECT_EQ(1u, creator_.ExpansionOnNewFrame()); QuicMessageFrame* frame3 = new QuicMessageFrame(3, MakeSpan(&allocator_, "message2", &storage)); - EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame3), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(frame3), NOT_RETRANSMISSION)); EXPECT_EQ(1u, creator_.ExpansionOnNewFrame()); creator_.FlushCurrentPacket(); @@ -2151,14 +1813,14 @@ TEST_P(QuicPacketCreatorTest, AddMessageFrame) { NOT_RETRANSMISSION, &frame)); QuicMessageFrame* frame4 = new QuicMessageFrame(4, MakeSpan(&allocator_, "message", &storage)); - EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame4), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(frame4), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); // Verify there is not enough room for largest payload. EXPECT_FALSE(creator_.HasRoomForMessageFrame( creator_.GetCurrentLargestMessagePayload())); // Add largest message will causes the flush of the stream frame. QuicMessageFrame frame5(5, MakeSpan(&allocator_, message, &storage)); - EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&frame5), NOT_RETRANSMISSION)); + EXPECT_FALSE(creator_.AddFrame(QuicFrame(&frame5), NOT_RETRANSMISSION)); EXPECT_FALSE(creator_.HasPendingFrames()); } @@ -2181,7 +1843,7 @@ TEST_P(QuicPacketCreatorTest, MessageFrameConsumption) { 0, MakeSpan(&allocator_, QuicStringPiece(message_buffer.data(), message_size), &storage)); - EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); size_t expansion_bytes = message_size >= 64 ? 2 : 1; @@ -2225,8 +1887,6 @@ TEST_P(QuicPacketCreatorTest, GetGuaranteedLargestMessagePayload) { TEST_P(QuicPacketCreatorTest, PacketTransmissionType) { creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - creator_.set_can_set_transmission_type(true); - creator_.SetTransmissionTypeOfNextPackets(NOT_RETRANSMISSION); QuicAckFrame temp_ack_frame = InitAckFrame(1); QuicFrame ack_frame(&temp_ack_frame); @@ -2244,23 +1904,19 @@ TEST_P(QuicPacketCreatorTest, PacketTransmissionType) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - EXPECT_TRUE(creator_.AddSavedFrame(ack_frame, LOSS_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(ack_frame, LOSS_RETRANSMISSION)); ASSERT_FALSE(serialized_packet_.encrypted_buffer); - EXPECT_TRUE(creator_.AddSavedFrame(stream_frame, RTO_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(stream_frame, RTO_RETRANSMISSION)); ASSERT_FALSE(serialized_packet_.encrypted_buffer); - EXPECT_TRUE(creator_.AddSavedFrame(padding_frame, TLP_RETRANSMISSION)); + EXPECT_TRUE(creator_.AddFrame(padding_frame, TLP_RETRANSMISSION)); creator_.FlushCurrentPacket(); ASSERT_TRUE(serialized_packet_.encrypted_buffer); - if (creator_.can_set_transmission_type()) { - // The last retransmittable frame on packet is a stream frame, the packet's - // transmission type should be the same as the stream frame's. - EXPECT_EQ(serialized_packet_.transmission_type, RTO_RETRANSMISSION); - } else { - EXPECT_EQ(serialized_packet_.transmission_type, NOT_RETRANSMISSION); - } + // The last retransmittable frame on packet is a stream frame, the packet's + // transmission type should be the same as the stream frame's. + EXPECT_EQ(serialized_packet_.transmission_type, RTO_RETRANSMISSION); DeleteSerializedPacket(); } @@ -2334,6 +1990,1732 @@ TEST_P(QuicPacketCreatorTest, ClientConnectionId) { EXPECT_EQ(TestConnectionId(0x33), creator_.GetSourceConnectionId()); } +TEST_P(QuicPacketCreatorTest, CoalesceStreamFrames) { + InSequence s; + if (!GetParam().version_serialization) { + creator_.StopSendingVersion(); + } + SetQuicRestartFlag(quic_coalesce_stream_frames_2, true); + const size_t max_plaintext_size = + client_framer_.GetMaxPlaintextSize(creator_.max_packet_length()); + EXPECT_FALSE(creator_.HasPendingFrames()); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + QuicStreamId stream_id1 = QuicUtils::GetFirstBidirectionalStreamId( + client_framer_.transport_version(), Perspective::IS_CLIENT); + QuicStreamId stream_id2 = GetNthClientInitiatedStreamId(1); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id1)); + EXPECT_EQ(max_plaintext_size - + GetPacketHeaderSize( + client_framer_.transport_version(), + creator_.GetDestinationConnectionIdLength(), + creator_.GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(&creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), + 0, QuicPacketCreatorPeer::GetLengthLength(&creator_)), + creator_.BytesFree()); + StrictMock debug; + creator_.set_debug_delegate(&debug); + + MakeIOVector("test", &iov_); + QuicFrame frame; + EXPECT_CALL(debug, OnFrameAddedToPacket(_)); + ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket( + stream_id1, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false, + NOT_RETRANSMISSION, &frame)); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id1)); + + MakeIOVector("coalesce", &iov_); + // frame will be coalesced with the first frame. + const auto previous_size = creator_.PacketSize(); + QuicStreamFrame target(stream_id1, true, 0, 12); + EXPECT_CALL(debug, OnStreamFrameCoalesced(target)); + ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket( + stream_id1, &iov_, 1u, iov_.iov_len, 0u, 4u, true, false, + NOT_RETRANSMISSION, &frame)); + EXPECT_EQ(frame.stream_frame.data_length, + creator_.PacketSize() - previous_size); + + // frame is for another stream, so it won't be coalesced. + const auto length = creator_.BytesFree() - 10u; + std::string large_data(length, 'x'); + MakeIOVector(large_data, &iov_); + EXPECT_CALL(debug, OnFrameAddedToPacket(_)); + ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket( + stream_id2, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false, + NOT_RETRANSMISSION, &frame)); + EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id2)); + + // The packet doesn't have enough free bytes for all data, but will still be + // able to consume and coalesce part of them. + EXPECT_CALL(debug, OnStreamFrameCoalesced(_)); + MakeIOVector("somerandomdata", &iov_); + ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket( + stream_id2, &iov_, 1u, iov_.iov_len, 0u, length, false, false, + NOT_RETRANSMISSION, &frame)); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); + creator_.FlushCurrentPacket(); + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + // The packet should only have 2 stream frames. + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + ProcessPacket(serialized_packet_); +} + +TEST_P(QuicPacketCreatorTest, SaveNonRetransmittableFrames) { + QuicAckFrame ack_frame(InitAckFrame(1)); + frames_.push_back(QuicFrame(&ack_frame)); + frames_.push_back(QuicFrame(QuicPaddingFrame(-1))); + SerializedPacket serialized = SerializeAllFrames(frames_); + ASSERT_EQ(2u, serialized.nonretransmittable_frames.size()); + EXPECT_EQ(ACK_FRAME, serialized.nonretransmittable_frames[0].type); + EXPECT_EQ(PADDING_FRAME, serialized.nonretransmittable_frames[1].type); + // Verify full padding frame is translated to a padding frame with actual + // bytes of padding. + EXPECT_LT( + 0, + serialized.nonretransmittable_frames[1].padding_frame.num_padding_bytes); + frames_.clear(); + + // Serialize another packet with the same frames. + SerializedPacket packet = QuicPacketCreatorPeer::SerializeAllFrames( + &creator_, serialized.nonretransmittable_frames, buffer_, + kMaxOutgoingPacketSize); + // Verify the packet length of both packets are equal. + EXPECT_EQ(serialized.encrypted_length, packet.encrypted_length); +} + +TEST_P(QuicPacketCreatorTest, SerializeCoalescedPacket) { + QuicCoalescedPacket coalesced; + SimpleBufferAllocator allocator; + QuicSocketAddress self_address(QuicIpAddress::Loopback4(), 1); + QuicSocketAddress peer_address(QuicIpAddress::Loopback4(), 2); + for (size_t i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { + EncryptionLevel level = static_cast(i); + creator_.set_encryption_level(level); + QuicAckFrame ack_frame(InitAckFrame(1)); + frames_.push_back(QuicFrame(&ack_frame)); + if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) { + frames_.push_back( + QuicFrame(QuicStreamFrame(1, false, 0u, QuicStringPiece()))); + } + SerializedPacket serialized = SerializeAllFrames(frames_); + EXPECT_EQ(level, serialized.encryption_level); + frames_.clear(); + ASSERT_TRUE(coalesced.MaybeCoalescePacket(serialized, self_address, + peer_address, &allocator, + creator_.max_packet_length())); + } + char buffer[kMaxOutgoingPacketSize]; + size_t coalesced_length = creator_.SerializeCoalescedPacket( + coalesced, buffer, kMaxOutgoingPacketSize); + // Verify packet is padded to full. + ASSERT_EQ(coalesced.max_packet_length(), coalesced_length); + if (!QuicVersionHasLongHeaderLengths(server_framer_.transport_version())) { + return; + } + // Verify packet process. + std::unique_ptr packets[NUM_ENCRYPTION_LEVELS]; + packets[ENCRYPTION_INITIAL] = + std::make_unique(buffer, coalesced_length); + for (size_t i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + if (i < ENCRYPTION_FORWARD_SECURE) { + // Save coalesced packet. + EXPECT_CALL(framer_visitor_, OnCoalescedPacket(_)) + .WillOnce(Invoke([i, &packets](const QuicEncryptedPacket& packet) { + packets[i + 1] = packet.Clone(); + })); + } + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnAckFrameStart(_, _)).WillOnce(Return(true)); + EXPECT_CALL(framer_visitor_, + OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2))) + .WillOnce(Return(true)); + EXPECT_CALL(framer_visitor_, OnAckFrameEnd(_)).WillOnce(Return(true)); + if (i == ENCRYPTION_INITIAL) { + // Verify padding is added. + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + } else { + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(testing::AtMost(1)); + } + if (i != ENCRYPTION_INITIAL && i != ENCRYPTION_HANDSHAKE) { + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + } + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + + server_framer_.ProcessPacket(*packets[i]); + } +} + +TEST_P(QuicPacketCreatorTest, SoftMaxPacketLength) { + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + QuicByteCount previous_max_packet_length = creator_.max_packet_length(); + const size_t overhead = + GetPacketHeaderOverhead(client_framer_.transport_version()) + + QuicPacketCreator::MinPlaintextPacketSize(client_framer_.version()) + + GetEncryptionOverhead(); + // Make sure a length which cannot accommodate header (includes header + // protection minimal length) gets rejected. + creator_.SetSoftMaxPacketLength(overhead - 1); + EXPECT_EQ(previous_max_packet_length, creator_.max_packet_length()); + + creator_.SetSoftMaxPacketLength(overhead); + EXPECT_EQ(overhead, creator_.max_packet_length()); + + // Verify creator has room for stream frame because max_packet_length_ gets + // restored. + ASSERT_TRUE(creator_.HasRoomForStreamFrame( + GetNthClientInitiatedStreamId(1), kMaxIetfVarInt, + std::numeric_limits::max())); + EXPECT_EQ(previous_max_packet_length, creator_.max_packet_length()); + + // Same for message frame. + if (VersionSupportsMessageFrames(client_framer_.transport_version())) { + creator_.SetSoftMaxPacketLength(overhead); + // Verify GetCurrentLargestMessagePayload is based on the actual + // max_packet_length. + EXPECT_LT(1u, creator_.GetCurrentLargestMessagePayload()); + EXPECT_EQ(overhead, creator_.max_packet_length()); + ASSERT_TRUE(creator_.HasRoomForMessageFrame( + creator_.GetCurrentLargestMessagePayload())); + EXPECT_EQ(previous_max_packet_length, creator_.max_packet_length()); + } + + // Verify creator can consume crypto data because max_packet_length_ gets + // restored. + creator_.SetSoftMaxPacketLength(overhead); + EXPECT_EQ(overhead, creator_.max_packet_length()); + std::string data = "crypto data"; + MakeIOVector(data, &iov_); + QuicFrame frame; + if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { + ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket( + QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_, + 1u, iov_.iov_len, 0u, kOffset, false, true, NOT_RETRANSMISSION, + &frame)); + size_t bytes_consumed = frame.stream_frame.data_length; + EXPECT_LT(0u, bytes_consumed); + } else { + producer_.SaveCryptoData(ENCRYPTION_INITIAL, kOffset, data); + ASSERT_TRUE(creator_.ConsumeCryptoDataToFillCurrentPacket( + ENCRYPTION_INITIAL, data.length(), kOffset, + /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)); + size_t bytes_consumed = frame.crypto_frame->data_length; + EXPECT_LT(0u, bytes_consumed); + } + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); + creator_.FlushCurrentPacket(); + + // Verify ACK frame can be consumed. + creator_.SetSoftMaxPacketLength(overhead); + EXPECT_EQ(overhead, creator_.max_packet_length()); + QuicAckFrame ack_frame(InitAckFrame(10u)); + EXPECT_TRUE(creator_.AddFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); + EXPECT_TRUE(creator_.HasPendingFrames()); +} + +class MockDelegate : public QuicPacketCreator::DelegateInterface { + public: + MockDelegate() {} + MockDelegate(const MockDelegate&) = delete; + MockDelegate& operator=(const MockDelegate&) = delete; + ~MockDelegate() override {} + + MOCK_METHOD2(ShouldGeneratePacket, + bool(HasRetransmittableData retransmittable, + IsHandshake handshake)); + MOCK_METHOD0(MaybeBundleAckOpportunistically, const QuicFrames()); + MOCK_METHOD0(GetPacketBuffer, char*()); + MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); + MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&)); + + void SetCanWriteAnything() { + EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _)) + .WillRepeatedly(Return(true)); + } + + void SetCanNotWrite() { + EXPECT_CALL(*this, ShouldGeneratePacket(_, _)) + .WillRepeatedly(Return(false)); + EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _)) + .WillRepeatedly(Return(false)); + } + + // Use this when only ack frames should be allowed to be written. + void SetCanWriteOnlyNonRetransmittable() { + EXPECT_CALL(*this, ShouldGeneratePacket(_, _)) + .WillRepeatedly(Return(false)); + EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _)) + .WillRepeatedly(Return(true)); + } +}; + +// Simple struct for describing the contents of a packet. +// Useful in conjunction with a SimpleQuicFrame for validating that a packet +// contains the expected frames. +struct PacketContents { + PacketContents() + : num_ack_frames(0), + num_connection_close_frames(0), + num_goaway_frames(0), + num_rst_stream_frames(0), + num_stop_waiting_frames(0), + num_stream_frames(0), + num_crypto_frames(0), + num_ping_frames(0), + num_mtu_discovery_frames(0), + num_padding_frames(0) {} + + size_t num_ack_frames; + size_t num_connection_close_frames; + size_t num_goaway_frames; + size_t num_rst_stream_frames; + size_t num_stop_waiting_frames; + size_t num_stream_frames; + size_t num_crypto_frames; + size_t num_ping_frames; + size_t num_mtu_discovery_frames; + size_t num_padding_frames; +}; + +class MultiplePacketsTestPacketCreator : public QuicPacketCreator { + public: + MultiplePacketsTestPacketCreator( + QuicConnectionId connection_id, + QuicFramer* framer, + QuicRandom* random_generator, + QuicPacketCreator::DelegateInterface* delegate, + SimpleDataProducer* producer) + : QuicPacketCreator(connection_id, framer, random_generator, delegate), + ack_frame_(InitAckFrame(1)), + delegate_(static_cast(delegate)), + producer_(producer) {} + + bool ConsumeRetransmittableControlFrame(const QuicFrame& frame, + bool bundle_ack) { + if (!has_ack()) { + QuicFrames frames; + if (bundle_ack) { + frames.push_back(QuicFrame(&ack_frame_)); + } + if (delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)) { + EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()) + .WillOnce(Return(frames)); + } + } + return QuicPacketCreator::ConsumeRetransmittableControlFrame(frame); + } + + QuicConsumedData ConsumeDataFastPath(QuicStreamId id, + const struct iovec* iov, + int iov_count, + size_t total_length, + QuicStreamOffset offset, + bool fin) { + // Save data before data is consumed. + if (total_length > 0) { + producer_->SaveStreamData(id, iov, iov_count, 0, total_length); + } + return QuicPacketCreator::ConsumeDataFastPath(id, total_length, offset, fin, + 0); + } + + QuicConsumedData ConsumeData(QuicStreamId id, + const struct iovec* iov, + int iov_count, + size_t total_length, + QuicStreamOffset offset, + StreamSendingState state) { + // Save data before data is consumed. + if (total_length > 0) { + producer_->SaveStreamData(id, iov, iov_count, 0, total_length); + } + if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)) { + EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); + } + return QuicPacketCreator::ConsumeData(id, total_length, offset, state); + } + + MessageStatus AddMessageFrame(QuicMessageId message_id, + QuicMemSliceSpan message) { + if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)) { + EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); + } + return QuicPacketCreator::AddMessageFrame(message_id, message); + } + + size_t ConsumeCryptoData(EncryptionLevel level, + QuicStringPiece data, + QuicStreamOffset offset) { + producer_->SaveCryptoData(level, offset, data); + if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)) { + EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); + } + return QuicPacketCreator::ConsumeCryptoData(level, data.length(), offset); + } + + QuicAckFrame ack_frame_; + MockDelegate* delegate_; + SimpleDataProducer* producer_; +}; + +class QuicPacketCreatorMultiplePacketsTest : public QuicTest { + public: + QuicPacketCreatorMultiplePacketsTest() + : framer_(AllSupportedVersions(), + QuicTime::Zero(), + Perspective::IS_CLIENT, + kQuicDefaultConnectionIdLength), + creator_(TestConnectionId(), + &framer_, + &random_creator_, + &delegate_, + &producer_), + ack_frame_(InitAckFrame(1)) { + EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); + creator_.SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique(Perspective::IS_CLIENT)); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + framer_.set_data_producer(&producer_); + if (simple_framer_.framer()->version().KnowsWhichDecrypterToUse()) { + simple_framer_.framer()->InstallDecrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique(Perspective::IS_SERVER)); + } + creator_.AttachPacketFlusher(); + } + + ~QuicPacketCreatorMultiplePacketsTest() override { + for (SerializedPacket& packet : packets_) { + delete[] packet.encrypted_buffer; + ClearSerializedPacket(&packet); + } + } + + void SavePacket(SerializedPacket* packet) { + packet->encrypted_buffer = CopyBuffer(*packet); + packets_.push_back(*packet); + packet->encrypted_buffer = nullptr; + packet->retransmittable_frames.clear(); + } + + protected: + QuicRstStreamFrame* CreateRstStreamFrame() { + return new QuicRstStreamFrame(1, 1, QUIC_STREAM_NO_ERROR, 0); + } + + QuicGoAwayFrame* CreateGoAwayFrame() { + return new QuicGoAwayFrame(2, QUIC_NO_ERROR, 1, std::string()); + } + + void CheckPacketContains(const PacketContents& contents, + size_t packet_index) { + ASSERT_GT(packets_.size(), packet_index); + const SerializedPacket& packet = packets_[packet_index]; + size_t num_retransmittable_frames = + contents.num_connection_close_frames + contents.num_goaway_frames + + contents.num_rst_stream_frames + contents.num_stream_frames + + contents.num_crypto_frames + contents.num_ping_frames; + size_t num_frames = + contents.num_ack_frames + contents.num_stop_waiting_frames + + contents.num_mtu_discovery_frames + contents.num_padding_frames + + num_retransmittable_frames; + + if (num_retransmittable_frames == 0) { + ASSERT_TRUE(packet.retransmittable_frames.empty()); + } else { + ASSERT_FALSE(packet.retransmittable_frames.empty()); + EXPECT_EQ(num_retransmittable_frames, + packet.retransmittable_frames.size()); + } + + ASSERT_TRUE(packet.encrypted_buffer != nullptr); + ASSERT_TRUE(simple_framer_.ProcessPacket( + QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length))); + size_t num_padding_frames = 0; + if (contents.num_padding_frames == 0) { + num_padding_frames = simple_framer_.padding_frames().size(); + } + EXPECT_EQ(num_frames + num_padding_frames, simple_framer_.num_frames()); + EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size()); + EXPECT_EQ(contents.num_connection_close_frames, + simple_framer_.connection_close_frames().size()); + EXPECT_EQ(contents.num_goaway_frames, + simple_framer_.goaway_frames().size()); + EXPECT_EQ(contents.num_rst_stream_frames, + simple_framer_.rst_stream_frames().size()); + EXPECT_EQ(contents.num_stream_frames, + simple_framer_.stream_frames().size()); + EXPECT_EQ(contents.num_crypto_frames, + simple_framer_.crypto_frames().size()); + EXPECT_EQ(contents.num_stop_waiting_frames, + simple_framer_.stop_waiting_frames().size()); + if (contents.num_padding_frames != 0) { + EXPECT_EQ(contents.num_padding_frames, + simple_framer_.padding_frames().size()); + } + + // From the receiver's perspective, MTU discovery frames are ping frames. + EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames, + simple_framer_.ping_frames().size()); + } + + void CheckPacketHasSingleStreamFrame(size_t packet_index) { + ASSERT_GT(packets_.size(), packet_index); + const SerializedPacket& packet = packets_[packet_index]; + ASSERT_FALSE(packet.retransmittable_frames.empty()); + EXPECT_EQ(1u, packet.retransmittable_frames.size()); + ASSERT_TRUE(packet.encrypted_buffer != nullptr); + ASSERT_TRUE(simple_framer_.ProcessPacket( + QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length))); + EXPECT_EQ(1u, simple_framer_.num_frames()); + EXPECT_EQ(1u, simple_framer_.stream_frames().size()); + } + + void CheckAllPacketsHaveSingleStreamFrame() { + for (size_t i = 0; i < packets_.size(); i++) { + CheckPacketHasSingleStreamFrame(i); + } + } + + void CreateData(size_t len) { + data_array_.reset(new char[len]); + memset(data_array_.get(), '?', len); + iov_.iov_base = data_array_.get(); + iov_.iov_len = len; + } + + QuicFramer framer_; + MockRandom random_creator_; + StrictMock delegate_; + MultiplePacketsTestPacketCreator creator_; + SimpleQuicFramer simple_framer_; + std::vector packets_; + QuicAckFrame ack_frame_; + struct iovec iov_; + SimpleBufferAllocator allocator_; + + private: + std::unique_ptr data_array_; + SimpleDataProducer producer_; +}; + +TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_NotWritable) { + delegate_.SetCanNotWrite(); + + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + EXPECT_FALSE(consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + delete rst_frame; +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_OnlyAckWritable) { + delegate_.SetCanWriteOnlyNonRetransmittable(); + + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + EXPECT_FALSE(consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + delete rst_frame; +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + AddControlFrame_WritableAndShouldNotFlush) { + delegate_.SetCanWriteAnything(); + + creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateRstStreamFrame()), + /*bundle_ack=*/false); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + AddControlFrame_NotWritableBatchThenFlush) { + delegate_.SetCanNotWrite(); + + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + EXPECT_FALSE(consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + delete rst_frame; +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + AddControlFrame_WritableAndShouldFlush) { + delegate_.SetCanWriteAnything(); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateRstStreamFrame()), + /*bundle_ack=*/false); + creator_.Flush(); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_rst_stream_frames = 1; + CheckPacketContains(contents, 0); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeCryptoData) { + delegate_.SetCanWriteAnything(); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + std::string data = "crypto data"; + size_t consumed_bytes = + creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + creator_.Flush(); + EXPECT_EQ(data.length(), consumed_bytes); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_crypto_frames = 1; + contents.num_padding_frames = 1; + CheckPacketContains(contents, 0); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_NotWritable) { + delegate_.SetCanNotWrite(); + + MakeIOVector("foo", &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ(0u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConsumeData_WritableAndShouldNotFlush) { + delegate_.SetCanWriteAnything(); + + MakeIOVector("foo", &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConsumeData_WritableAndShouldFlush) { + delegate_.SetCanWriteAnything(); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + MakeIOVector("foo", &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + creator_.Flush(); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); +} + +// Test the behavior of ConsumeData when the data consumed is for the crypto +// handshake stream. Ensure that the packet is always sent and padded even if +// the creator operates in batch mode. +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_Handshake) { + delegate_.SetCanWriteAnything(); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + std::string data = "foo bar"; + MakeIOVector(data, &iov_); + size_t consumed_bytes = 0; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + consumed_bytes = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + } else { + consumed_bytes = + creator_ + .ConsumeData( + QuicUtils::GetCryptoStreamId(framer_.transport_version()), + &iov_, 1u, iov_.iov_len, 0, NO_FIN) + .bytes_consumed; + } + EXPECT_EQ(7u, consumed_bytes); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + contents.num_crypto_frames = 1; + } else { + contents.num_stream_frames = 1; + } + contents.num_padding_frames = 1; + CheckPacketContains(contents, 0); + + ASSERT_EQ(1u, packets_.size()); + ASSERT_EQ(kDefaultMaxPacketSize, creator_.max_packet_length()); + EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); +} + +// Test the behavior of ConsumeData when the data is for the crypto handshake +// stream, but padding is disabled. +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConsumeData_Handshake_PaddingDisabled) { + creator_.set_fully_pad_crypto_handshake_packets(false); + + delegate_.SetCanWriteAnything(); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + std::string data = "foo"; + MakeIOVector(data, &iov_); + size_t bytes_consumed = 0; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + bytes_consumed = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + } else { + bytes_consumed = + creator_ + .ConsumeData( + QuicUtils::GetCryptoStreamId(framer_.transport_version()), + &iov_, 1u, iov_.iov_len, 0, NO_FIN) + .bytes_consumed; + } + EXPECT_EQ(3u, bytes_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + contents.num_crypto_frames = 1; + } else { + contents.num_stream_frames = 1; + } + contents.num_padding_frames = 0; + CheckPacketContains(contents, 0); + + ASSERT_EQ(1u, packets_.size()); + + // Packet is not fully padded, but we want to future packets to be larger. + ASSERT_EQ(kDefaultMaxPacketSize, creator_.max_packet_length()); + size_t expected_packet_length = 27; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + // The framing of CRYPTO frames is slightly different than that of stream + // frames, so the expected packet length differs slightly. + expected_packet_length = 28; + } + if (framer_.version().HasHeaderProtection()) { + expected_packet_length = 29; + } + EXPECT_EQ(expected_packet_length, packets_[0].encrypted_length); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_EmptyData) { + delegate_.SetCanWriteAnything(); + + EXPECT_QUIC_BUG(creator_.ConsumeData( + QuicUtils::QuicUtils::GetFirstBidirectionalStreamId( + framer_.transport_version(), Perspective::IS_CLIENT), + nullptr, 0, 0, 0, NO_FIN), + "Attempt to consume empty data without FIN."); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConsumeDataMultipleTimes_WritableAndShouldNotFlush) { + delegate_.SetCanWriteAnything(); + + MakeIOVector("foo", &iov_); + creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId( + framer_.transport_version(), Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + MakeIOVector("quux", &iov_); + QuicConsumedData consumed = + creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN); + EXPECT_EQ(4u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_BatchOperations) { + delegate_.SetCanWriteAnything(); + + MakeIOVector("foo", &iov_); + creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId( + framer_.transport_version(), Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, NO_FIN); + MakeIOVector("quux", &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 3, FIN); + EXPECT_EQ(4u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + // Now both frames will be flushed out. + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + creator_.Flush(); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_stream_frames = + GetQuicRestartFlag(quic_coalesce_stream_frames_2) ? 1 : 2; + CheckPacketContains(contents, 0); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConsumeData_FramesPreviouslyQueued) { + // Set the packet size be enough for two stream frames with 0 stream offset, + // but not enough for a stream frame of 0 offset and one with non-zero offset. + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_.GetDestinationConnectionIdLength(), + creator_.GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(&creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(&creator_)) + + // Add an extra 3 bytes for the payload and 1 byte so + // BytesFree is larger than the GetMinStreamFrameSize. + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, + false, 3) + + 3 + + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, true, + 1) + + 1; + creator_.SetMaxPacketLength(length); + delegate_.SetCanWriteAnything(); + { + InSequence dummy; + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + } + // Queue enough data to prevent a stream frame with a non-zero offset from + // fitting. + MakeIOVector("foo", &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + // This frame will not fit with the existing frame, causing the queued frame + // to be serialized, and it will be added to a new open packet. + MakeIOVector("bar", &iov_); + consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 3, FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + creator_.FlushCurrentPacket(); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); + CheckPacketContains(contents, 1); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataFastPath) { + delegate_.SetCanWriteAnything(); + creator_.SetTransmissionType(LOSS_RETRANSMISSION); + + // Create a 10000 byte IOVector. + CreateData(10000); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + QuicConsumedData consumed = creator_.ConsumeDataFastPath( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, true); + EXPECT_EQ(10000u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); + EXPECT_FALSE(packets_.empty()); + SerializedPacket packet = packets_.back(); + EXPECT_TRUE(!packet.retransmittable_frames.empty()); + EXPECT_EQ(LOSS_RETRANSMISSION, packet.transmission_type); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + const QuicStreamFrame& stream_frame = + packet.retransmittable_frames.front().stream_frame; + EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLarge) { + delegate_.SetCanWriteAnything(); + + // Create a 10000 byte IOVector. + CreateData(10000); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ(10000u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + PacketContents contents; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); + EXPECT_FALSE(packets_.empty()); + SerializedPacket packet = packets_.back(); + EXPECT_TRUE(!packet.retransmittable_frames.empty()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + const QuicStreamFrame& stream_frame = + packet.retransmittable_frames.front().stream_frame; + EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckFalse) { + delegate_.SetCanNotWrite(); + + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool success = + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/true); + EXPECT_FALSE(success); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + delegate_.SetCanWriteAnything(); + + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + + // Create a 10000 byte IOVector. + CreateData(10000); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateRstStreamFrame()), + /*bundle_ack=*/true); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + creator_.Flush(); + + EXPECT_EQ(10000u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + EXPECT_FALSE(packets_.empty()); + SerializedPacket packet = packets_.back(); + EXPECT_TRUE(!packet.retransmittable_frames.empty()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + const QuicStreamFrame& stream_frame = + packet.retransmittable_frames.front().stream_frame; + EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckTrue) { + delegate_.SetCanNotWrite(); + delegate_.SetCanWriteAnything(); + + // Create a 10000 byte IOVector. + CreateData(10000); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + creator_.Flush(); + + EXPECT_EQ(10000u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + EXPECT_FALSE(packets_.empty()); + SerializedPacket packet = packets_.back(); + EXPECT_TRUE(!packet.retransmittable_frames.empty()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + const QuicStreamFrame& stream_frame = + packet.retransmittable_frames.front().stream_frame; + EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, NotWritableThenBatchOperations) { + delegate_.SetCanNotWrite(); + + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/true); + EXPECT_FALSE(consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(3)); + + delegate_.SetCanWriteAnything(); + + EXPECT_TRUE( + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false)); + // Send some data and a control frame + MakeIOVector("quux", &iov_); + creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN); + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateGoAwayFrame()), + /*bundle_ack=*/false); + } + EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(3)); + + // All five frames will be flushed out in a single packet. + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + creator_.Flush(); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(3)); + + PacketContents contents; + // ACK will be flushed by connection. + contents.num_ack_frames = 0; + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + contents.num_goaway_frames = 1; + } else { + contents.num_goaway_frames = 0; + } + contents.num_rst_stream_frames = 1; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, NotWritableThenBatchOperations2) { + delegate_.SetCanNotWrite(); + + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool success = + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/true); + EXPECT_FALSE(success); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + delegate_.SetCanWriteAnything(); + + { + InSequence dummy; + // All five frames will be flushed out in a single packet + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + } + EXPECT_TRUE( + creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false)); + // Send enough data to exceed one packet + size_t data_len = kDefaultMaxPacketSize + 100; + CreateData(data_len); + QuicConsumedData consumed = + creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateGoAwayFrame()), + /*bundle_ack=*/false); + } + + creator_.Flush(); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // The first packet should have the queued data and part of the stream data. + PacketContents contents; + // ACK will be sent by connection. + contents.num_ack_frames = 0; + contents.num_rst_stream_frames = 1; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); + + // The second should have the remainder of the stream data. + PacketContents contents2; + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + contents2.num_goaway_frames = 1; + } else { + contents2.num_goaway_frames = 0; + } + contents2.num_stream_frames = 1; + CheckPacketContains(contents2, 1); +} + +// Regression test of b/120493795. +TEST_F(QuicPacketCreatorMultiplePacketsTest, PacketTransmissionType) { + delegate_.SetCanWriteAnything(); + + // The first ConsumeData will fill the packet without flush. + creator_.SetTransmissionType(LOSS_RETRANSMISSION); + + size_t data_len = 1324; + CreateData(data_len); + QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId( + framer_.transport_version(), Perspective::IS_CLIENT); + QuicConsumedData consumed = + creator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(data_len, consumed.bytes_consumed); + ASSERT_EQ(0u, creator_.BytesFree()) + << "Test setup failed: Please increase data_len to " + << data_len + creator_.BytesFree() << " bytes."; + + // The second ConsumeData can not be added to the packet and will flush. + creator_.SetTransmissionType(NOT_RETRANSMISSION); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + QuicStreamId stream2_id = stream1_id + 4; + + consumed = + creator_.ConsumeData(stream2_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(data_len, consumed.bytes_consumed); + + // Ensure the packet is successfully created. + ASSERT_EQ(1u, packets_.size()); + ASSERT_TRUE(packets_[0].encrypted_buffer); + ASSERT_EQ(1u, packets_[0].retransmittable_frames.size()); + EXPECT_EQ(stream1_id, + packets_[0].retransmittable_frames[0].stream_frame.stream_id); + + // Since the second frame was not added, the packet's transmission type + // should be the first frame's type. + EXPECT_EQ(packets_[0].transmission_type, LOSS_RETRANSMISSION); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, TestConnectionIdLength) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + creator_.SetServerConnectionIdLength(0); + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, + creator_.GetDestinationConnectionIdLength()); + + for (size_t i = 1; i < 10; i++) { + creator_.SetServerConnectionIdLength(i); + if (VersionHasIetfInvariantHeader(framer_.transport_version())) { + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, + creator_.GetDestinationConnectionIdLength()); + } else { + EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, + creator_.GetDestinationConnectionIdLength()); + } + } +} + +// Test whether SetMaxPacketLength() works in the situation when the queue is +// empty, and we send three packets worth of data. +TEST_F(QuicPacketCreatorMultiplePacketsTest, SetMaxPacketLength_Initial) { + delegate_.SetCanWriteAnything(); + + // Send enough data for three packets. + size_t data_len = 3 * kDefaultMaxPacketSize + 1; + size_t packet_len = kDefaultMaxPacketSize + 100; + ASSERT_LE(packet_len, kMaxOutgoingPacketSize); + creator_.SetMaxPacketLength(packet_len); + EXPECT_EQ(packet_len, creator_.max_packet_length()); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .Times(3) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + CreateData(data_len); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, + /*offset=*/0, FIN); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // We expect three packets, and first two of them have to be of packet_len + // size. We check multiple packets (instead of just one) because we want to + // ensure that |max_packet_length_| does not get changed incorrectly by the + // creator after first packet is serialized. + ASSERT_EQ(3u, packets_.size()); + EXPECT_EQ(packet_len, packets_[0].encrypted_length); + EXPECT_EQ(packet_len, packets_[1].encrypted_length); + CheckAllPacketsHaveSingleStreamFrame(); +} + +// Test whether SetMaxPacketLength() works in the situation when we first write +// data, then change packet size, then write data again. +TEST_F(QuicPacketCreatorMultiplePacketsTest, SetMaxPacketLength_Middle) { + delegate_.SetCanWriteAnything(); + + // We send enough data to overflow default packet length, but not the altered + // one. + size_t data_len = kDefaultMaxPacketSize; + size_t packet_len = kDefaultMaxPacketSize + 100; + ASSERT_LE(packet_len, kMaxOutgoingPacketSize); + + // We expect to see three packets in total. + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .Times(3) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + // Send two packets before packet size change. + CreateData(data_len); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, + /*offset=*/0, NO_FIN); + creator_.Flush(); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // Make sure we already have two packets. + ASSERT_EQ(2u, packets_.size()); + + // Increase packet size. + creator_.SetMaxPacketLength(packet_len); + EXPECT_EQ(packet_len, creator_.max_packet_length()); + + // Send a packet after packet size change. + CreateData(data_len); + creator_.AttachPacketFlusher(); + consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, data_len, FIN); + creator_.Flush(); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // We expect first data chunk to get fragmented, but the second one to fit + // into a single packet. + ASSERT_EQ(3u, packets_.size()); + EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); + EXPECT_LE(kDefaultMaxPacketSize, packets_[2].encrypted_length); + CheckAllPacketsHaveSingleStreamFrame(); +} + +// Test whether SetMaxPacketLength() works correctly when we force the change of +// the packet size in the middle of the batched packet. +TEST_F(QuicPacketCreatorMultiplePacketsTest, + SetMaxPacketLength_MidpacketFlush) { + delegate_.SetCanWriteAnything(); + + size_t first_write_len = kDefaultMaxPacketSize / 2; + size_t packet_len = kDefaultMaxPacketSize + 100; + size_t second_write_len = packet_len + 1; + ASSERT_LE(packet_len, kMaxOutgoingPacketSize); + + // First send half of the packet worth of data. We are in the batch mode, so + // should not cause packet serialization. + CreateData(first_write_len); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, + /*offset=*/0, NO_FIN); + EXPECT_EQ(first_write_len, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + // Make sure we have no packets so far. + ASSERT_EQ(0u, packets_.size()); + + // Expect a packet to be flushed. + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + // Increase packet size after flushing all frames. + // Ensure it's immediately enacted. + creator_.FlushCurrentPacket(); + creator_.SetMaxPacketLength(packet_len); + EXPECT_EQ(packet_len, creator_.max_packet_length()); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // We expect to see exactly one packet serialized after that, because we send + // a value somewhat exceeding new max packet size, and the tail data does not + // get serialized because we are still in the batch mode. + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + // Send a more than a packet worth of data to the same stream. This should + // trigger serialization of one packet, and queue another one. + CreateData(second_write_len); + consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, + /*offset=*/first_write_len, FIN); + EXPECT_EQ(second_write_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + // We expect the first packet to be underfilled, and the second packet be up + // to the new max packet size. + ASSERT_EQ(2u, packets_.size()); + EXPECT_GT(kDefaultMaxPacketSize, packets_[0].encrypted_length); + EXPECT_EQ(packet_len, packets_[1].encrypted_length); + + CheckAllPacketsHaveSingleStreamFrame(); +} + +// Test sending a connectivity probing packet. +TEST_F(QuicPacketCreatorMultiplePacketsTest, + GenerateConnectivityProbingPacket) { + delegate_.SetCanWriteAnything(); + + OwningSerializedPacketPointer probing_packet; + if (VersionHasIetfQuicFrames(framer_.transport_version())) { + QuicPathFrameBuffer payload = { + {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; + probing_packet = + creator_.SerializePathChallengeConnectivityProbingPacket(&payload); + } else { + probing_packet = creator_.SerializeConnectivityProbingPacket(); + } + + ASSERT_TRUE(simple_framer_.ProcessPacket(QuicEncryptedPacket( + probing_packet->encrypted_buffer, probing_packet->encrypted_length))); + + EXPECT_EQ(2u, simple_framer_.num_frames()); + if (VersionHasIetfQuicFrames(framer_.transport_version())) { + EXPECT_EQ(1u, simple_framer_.path_challenge_frames().size()); + } else { + EXPECT_EQ(1u, simple_framer_.ping_frames().size()); + } + EXPECT_EQ(1u, simple_framer_.padding_frames().size()); +} + +// Test sending an MTU probe, without any surrounding data. +TEST_F(QuicPacketCreatorMultiplePacketsTest, + GenerateMtuDiscoveryPacket_Simple) { + delegate_.SetCanWriteAnything(); + + const size_t target_mtu = kDefaultMaxPacketSize + 100; + static_assert(target_mtu < kMaxOutgoingPacketSize, + "The MTU probe used by the test exceeds maximum packet size"); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + creator_.GenerateMtuDiscoveryPacket(target_mtu); + + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + ASSERT_EQ(1u, packets_.size()); + EXPECT_EQ(target_mtu, packets_[0].encrypted_length); + + PacketContents contents; + contents.num_mtu_discovery_frames = 1; + contents.num_padding_frames = 1; + CheckPacketContains(contents, 0); +} + +// Test sending an MTU probe. Surround it with data, to ensure that it resets +// the MTU to the value before the probe was sent. +TEST_F(QuicPacketCreatorMultiplePacketsTest, + GenerateMtuDiscoveryPacket_SurroundedByData) { + delegate_.SetCanWriteAnything(); + + const size_t target_mtu = kDefaultMaxPacketSize + 100; + static_assert(target_mtu < kMaxOutgoingPacketSize, + "The MTU probe used by the test exceeds maximum packet size"); + + // Send enough data so it would always cause two packets to be sent. + const size_t data_len = target_mtu + 1; + + // Send a total of five packets: two packets before the probe, the probe + // itself, and two packets after the probe. + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .Times(5) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + // Send data before the MTU probe. + CreateData(data_len); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, + /*offset=*/0, NO_FIN); + creator_.Flush(); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // Send the MTU probe. + creator_.GenerateMtuDiscoveryPacket(target_mtu); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + // Send data after the MTU probe. + CreateData(data_len); + creator_.AttachPacketFlusher(); + consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, + /*offset=*/data_len, FIN); + creator_.Flush(); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + ASSERT_EQ(5u, packets_.size()); + EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); + EXPECT_EQ(target_mtu, packets_[2].encrypted_length); + EXPECT_EQ(kDefaultMaxPacketSize, packets_[3].encrypted_length); + + PacketContents probe_contents; + probe_contents.num_mtu_discovery_frames = 1; + probe_contents.num_padding_frames = 1; + + CheckPacketHasSingleStreamFrame(0); + CheckPacketHasSingleStreamFrame(1); + CheckPacketContains(probe_contents, 2); + CheckPacketHasSingleStreamFrame(3); + CheckPacketHasSingleStreamFrame(4); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, DontCrashOnInvalidStopWaiting) { + if (VersionSupportsMessageFrames(framer_.transport_version())) { + return; + } + // Test added to ensure the creator does not crash when an invalid frame is + // added. Because this is an indication of internal programming errors, + // DFATALs are expected. + // A 1 byte packet number length can't encode a gap of 1000. + QuicPacketCreatorPeer::SetPacketNumber(&creator_, 1000); + + delegate_.SetCanNotWrite(); + delegate_.SetCanWriteAnything(); + + // This will not serialize any packets, because of the invalid frame. + EXPECT_CALL(delegate_, + OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _)); + EXPECT_QUIC_BUG(creator_.Flush(), + "packet_number_length 1 is too small " + "for least_unacked_delta: 1001"); +} + +// Regression test for b/31486443. +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConnectionCloseFrameLargerThanPacketSize) { + delegate_.SetCanWriteAnything(); + char buf[2000] = {}; + QuicStringPiece error_details(buf, 2000); + const QuicErrorCode kQuicErrorCode = QUIC_PACKET_WRITE_ERROR; + + QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame( + framer_.transport_version(), kQuicErrorCode, std::string(error_details), + /*transport_close_frame_type=*/0); + creator_.ConsumeRetransmittableControlFrame(QuicFrame(frame), + /*bundle_ack=*/false); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + RandomPaddingAfterFinSingleStreamSinglePacket) { + const QuicByteCount kStreamFramePayloadSize = 100u; + char buf[kStreamFramePayloadSize] = {}; + const QuicStreamId kDataStreamId = 5; + // Set the packet size be enough for one stream frame with 0 stream offset and + // max size of random padding. + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_.GetDestinationConnectionIdLength(), + creator_.GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(&creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(&creator_)) + + QuicFramer::GetMinStreamFrameSize( + framer_.transport_version(), kDataStreamId, 0, + /*last_frame_in_packet=*/false, + kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) + + kStreamFramePayloadSize + kMaxNumRandomPaddingBytes; + creator_.SetMaxPacketLength(length); + delegate_.SetCanWriteAnything(); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); + creator_.Flush(); + EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + EXPECT_EQ(1u, packets_.size()); + PacketContents contents; + // The packet has both stream and padding frames. + contents.num_padding_frames = 1; + contents.num_stream_frames = 1; + CheckPacketContains(contents, 0); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + RandomPaddingAfterFinSingleStreamMultiplePackets) { + const QuicByteCount kStreamFramePayloadSize = 100u; + char buf[kStreamFramePayloadSize] = {}; + const QuicStreamId kDataStreamId = 5; + // Set the packet size be enough for one stream frame with 0 stream offset + + // 1. One or more packets will accommodate. + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_.GetDestinationConnectionIdLength(), + creator_.GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(&creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(&creator_)) + + QuicFramer::GetMinStreamFrameSize( + framer_.transport_version(), kDataStreamId, 0, + /*last_frame_in_packet=*/false, kStreamFramePayloadSize + 1) + + kStreamFramePayloadSize + 1; + creator_.SetMaxPacketLength(length); + delegate_.SetCanWriteAnything(); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); + creator_.Flush(); + EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + EXPECT_LE(1u, packets_.size()); + PacketContents contents; + // The first packet has both stream and padding frames. + contents.num_stream_frames = 1; + contents.num_padding_frames = 1; + CheckPacketContains(contents, 0); + + for (size_t i = 1; i < packets_.size(); ++i) { + // Following packets only have paddings. + contents.num_stream_frames = 0; + contents.num_padding_frames = 1; + CheckPacketContains(contents, i); + } +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + RandomPaddingAfterFinMultipleStreamsMultiplePackets) { + const QuicByteCount kStreamFramePayloadSize = 100u; + char buf[kStreamFramePayloadSize] = {}; + const QuicStreamId kDataStreamId1 = 5; + const QuicStreamId kDataStreamId2 = 6; + // Set the packet size be enough for first frame with 0 stream offset + second + // frame + 1 byte payload. two or more packets will accommodate. + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_.GetDestinationConnectionIdLength(), + creator_.GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(&creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(&creator_)) + + QuicFramer::GetMinStreamFrameSize( + framer_.transport_version(), kDataStreamId1, 0, + /*last_frame_in_packet=*/false, kStreamFramePayloadSize) + + kStreamFramePayloadSize + + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), + kDataStreamId1, 0, + /*last_frame_in_packet=*/false, 1) + + 1; + creator_.SetMaxPacketLength(length); + delegate_.SetCanWriteAnything(); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillRepeatedly( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); + QuicConsumedData consumed = creator_.ConsumeData( + kDataStreamId1, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); + EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); + MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); + consumed = creator_.ConsumeData(kDataStreamId2, &iov_, 1u, iov_.iov_len, 0, + FIN_AND_PADDING); + EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); + creator_.Flush(); + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + + EXPECT_LE(2u, packets_.size()); + PacketContents contents; + // The first packet has two stream frames. + contents.num_stream_frames = 2; + CheckPacketContains(contents, 0); + + // The second packet has one stream frame and padding frames. + contents.num_stream_frames = 1; + contents.num_padding_frames = 1; + CheckPacketContains(contents, 1); + + for (size_t i = 2; i < packets_.size(); ++i) { + // Following packets only have paddings. + contents.num_stream_frames = 0; + contents.num_padding_frames = 1; + CheckPacketContains(contents, i); + } +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, AddMessageFrame) { + if (!VersionSupportsMessageFrames(framer_.transport_version())) { + return; + } + quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); + delegate_.SetCanWriteAnything(); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + + MakeIOVector("foo", &iov_); + creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId( + framer_.transport_version(), Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ( + MESSAGE_STATUS_SUCCESS, + creator_.AddMessageFrame(1, MakeSpan(&allocator_, "message", &storage))); + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + // Add a message which causes the flush of current packet. + EXPECT_EQ( + MESSAGE_STATUS_SUCCESS, + creator_.AddMessageFrame( + 2, + MakeSpan(&allocator_, + std::string(creator_.GetCurrentLargestMessagePayload(), 'a'), + &storage))); + EXPECT_TRUE(creator_.HasPendingRetransmittableFrames()); + + // Failed to send messages which cannot fit into one packet. + EXPECT_EQ( + MESSAGE_STATUS_TOO_LARGE, + creator_.AddMessageFrame( + 3, MakeSpan(&allocator_, + std::string( + creator_.GetCurrentLargestMessagePayload() + 10, 'a'), + &storage))); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, ConnectionId) { + creator_.SetServerConnectionId(TestConnectionId(0x1337)); + EXPECT_EQ(TestConnectionId(0x1337), creator_.GetDestinationConnectionId()); + EXPECT_EQ(EmptyQuicConnectionId(), creator_.GetSourceConnectionId()); + if (!framer_.version().SupportsClientConnectionIds()) { + return; + } + creator_.SetClientConnectionId(TestConnectionId(0x33)); + EXPECT_EQ(TestConnectionId(0x1337), creator_.GetDestinationConnectionId()); + EXPECT_EQ(TestConnectionId(0x33), creator_.GetSourceConnectionId()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc deleted file mode 100644 index fbb7894d0da..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc +++ /dev/null @@ -1,556 +0,0 @@ -// Copyright (c) 2012 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 "net/third_party/quiche/src/quic/core/quic_packet_generator.h" - -#include - -#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" -#include "net/third_party/quiche/src/quic/core/quic_connection_id.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" -#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" -#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h" - -namespace quic { - -QuicPacketGenerator::QuicPacketGenerator( - QuicConnectionId server_connection_id, - QuicFramer* framer, - QuicRandom* random_generator, - QuicPacketCreator::DelegateInterface* delegate) - : delegate_(delegate), - packet_creator_(server_connection_id, framer, random_generator, delegate), - next_transmission_type_(NOT_RETRANSMISSION), - flusher_attached_(false), - random_generator_(random_generator), - fully_pad_crypto_handshake_packets_(true) {} - -QuicPacketGenerator::~QuicPacketGenerator() {} - -bool QuicPacketGenerator::ConsumeRetransmittableControlFrame( - const QuicFrame& frame) { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.ConsumeRetransmittableControlFrame(frame); - } - QUIC_BUG_IF(IsControlFrame(frame.type) && !GetControlFrameId(frame)) - << "Adding a control frame with no control frame id: " << frame; - DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) << frame; - MaybeBundleAckOpportunistically(); - if (packet_creator_.HasPendingFrames()) { - if (packet_creator_.AddSavedFrame(frame, next_transmission_type_)) { - // There is pending frames and current frame fits. - return true; - } - } - DCHECK(!packet_creator_.HasPendingFrames()); - if (frame.type != PING_FRAME && frame.type != CONNECTION_CLOSE_FRAME && - !delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - // Do not check congestion window for ping or connection close frames. - return false; - } - const bool success = - packet_creator_.AddSavedFrame(frame, next_transmission_type_); - DCHECK(success); - return success; -} - -size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level, - size_t write_length, - QuicStreamOffset offset) { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.ConsumeCryptoData(level, write_length, offset); - } - QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " - "generator tries to write crypto data."; - MaybeBundleAckOpportunistically(); - // To make reasoning about crypto frames easier, we don't combine them with - // other retransmittable frames in a single packet. - // TODO(nharper): Once we have separate packet number spaces, everything - // should be driven by encryption level, and we should stop flushing in this - // spot. - if (packet_creator_.HasPendingRetransmittableFrames()) { - packet_creator_.FlushCurrentPacket(); - } - - size_t total_bytes_consumed = 0; - - while (total_bytes_consumed < write_length) { - QuicFrame frame; - if (!packet_creator_.ConsumeCryptoDataToFillCurrentPacket( - level, write_length - total_bytes_consumed, - offset + total_bytes_consumed, fully_pad_crypto_handshake_packets_, - next_transmission_type_, &frame)) { - // The only pending data in the packet is non-retransmittable frames. I'm - // assuming here that they won't occupy so much of the packet that a - // CRYPTO frame won't fit. - QUIC_BUG << "Failed to ConsumeCryptoData at level " << level; - return 0; - } - total_bytes_consumed += frame.crypto_frame->data_length; - - // TODO(ianswett): Move to having the creator flush itself when it's full. - packet_creator_.FlushCurrentPacket(); - } - - // Don't allow the handshake to be bundled with other retransmittable frames. - packet_creator_.FlushCurrentPacket(); - - return total_bytes_consumed; -} - -QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state) { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.ConsumeData(id, write_length, offset, state); - } - QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " - "generator tries to write stream data."; - bool has_handshake = - QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id); - MaybeBundleAckOpportunistically(); - bool fin = state != NO_FIN; - QUIC_BUG_IF(has_handshake && fin) - << "Handshake packets should never send a fin"; - // To make reasoning about crypto frames easier, we don't combine them with - // other retransmittable frames in a single packet. - if (has_handshake && packet_creator_.HasPendingRetransmittableFrames()) { - packet_creator_.FlushCurrentPacket(); - } - - size_t total_bytes_consumed = 0; - bool fin_consumed = false; - - if (!packet_creator_.HasRoomForStreamFrame(id, offset, write_length)) { - packet_creator_.FlushCurrentPacket(); - } - - if (!fin && (write_length == 0)) { - QUIC_BUG << "Attempt to consume empty data without FIN."; - return QuicConsumedData(0, false); - } - // We determine if we can enter the fast path before executing - // the slow path loop. - bool run_fast_path = - !has_handshake && state != FIN_AND_PADDING && !HasPendingFrames() && - write_length - total_bytes_consumed > kMaxOutgoingPacketSize; - - while (!run_fast_path && delegate_->ShouldGeneratePacket( - HAS_RETRANSMITTABLE_DATA, - has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) { - QuicFrame frame; - bool needs_full_padding = - has_handshake && fully_pad_crypto_handshake_packets_; - - if (!packet_creator_.ConsumeDataToFillCurrentPacket( - id, write_length - total_bytes_consumed, - offset + total_bytes_consumed, fin, needs_full_padding, - next_transmission_type_, &frame)) { - // The creator is always flushed if there's not enough room for a new - // stream frame before ConsumeData, so ConsumeData should always succeed. - QUIC_BUG << "Failed to ConsumeData, stream:" << id; - return QuicConsumedData(0, false); - } - - // A stream frame is created and added. - size_t bytes_consumed = frame.stream_frame.data_length; - total_bytes_consumed += bytes_consumed; - fin_consumed = fin && total_bytes_consumed == write_length; - if (fin_consumed && state == FIN_AND_PADDING) { - AddRandomPadding(); - } - DCHECK(total_bytes_consumed == write_length || - (bytes_consumed > 0 && packet_creator_.HasPendingFrames())); - - if (total_bytes_consumed == write_length) { - // We're done writing the data. Exit the loop. - // We don't make this a precondition because we could have 0 bytes of data - // if we're simply writing a fin. - break; - } - // TODO(ianswett): Move to having the creator flush itself when it's full. - packet_creator_.FlushCurrentPacket(); - - run_fast_path = - !has_handshake && state != FIN_AND_PADDING && !HasPendingFrames() && - write_length - total_bytes_consumed > kMaxOutgoingPacketSize; - } - - if (run_fast_path) { - return ConsumeDataFastPath(id, write_length, offset, state != NO_FIN, - total_bytes_consumed); - } - - // Don't allow the handshake to be bundled with other retransmittable frames. - if (has_handshake) { - packet_creator_.FlushCurrentPacket(); - } - - return QuicConsumedData(total_bytes_consumed, fin_consumed); -} - -QuicConsumedData QuicPacketGenerator::ConsumeDataFastPath( - QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - bool fin, - size_t total_bytes_consumed) { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.ConsumeDataFastPath(id, write_length, offset, fin, - total_bytes_consumed); - } - DCHECK(!QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id)); - - while (total_bytes_consumed < write_length && - delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - // Serialize and encrypt the packet. - size_t bytes_consumed = 0; - packet_creator_.CreateAndSerializeStreamFrame( - id, write_length, total_bytes_consumed, offset + total_bytes_consumed, - fin, next_transmission_type_, &bytes_consumed); - total_bytes_consumed += bytes_consumed; - } - - return QuicConsumedData(total_bytes_consumed, - fin && (total_bytes_consumed == write_length)); -} - -void QuicPacketGenerator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.GenerateMtuDiscoveryPacket(target_mtu); - return; - } - // MTU discovery frames must be sent by themselves. - if (!packet_creator_.CanSetMaxPacketLength()) { - QUIC_BUG << "MTU discovery packets should only be sent when no other " - << "frames needs to be sent."; - return; - } - const QuicByteCount current_mtu = GetCurrentMaxPacketLength(); - - // The MTU discovery frame is allocated on the stack, since it is going to be - // serialized within this function. - QuicMtuDiscoveryFrame mtu_discovery_frame; - QuicFrame frame(mtu_discovery_frame); - - // Send the probe packet with the new length. - SetMaxPacketLength(target_mtu); - const bool success = - packet_creator_.AddPaddedSavedFrame(frame, next_transmission_type_); - packet_creator_.FlushCurrentPacket(); - // The only reason AddFrame can fail is that the packet is too full to fit in - // a ping. This is not possible for any sane MTU. - DCHECK(success); - - // Reset the packet length back. - SetMaxPacketLength(current_mtu); -} - -bool QuicPacketGenerator::PacketFlusherAttached() const { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.PacketFlusherAttached(); - } - return flusher_attached_; -} - -void QuicPacketGenerator::AttachPacketFlusher() { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.AttachPacketFlusher(); - return; - } - flusher_attached_ = true; - if (!write_start_packet_number_.IsInitialized()) { - write_start_packet_number_ = packet_creator_.NextSendingPacketNumber(); - } -} - -void QuicPacketGenerator::Flush() { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.Flush(); - return; - } - packet_creator_.FlushCurrentPacket(); - SendRemainingPendingPadding(); - flusher_attached_ = false; - if (GetQuicFlag(FLAGS_quic_export_server_num_packets_per_write_histogram)) { - if (!write_start_packet_number_.IsInitialized()) { - QUIC_BUG << "write_start_packet_number is not initialized"; - return; - } - QUIC_SERVER_HISTOGRAM_COUNTS( - "quic_server_num_written_packets_per_write", - packet_creator_.NextSendingPacketNumber() - write_start_packet_number_, - 1, 200, 50, "Number of QUIC packets written per write operation"); - } - write_start_packet_number_.Clear(); -} - -void QuicPacketGenerator::FlushAllQueuedFrames() { - packet_creator_.FlushCurrentPacket(); -} - -bool QuicPacketGenerator::HasPendingFrames() const { - return packet_creator_.HasPendingFrames(); -} - -void QuicPacketGenerator::StopSendingVersion() { - packet_creator_.StopSendingVersion(); -} - -void QuicPacketGenerator::SetDiversificationNonce( - const DiversificationNonce& nonce) { - packet_creator_.SetDiversificationNonce(nonce); -} - -QuicPacketNumber QuicPacketGenerator::packet_number() const { - return packet_creator_.packet_number(); -} - -QuicByteCount QuicPacketGenerator::GetCurrentMaxPacketLength() const { - return packet_creator_.max_packet_length(); -} - -void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) { - DCHECK(packet_creator_.CanSetMaxPacketLength()); - packet_creator_.SetMaxPacketLength(length); -} - -std::unique_ptr -QuicPacketGenerator::SerializeVersionNegotiationPacket( - bool ietf_quic, - bool use_length_prefix, - const ParsedQuicVersionVector& supported_versions) { - return packet_creator_.SerializeVersionNegotiationPacket( - ietf_quic, use_length_prefix, supported_versions); -} - -OwningSerializedPacketPointer -QuicPacketGenerator::SerializeConnectivityProbingPacket() { - return packet_creator_.SerializeConnectivityProbingPacket(); -} - -OwningSerializedPacketPointer -QuicPacketGenerator::SerializePathChallengeConnectivityProbingPacket( - QuicPathFrameBuffer* payload) { - return packet_creator_.SerializePathChallengeConnectivityProbingPacket( - payload); -} - -OwningSerializedPacketPointer -QuicPacketGenerator::SerializePathResponseConnectivityProbingPacket( - const QuicDeque& payloads, - const bool is_padded) { - return packet_creator_.SerializePathResponseConnectivityProbingPacket( - payloads, is_padded); -} - -void QuicPacketGenerator::ReserializeAllFrames( - const QuicPendingRetransmission& retransmission, - char* buffer, - size_t buffer_len) { - packet_creator_.ReserializeAllFrames(retransmission, buffer, buffer_len); -} - -void QuicPacketGenerator::UpdatePacketNumberLength( - QuicPacketNumber least_packet_awaited_by_peer, - QuicPacketCount max_packets_in_flight) { - return packet_creator_.UpdatePacketNumberLength(least_packet_awaited_by_peer, - max_packets_in_flight); -} - -void QuicPacketGenerator::SkipNPacketNumbers( - QuicPacketCount count, - QuicPacketNumber least_packet_awaited_by_peer, - QuicPacketCount max_packets_in_flight) { - packet_creator_.SkipNPacketNumbers(count, least_packet_awaited_by_peer, - max_packets_in_flight); -} - -void QuicPacketGenerator::SetServerConnectionIdLength(uint32_t length) { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.SetServerConnectionIdLength(length); - return; - } - if (length == 0) { - packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_ABSENT); - } else { - packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_PRESENT); - } -} - -void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) { - packet_creator_.set_encryption_level(level); -} - -void QuicPacketGenerator::SetEncrypter( - EncryptionLevel level, - std::unique_ptr encrypter) { - packet_creator_.SetEncrypter(level, std::move(encrypter)); -} - -void QuicPacketGenerator::AddRandomPadding() { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.AddRandomPadding(); - return; - } - packet_creator_.AddPendingPadding( - random_generator_->RandUint64() % kMaxNumRandomPaddingBytes + 1); -} - -void QuicPacketGenerator::SendRemainingPendingPadding() { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.SendRemainingPendingPadding(); - return; - } - while ( - packet_creator_.pending_padding_bytes() > 0 && !HasPendingFrames() && - delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) { - packet_creator_.FlushCurrentPacket(); - } -} - -bool QuicPacketGenerator::HasRetransmittableFrames() const { - return packet_creator_.HasPendingRetransmittableFrames(); -} - -bool QuicPacketGenerator::HasPendingStreamFramesOfStream( - QuicStreamId id) const { - return packet_creator_.HasPendingStreamFramesOfStream(id); -} - -void QuicPacketGenerator::SetTransmissionType(TransmissionType type) { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.SetTransmissionType(type); - return; - } - packet_creator_.SetTransmissionTypeOfNextPackets(type); - if (packet_creator_.can_set_transmission_type()) { - next_transmission_type_ = type; - } -} - -void QuicPacketGenerator::SetRetryToken(QuicStringPiece retry_token) { - packet_creator_.SetRetryToken(retry_token); -} - -void QuicPacketGenerator::SetCanSetTransmissionType( - bool can_set_transmission_type) { - packet_creator_.set_can_set_transmission_type(can_set_transmission_type); -} - -MessageStatus QuicPacketGenerator::AddMessageFrame(QuicMessageId message_id, - QuicMemSliceSpan message) { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.AddMessageFrame(message_id, message); - } - QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " - "generator tries to add message frame."; - MaybeBundleAckOpportunistically(); - const QuicByteCount message_length = message.total_length(); - if (message_length > GetCurrentLargestMessagePayload()) { - return MESSAGE_STATUS_TOO_LARGE; - } - if (!packet_creator_.HasRoomForMessageFrame(message_length)) { - packet_creator_.FlushCurrentPacket(); - } - QuicMessageFrame* frame = new QuicMessageFrame(message_id, message); - const bool success = - packet_creator_.AddSavedFrame(QuicFrame(frame), next_transmission_type_); - if (!success) { - QUIC_BUG << "Failed to send message " << message_id; - delete frame; - return MESSAGE_STATUS_INTERNAL_ERROR; - } - return MESSAGE_STATUS_SUCCESS; -} - -void QuicPacketGenerator::MaybeBundleAckOpportunistically() { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.MaybeBundleAckOpportunistically(); - return; - } - if (packet_creator_.has_ack()) { - // Ack already queued, nothing to do. - return; - } - if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - return; - } - const bool flushed = - FlushAckFrame(delegate_->MaybeBundleAckOpportunistically()); - DCHECK(flushed); -} - -bool QuicPacketGenerator::FlushAckFrame(const QuicFrames& frames) { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.FlushAckFrame(frames); - } - QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " - "generator tries to send ACK frame."; - for (const auto& frame : frames) { - DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME); - if (packet_creator_.HasPendingFrames()) { - if (packet_creator_.AddSavedFrame(frame, next_transmission_type_)) { - // There is pending frames and current frame fits. - continue; - } - } - DCHECK(!packet_creator_.HasPendingFrames()); - // There is no pending frames, consult the delegate whether a packet can be - // generated. - if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - return false; - } - const bool success = - packet_creator_.AddSavedFrame(frame, next_transmission_type_); - QUIC_BUG_IF(!success) << "Failed to flush " << frame; - } - return true; -} - -QuicPacketLength QuicPacketGenerator::GetCurrentLargestMessagePayload() const { - return packet_creator_.GetCurrentLargestMessagePayload(); -} - -QuicPacketLength QuicPacketGenerator::GetGuaranteedLargestMessagePayload() - const { - return packet_creator_.GetGuaranteedLargestMessagePayload(); -} - -void QuicPacketGenerator::SetServerConnectionId( - QuicConnectionId server_connection_id) { - packet_creator_.SetServerConnectionId(server_connection_id); -} - -void QuicPacketGenerator::SetClientConnectionId( - QuicConnectionId client_connection_id) { - packet_creator_.SetClientConnectionId(client_connection_id); -} - -void QuicPacketGenerator::set_fully_pad_crypto_handshake_packets( - bool new_value) { - if (packet_creator_.combine_generator_and_creator()) { - packet_creator_.set_fully_pad_crypto_handshake_packets(new_value); - return; - } - fully_pad_crypto_handshake_packets_ = new_value; -} - -bool QuicPacketGenerator::fully_pad_crypto_handshake_packets() const { - if (packet_creator_.combine_generator_and_creator()) { - return packet_creator_.fully_pad_crypto_handshake_packets(); - } - return fully_pad_crypto_handshake_packets_; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h deleted file mode 100644 index 7d8df7e778e..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) 2012 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. - -// Responsible for generating packets on behalf of a QuicConnection. -// Packets are serialized just-in-time. -// Ack and Feedback frames will be requested from the Connection -// just-in-time. When a packet needs to be sent, the Generator -// will serialize a packet and pass it to QuicConnection::SendOrQueuePacket() -// -// The Generator's mode of operation is controlled by two conditions: -// -// 1) Is the Delegate writable? -// -// If the Delegate is not writable, then no operations will cause -// a packet to be serialized. In particular: -// * SetShouldSendAck will simply record that an ack is to be sent. -// * AddControlFrame will enqueue the control frame. -// * ConsumeData will do nothing. -// -// If the Delegate is writable, then the behavior depends on the second -// condition: -// -// 2) Is the Generator in batch mode? -// -// If the Generator is NOT in batch mode, then each call to a write -// operation will serialize one or more packets. The contents will -// include any previous queued frames. If an ack should be sent -// but has not been sent, then the Delegate will be asked to create -// an Ack frame which will then be included in the packet. When -// the write call completes, the current packet will be serialized -// and sent to the Delegate, even if it is not full. -// -// If the Generator is in batch mode, then each write operation will -// add data to the "current" packet. When the current packet becomes -// full, it will be serialized and sent to the packet. When batch -// mode is ended via |FinishBatchOperations|, the current packet -// will be serialzied, even if it is not full. - -#ifndef QUICHE_QUIC_CORE_QUIC_PACKET_GENERATOR_H_ -#define QUICHE_QUIC_CORE_QUIC_PACKET_GENERATOR_H_ - -#include -#include -#include - -#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h" -#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.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_mem_slice_span.h" - -namespace quic { - -namespace test { -class QuicPacketGeneratorPeer; -} // namespace test - -class QUIC_EXPORT_PRIVATE QuicPacketGenerator { - public: - QuicPacketGenerator(QuicConnectionId server_connection_id, - QuicFramer* framer, - QuicRandom* random_generator, - QuicPacketCreator::DelegateInterface* delegate); - QuicPacketGenerator(const QuicPacketGenerator&) = delete; - QuicPacketGenerator& operator=(const QuicPacketGenerator&) = delete; - - ~QuicPacketGenerator(); - - // Consumes retransmittable control |frame|. Returns true if the frame is - // successfully consumed. Returns false otherwise. - bool ConsumeRetransmittableControlFrame(const QuicFrame& frame); - - // Given some data, may consume part or all of it and pass it to the - // packet creator to be serialized into packets. If not in batch - // mode, these packets will also be sent during this call. - // When |state| is FIN_AND_PADDING, random padding of size [1, 256] will be - // added after stream frames. If current constructed packet cannot - // accommodate, the padding will overflow to the next packet(s). - QuicConsumedData ConsumeData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state); - - // Consumes data for CRYPTO frames sent at |level| starting at |offset| for a - // total of |write_length| bytes, and returns the number of bytes consumed. - // The data is passed into the packet creator and serialized into one or more - // packets. - size_t ConsumeCryptoData(EncryptionLevel level, - size_t write_length, - QuicStreamOffset offset); - - // Sends as many data only packets as allowed by the send algorithm and the - // available iov. - // This path does not support padding, or bundling pending frames. - // In case we access this method from ConsumeData, total_bytes_consumed - // keeps track of how many bytes have already been consumed. - QuicConsumedData ConsumeDataFastPath(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - bool fin, - size_t total_bytes_consumed); - - // Generates an MTU discovery packet of specified size. - void GenerateMtuDiscoveryPacket(QuicByteCount target_mtu); - - // Indicates whether packet flusher is currently attached. - bool PacketFlusherAttached() const; - // Attaches packet flusher. - void AttachPacketFlusher(); - // Flushes everything, including current open packet and pending padding. - void Flush(); - - // Flushes current open packet. - void FlushAllQueuedFrames(); - - // Returns true if there are frames pending to be serialized. - bool HasPendingFrames() const; - - // Makes the framer not serialize the protocol version in sent packets. - void StopSendingVersion(); - - // SetDiversificationNonce sets the nonce that will be sent in each public - // header of packets encrypted at the initial encryption level. Should only - // be called by servers. - void SetDiversificationNonce(const DiversificationNonce& nonce); - - // Creates a version negotiation packet which supports |supported_versions|. - std::unique_ptr SerializeVersionNegotiationPacket( - bool ietf_quic, - bool use_length_prefix, - const ParsedQuicVersionVector& supported_versions); - - // Creates a connectivity probing packet. - OwningSerializedPacketPointer SerializeConnectivityProbingPacket(); - - // Create connectivity probing request and response packets using PATH - // CHALLENGE and PATH RESPONSE frames, respectively. - // SerializePathChallengeConnectivityProbingPacket will pad the packet to be - // MTU bytes long. - OwningSerializedPacketPointer SerializePathChallengeConnectivityProbingPacket( - QuicPathFrameBuffer* payload); - - // If |is_padded| is true then SerializePathResponseConnectivityProbingPacket - // will pad the packet to be MTU bytes long, else it will not pad the packet. - // |payloads| is cleared. - OwningSerializedPacketPointer SerializePathResponseConnectivityProbingPacket( - const QuicDeque& payloads, - const bool is_padded); - - // Re-serializes frames with the original packet's packet number length. - // Used for retransmitting packets to ensure they aren't too long. - void ReserializeAllFrames(const QuicPendingRetransmission& retransmission, - char* buffer, - size_t buffer_len); - - // Update the packet number length to use in future packets as soon as it - // can be safely changed. - void UpdatePacketNumberLength(QuicPacketNumber least_packet_awaited_by_peer, - QuicPacketCount max_packets_in_flight); - - // Skip |count| packet numbers. - void SkipNPacketNumbers(QuicPacketCount count, - QuicPacketNumber least_packet_awaited_by_peer, - QuicPacketCount max_packets_in_flight); - - // Set the minimum number of bytes for the server connection id length; - void SetServerConnectionIdLength(uint32_t length); - - // Sets the encrypter to use for the encryption level. - void SetEncrypter(EncryptionLevel level, - std::unique_ptr encrypter); - - // Returns true if there are control frames or current constructed packet has - // pending retransmittable frames. - bool HasRetransmittableFrames() const; - - // Returns true if current constructed packet has pending stream frames for - // stream |id|. - bool HasPendingStreamFramesOfStream(QuicStreamId id) const; - - // Sets the encryption level that will be applied to new packets. - void set_encryption_level(EncryptionLevel level); - - // packet number of the last created packet, or 0 if no packets have been - // created. - QuicPacketNumber packet_number() const; - - // Returns the maximum length a current packet can actually have. - QuicByteCount GetCurrentMaxPacketLength() const; - - // Set maximum packet length in the creator immediately. May not be called - // when there are frames queued in the creator. - void SetMaxPacketLength(QuicByteCount length); - - // Set transmission type of next constructed packets. - void SetTransmissionType(TransmissionType type); - - // Sets the retry token to be sent over the wire in IETF Initial packets. - void SetRetryToken(QuicStringPiece retry_token); - - // Allow/Disallow setting transmission type of next constructed packets. - void SetCanSetTransmissionType(bool can_set_transmission_type); - - // Tries to add a message frame containing |message| and returns the status. - MessageStatus AddMessageFrame(QuicMessageId message_id, - QuicMemSliceSpan message); - - // Called to flush ACK and STOP_WAITING frames, returns false if the flush - // fails. - bool FlushAckFrame(const QuicFrames& frames); - - // Returns the largest payload that will fit into a single MESSAGE frame. - QuicPacketLength GetCurrentLargestMessagePayload() const; - QuicPacketLength GetGuaranteedLargestMessagePayload() const; - - // Update the server connection ID used in outgoing packets. - void SetServerConnectionId(QuicConnectionId server_connection_id); - - // Update the client connection ID used in outgoing packets. - void SetClientConnectionId(QuicConnectionId client_connection_id); - - void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) { - packet_creator_.set_debug_delegate(debug_delegate); - } - - void set_fully_pad_crypto_handshake_packets(bool new_value); - - bool fully_pad_crypto_handshake_packets() const; - - private: - friend class test::QuicPacketGeneratorPeer; - - // Adds a random amount of padding (between 1 to 256 bytes). - void AddRandomPadding(); - - // Sends remaining pending padding. - // Pending paddings should only be sent when there is nothing else to send. - void SendRemainingPendingPadding(); - - // Called when there is data to be sent, Retrieves updated ACK frame from - // delegate_ and flushes it. - void MaybeBundleAckOpportunistically(); - - QuicPacketCreator::DelegateInterface* delegate_; - - QuicPacketCreator packet_creator_; - - // Transmission type of the next serialized packet. - TransmissionType next_transmission_type_; - - // True if packet flusher is currently attached. - bool flusher_attached_; - - QuicRandom* random_generator_; - - // Whether crypto handshake packets should be fully padded. - bool fully_pad_crypto_handshake_packets_; - - // Packet number of the first packet of a write operation. This gets set - // when the out-most flusher attaches and gets cleared when the out-most - // flusher detaches. - QuicPacketNumber write_start_packet_number_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QUIC_PACKET_GENERATOR_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc deleted file mode 100644 index b098958cb52..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc +++ /dev/null @@ -1,1512 +0,0 @@ -// Copyright (c) 2012 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 "net/third_party/quiche/src/quic/core/quic_packet_generator.h" - -#include -#include -#include -#include - -#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.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" -#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.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_piece.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.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/quic_packet_creator_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_packet_generator_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" - -using testing::_; -using testing::InSequence; -using testing::Return; -using testing::StrictMock; - -namespace quic { -namespace test { -namespace { - -class MockDelegate : public QuicPacketCreator::DelegateInterface { - public: - MockDelegate() {} - MockDelegate(const MockDelegate&) = delete; - MockDelegate& operator=(const MockDelegate&) = delete; - ~MockDelegate() override {} - - MOCK_METHOD2(ShouldGeneratePacket, - bool(HasRetransmittableData retransmittable, - IsHandshake handshake)); - MOCK_METHOD0(MaybeBundleAckOpportunistically, const QuicFrames()); - MOCK_METHOD0(GetPacketBuffer, char*()); - MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); - MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&)); - - void SetCanWriteAnything() { - EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true)); - EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _)) - .WillRepeatedly(Return(true)); - } - - void SetCanNotWrite() { - EXPECT_CALL(*this, ShouldGeneratePacket(_, _)) - .WillRepeatedly(Return(false)); - EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _)) - .WillRepeatedly(Return(false)); - } - - // Use this when only ack frames should be allowed to be written. - void SetCanWriteOnlyNonRetransmittable() { - EXPECT_CALL(*this, ShouldGeneratePacket(_, _)) - .WillRepeatedly(Return(false)); - EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _)) - .WillRepeatedly(Return(true)); - } -}; - -// Simple struct for describing the contents of a packet. -// Useful in conjunction with a SimpleQuicFrame for validating that a packet -// contains the expected frames. -struct PacketContents { - PacketContents() - : num_ack_frames(0), - num_connection_close_frames(0), - num_goaway_frames(0), - num_rst_stream_frames(0), - num_stop_waiting_frames(0), - num_stream_frames(0), - num_crypto_frames(0), - num_ping_frames(0), - num_mtu_discovery_frames(0), - num_padding_frames(0) {} - - size_t num_ack_frames; - size_t num_connection_close_frames; - size_t num_goaway_frames; - size_t num_rst_stream_frames; - size_t num_stop_waiting_frames; - size_t num_stream_frames; - size_t num_crypto_frames; - size_t num_ping_frames; - size_t num_mtu_discovery_frames; - size_t num_padding_frames; -}; - -} // namespace - -class TestPacketGenerator : public QuicPacketGenerator { - public: - TestPacketGenerator(QuicConnectionId connection_id, - QuicFramer* framer, - QuicRandom* random_generator, - QuicPacketCreator::DelegateInterface* delegate, - SimpleDataProducer* producer) - : QuicPacketGenerator(connection_id, framer, random_generator, delegate), - ack_frame_(InitAckFrame(1)), - delegate_(static_cast(delegate)), - producer_(producer) {} - - bool ConsumeRetransmittableControlFrame(const QuicFrame& frame, - bool bundle_ack) { - if (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack()) { - QuicFrames frames; - if (bundle_ack) { - frames.push_back(QuicFrame(&ack_frame_)); - } - if (delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()) - .WillOnce(Return(frames)); - } - } - return QuicPacketGenerator::ConsumeRetransmittableControlFrame(frame); - } - - QuicConsumedData ConsumeDataFastPath(QuicStreamId id, - const struct iovec* iov, - int iov_count, - size_t total_length, - QuicStreamOffset offset, - bool fin) { - // Save data before data is consumed. - if (total_length > 0) { - producer_->SaveStreamData(id, iov, iov_count, 0, total_length); - } - return QuicPacketGenerator::ConsumeDataFastPath(id, total_length, offset, - fin, 0); - } - - QuicConsumedData ConsumeData(QuicStreamId id, - const struct iovec* iov, - int iov_count, - size_t total_length, - QuicStreamOffset offset, - StreamSendingState state) { - // Save data before data is consumed. - if (total_length > 0) { - producer_->SaveStreamData(id, iov, iov_count, 0, total_length); - } - if (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack() && - delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); - } - return QuicPacketGenerator::ConsumeData(id, total_length, offset, state); - } - - MessageStatus AddMessageFrame(QuicMessageId message_id, - QuicMemSliceSpan message) { - if (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack() && - delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); - } - return QuicPacketGenerator::AddMessageFrame(message_id, message); - } - - size_t ConsumeCryptoData(EncryptionLevel level, - QuicStringPiece data, - QuicStreamOffset offset) { - producer_->SaveCryptoData(level, offset, data); - if (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack() && - delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) { - EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); - } - return QuicPacketGenerator::ConsumeCryptoData(level, data.length(), offset); - } - - QuicAckFrame ack_frame_; - MockDelegate* delegate_; - SimpleDataProducer* producer_; -}; - -class QuicPacketGeneratorTest : public QuicTest { - public: - QuicPacketGeneratorTest() - : framer_(AllSupportedVersions(), - QuicTime::Zero(), - Perspective::IS_CLIENT, - kQuicDefaultConnectionIdLength), - generator_(TestConnectionId(), - &framer_, - &random_generator_, - &delegate_, - &producer_), - creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)), - ack_frame_(InitAckFrame(1)) { - EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); - creator_->SetEncrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique(Perspective::IS_CLIENT)); - creator_->set_encryption_level(ENCRYPTION_FORWARD_SECURE); - framer_.set_data_producer(&producer_); - if (simple_framer_.framer()->version().KnowsWhichDecrypterToUse()) { - simple_framer_.framer()->InstallDecrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique(Perspective::IS_SERVER)); - } - generator_.AttachPacketFlusher(); - } - - ~QuicPacketGeneratorTest() override { - for (SerializedPacket& packet : packets_) { - delete[] packet.encrypted_buffer; - ClearSerializedPacket(&packet); - } - } - - void SavePacket(SerializedPacket* packet) { - packet->encrypted_buffer = CopyBuffer(*packet); - packets_.push_back(*packet); - packet->encrypted_buffer = nullptr; - packet->retransmittable_frames.clear(); - } - - protected: - QuicRstStreamFrame* CreateRstStreamFrame() { - return new QuicRstStreamFrame(1, 1, QUIC_STREAM_NO_ERROR, 0); - } - - QuicGoAwayFrame* CreateGoAwayFrame() { - return new QuicGoAwayFrame(2, QUIC_NO_ERROR, 1, std::string()); - } - - void CheckPacketContains(const PacketContents& contents, - size_t packet_index) { - ASSERT_GT(packets_.size(), packet_index); - const SerializedPacket& packet = packets_[packet_index]; - size_t num_retransmittable_frames = - contents.num_connection_close_frames + contents.num_goaway_frames + - contents.num_rst_stream_frames + contents.num_stream_frames + - contents.num_crypto_frames + contents.num_ping_frames; - size_t num_frames = - contents.num_ack_frames + contents.num_stop_waiting_frames + - contents.num_mtu_discovery_frames + contents.num_padding_frames + - num_retransmittable_frames; - - if (num_retransmittable_frames == 0) { - ASSERT_TRUE(packet.retransmittable_frames.empty()); - } else { - ASSERT_FALSE(packet.retransmittable_frames.empty()); - EXPECT_EQ(num_retransmittable_frames, - packet.retransmittable_frames.size()); - } - - ASSERT_TRUE(packet.encrypted_buffer != nullptr); - ASSERT_TRUE(simple_framer_.ProcessPacket( - QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length))); - size_t num_padding_frames = 0; - if (contents.num_padding_frames == 0) { - num_padding_frames = simple_framer_.padding_frames().size(); - } - EXPECT_EQ(num_frames + num_padding_frames, simple_framer_.num_frames()); - EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size()); - EXPECT_EQ(contents.num_connection_close_frames, - simple_framer_.connection_close_frames().size()); - EXPECT_EQ(contents.num_goaway_frames, - simple_framer_.goaway_frames().size()); - EXPECT_EQ(contents.num_rst_stream_frames, - simple_framer_.rst_stream_frames().size()); - EXPECT_EQ(contents.num_stream_frames, - simple_framer_.stream_frames().size()); - EXPECT_EQ(contents.num_crypto_frames, - simple_framer_.crypto_frames().size()); - EXPECT_EQ(contents.num_stop_waiting_frames, - simple_framer_.stop_waiting_frames().size()); - if (contents.num_padding_frames != 0) { - EXPECT_EQ(contents.num_padding_frames, - simple_framer_.padding_frames().size()); - } - - // From the receiver's perspective, MTU discovery frames are ping frames. - EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames, - simple_framer_.ping_frames().size()); - } - - void CheckPacketHasSingleStreamFrame(size_t packet_index) { - ASSERT_GT(packets_.size(), packet_index); - const SerializedPacket& packet = packets_[packet_index]; - ASSERT_FALSE(packet.retransmittable_frames.empty()); - EXPECT_EQ(1u, packet.retransmittable_frames.size()); - ASSERT_TRUE(packet.encrypted_buffer != nullptr); - ASSERT_TRUE(simple_framer_.ProcessPacket( - QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length))); - EXPECT_EQ(1u, simple_framer_.num_frames()); - EXPECT_EQ(1u, simple_framer_.stream_frames().size()); - } - - void CheckAllPacketsHaveSingleStreamFrame() { - for (size_t i = 0; i < packets_.size(); i++) { - CheckPacketHasSingleStreamFrame(i); - } - } - - void CreateData(size_t len) { - data_array_.reset(new char[len]); - memset(data_array_.get(), '?', len); - iov_.iov_base = data_array_.get(); - iov_.iov_len = len; - } - - QuicFramer framer_; - MockRandom random_generator_; - StrictMock delegate_; - TestPacketGenerator generator_; - QuicPacketCreator* creator_; - SimpleQuicFramer simple_framer_; - std::vector packets_; - QuicAckFrame ack_frame_; - struct iovec iov_; - SimpleBufferAllocator allocator_; - - private: - std::unique_ptr data_array_; - SimpleDataProducer producer_; -}; - -class MockDebugDelegate : public QuicPacketCreator::DebugDelegate { - public: - MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&)); -}; - -TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) { - delegate_.SetCanNotWrite(); - - QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); - const bool consumed = - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/false); - EXPECT_FALSE(consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - delete rst_frame; -} - -TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) { - delegate_.SetCanWriteOnlyNonRetransmittable(); - - QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); - const bool consumed = - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/false); - EXPECT_FALSE(consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - delete rst_frame; -} - -TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { - delegate_.SetCanWriteAnything(); - - generator_.ConsumeRetransmittableControlFrame( - QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); -} - -TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) { - delegate_.SetCanNotWrite(); - - QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); - const bool consumed = - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/false); - EXPECT_FALSE(consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - delete rst_frame; -} - -TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) { - delegate_.SetCanWriteAnything(); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - generator_.ConsumeRetransmittableControlFrame( - QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); - generator_.Flush(); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_rst_stream_frames = 1; - CheckPacketContains(contents, 0); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeCryptoData) { - delegate_.SetCanWriteAnything(); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - std::string data = "crypto data"; - size_t consumed_bytes = - generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); - generator_.Flush(); - EXPECT_EQ(data.length(), consumed_bytes); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_crypto_frames = 1; - contents.num_padding_frames = 1; - CheckPacketContains(contents, 0); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) { - delegate_.SetCanNotWrite(); - - MakeIOVector("foo", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - EXPECT_EQ(0u, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) { - delegate_.SetCanWriteAnything(); - - MakeIOVector("foo", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - EXPECT_EQ(3u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) { - delegate_.SetCanWriteAnything(); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector("foo", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - generator_.Flush(); - EXPECT_EQ(3u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); -} - -// Test the behavior of ConsumeData when the data consumed is for the crypto -// handshake stream. Ensure that the packet is always sent and padded even if -// the generator operates in batch mode. -TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake) { - delegate_.SetCanWriteAnything(); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - std::string data = "foo bar"; - MakeIOVector(data, &iov_); - size_t consumed_bytes = 0; - if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { - consumed_bytes = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); - } else { - consumed_bytes = - generator_ - .ConsumeData( - QuicUtils::GetCryptoStreamId(framer_.transport_version()), - &iov_, 1u, iov_.iov_len, 0, NO_FIN) - .bytes_consumed; - } - EXPECT_EQ(7u, consumed_bytes); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { - contents.num_crypto_frames = 1; - } else { - contents.num_stream_frames = 1; - } - contents.num_padding_frames = 1; - CheckPacketContains(contents, 0); - - ASSERT_EQ(1u, packets_.size()); - ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength()); - EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); -} - -// Test the behavior of ConsumeData when the data is for the crypto handshake -// stream, but padding is disabled. -TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) { - generator_.set_fully_pad_crypto_handshake_packets(false); - - delegate_.SetCanWriteAnything(); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - std::string data = "foo"; - MakeIOVector(data, &iov_); - size_t bytes_consumed = 0; - if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { - bytes_consumed = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); - } else { - bytes_consumed = - generator_ - .ConsumeData( - QuicUtils::GetCryptoStreamId(framer_.transport_version()), - &iov_, 1u, iov_.iov_len, 0, NO_FIN) - .bytes_consumed; - } - EXPECT_EQ(3u, bytes_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { - contents.num_crypto_frames = 1; - } else { - contents.num_stream_frames = 1; - } - contents.num_padding_frames = 0; - CheckPacketContains(contents, 0); - - ASSERT_EQ(1u, packets_.size()); - - // Packet is not fully padded, but we want to future packets to be larger. - ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength()); - size_t expected_packet_length = 27; - if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { - // The framing of CRYPTO frames is slightly different than that of stream - // frames, so the expected packet length differs slightly. - expected_packet_length = 28; - } - if (framer_.version().HasHeaderProtection()) { - expected_packet_length = 29; - } - EXPECT_EQ(expected_packet_length, packets_[0].encrypted_length); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) { - delegate_.SetCanWriteAnything(); - - EXPECT_QUIC_BUG(generator_.ConsumeData( - QuicUtils::QuicUtils::GetFirstBidirectionalStreamId( - framer_.transport_version(), Perspective::IS_CLIENT), - nullptr, 0, 0, 0, NO_FIN), - "Attempt to consume empty data without FIN."); -} - -TEST_F(QuicPacketGeneratorTest, - ConsumeDataMultipleTimes_WritableAndShouldNotFlush) { - delegate_.SetCanWriteAnything(); - - MakeIOVector("foo", &iov_); - generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - MakeIOVector("quux", &iov_); - QuicConsumedData consumed = - generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN); - EXPECT_EQ(4u, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) { - delegate_.SetCanWriteAnything(); - - MakeIOVector("foo", &iov_); - generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - MakeIOVector("quux", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 3, NO_FIN); - EXPECT_EQ(4u, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - // Now both frames will be flushed out. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.Flush(); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_stream_frames = 2; - CheckPacketContains(contents, 0); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) { - // Set the packet size be enough for two stream frames with 0 stream offset, - // but not enough for a stream frame of 0 offset and one with non-zero offset. - size_t length = - NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_), - QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, - QuicPacketCreatorPeer::GetLengthLength(creator_)) + - // Add an extra 3 bytes for the payload and 1 byte so - // BytesFree is larger than the GetMinStreamFrameSize. - QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, - false, 3) + - 3 + - QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, true, - 1) + - 1; - generator_.SetMaxPacketLength(length); - delegate_.SetCanWriteAnything(); - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - // Queue enough data to prevent a stream frame with a non-zero offset from - // fitting. - MakeIOVector("foo", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, NO_FIN); - EXPECT_EQ(3u, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - // This frame will not fit with the existing frame, causing the queued frame - // to be serialized, and it will be added to a new open packet. - MakeIOVector("bar", &iov_); - consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 3, FIN); - EXPECT_EQ(3u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - creator_->FlushCurrentPacket(); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); - CheckPacketContains(contents, 1); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeDataFastPath) { - delegate_.SetCanWriteAnything(); - generator_.SetCanSetTransmissionType(true); - generator_.SetTransmissionType(LOSS_RETRANSMISSION); - - // Create a 10000 byte IOVector. - CreateData(10000); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeDataFastPath( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, true); - EXPECT_EQ(10000u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); - EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); - EXPECT_TRUE(!packet.retransmittable_frames.empty()); - EXPECT_EQ(LOSS_RETRANSMISSION, packet.transmission_type); - EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); - const QuicStreamFrame& stream_frame = - packet.retransmittable_frames.front().stream_frame; - EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeDataLarge) { - delegate_.SetCanWriteAnything(); - - // Create a 10000 byte IOVector. - CreateData(10000); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - EXPECT_EQ(10000u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - PacketContents contents; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); - EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); - EXPECT_TRUE(!packet.retransmittable_frames.empty()); - EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); - const QuicStreamFrame& stream_frame = - packet.retransmittable_frames.front().stream_frame; - EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckFalse) { - delegate_.SetCanNotWrite(); - - QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); - const bool success = - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/true); - EXPECT_FALSE(success); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - delegate_.SetCanWriteAnything(); - - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/false); - - // Create a 10000 byte IOVector. - CreateData(10000); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.ConsumeRetransmittableControlFrame( - QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/true); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - generator_.Flush(); - - EXPECT_EQ(10000u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); - EXPECT_TRUE(!packet.retransmittable_frames.empty()); - EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); - const QuicStreamFrame& stream_frame = - packet.retransmittable_frames.front().stream_frame; - EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); -} - -TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckTrue) { - if (VersionHasIetfInvariantHeader(framer_.transport_version())) { - return; - } - delegate_.SetCanNotWrite(); - delegate_.SetCanWriteAnything(); - - // Create a 10000 byte IOVector. - CreateData(10000); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - generator_.Flush(); - - EXPECT_EQ(10000u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); - EXPECT_TRUE(!packet.retransmittable_frames.empty()); - EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); - const QuicStreamFrame& stream_frame = - packet.retransmittable_frames.front().stream_frame; - EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset); -} - -TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { - delegate_.SetCanNotWrite(); - - QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); - const bool consumed = - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/true); - EXPECT_FALSE(consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - EXPECT_FALSE(generator_.HasPendingStreamFramesOfStream(3)); - - delegate_.SetCanWriteAnything(); - - EXPECT_TRUE( - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/false)); - // Send some data and a control frame - MakeIOVector("quux", &iov_); - generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN); - if (!VersionHasIetfQuicFrames(framer_.transport_version())) { - generator_.ConsumeRetransmittableControlFrame( - QuicFrame(CreateGoAwayFrame()), - /*bundle_ack=*/false); - } - EXPECT_TRUE(generator_.HasPendingStreamFramesOfStream(3)); - - // All five frames will be flushed out in a single packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.Flush(); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - EXPECT_FALSE(generator_.HasPendingStreamFramesOfStream(3)); - - PacketContents contents; - // ACK will be flushed by connection. - contents.num_ack_frames = 0; - if (!VersionHasIetfQuicFrames(framer_.transport_version())) { - contents.num_goaway_frames = 1; - } else { - contents.num_goaway_frames = 0; - } - contents.num_rst_stream_frames = 1; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); -} - -TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { - delegate_.SetCanNotWrite(); - - QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); - const bool success = - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/true); - EXPECT_FALSE(success); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - delegate_.SetCanWriteAnything(); - - { - InSequence dummy; - // All five frames will be flushed out in a single packet - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - EXPECT_TRUE( - generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), - /*bundle_ack=*/false)); - // Send enough data to exceed one packet - size_t data_len = kDefaultMaxPacketSize + 100; - CreateData(data_len); - QuicConsumedData consumed = - generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, FIN); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - if (!VersionHasIetfQuicFrames(framer_.transport_version())) { - generator_.ConsumeRetransmittableControlFrame( - QuicFrame(CreateGoAwayFrame()), - /*bundle_ack=*/false); - } - - generator_.Flush(); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // The first packet should have the queued data and part of the stream data. - PacketContents contents; - // ACK will be sent by connection. - contents.num_ack_frames = 0; - contents.num_rst_stream_frames = 1; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); - - // The second should have the remainder of the stream data. - PacketContents contents2; - if (!VersionHasIetfQuicFrames(framer_.transport_version())) { - contents2.num_goaway_frames = 1; - } else { - contents2.num_goaway_frames = 0; - } - contents2.num_stream_frames = 1; - CheckPacketContains(contents2, 1); -} - -// Regression test of b/120493795. -TEST_F(QuicPacketGeneratorTest, PacketTransmissionType) { - delegate_.SetCanWriteAnything(); - generator_.SetCanSetTransmissionType(true); - - // The first ConsumeData will fill the packet without flush. - generator_.SetTransmissionType(LOSS_RETRANSMISSION); - - size_t data_len = 1324; - CreateData(data_len); - QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId( - framer_.transport_version(), Perspective::IS_CLIENT); - QuicConsumedData consumed = - generator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN); - EXPECT_EQ(data_len, consumed.bytes_consumed); - ASSERT_EQ(0u, creator_->BytesFree()) - << "Test setup failed: Please increase data_len to " - << data_len + creator_->BytesFree() << " bytes."; - - // The second ConsumeData can not be added to the packet and will flush. - generator_.SetTransmissionType(NOT_RETRANSMISSION); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - QuicStreamId stream2_id = stream1_id + 4; - - consumed = - generator_.ConsumeData(stream2_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN); - EXPECT_EQ(data_len, consumed.bytes_consumed); - - // Ensure the packet is successfully created. - ASSERT_EQ(1u, packets_.size()); - ASSERT_TRUE(packets_[0].encrypted_buffer); - ASSERT_EQ(1u, packets_[0].retransmittable_frames.size()); - EXPECT_EQ(stream1_id, - packets_[0].retransmittable_frames[0].stream_frame.stream_id); - - // Since the second frame was not added, the packet's transmission type - // should be the first frame's type. - EXPECT_EQ(packets_[0].transmission_type, LOSS_RETRANSMISSION); -} - -TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) { - QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); - generator_.SetServerConnectionIdLength(0); - EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, - creator_->GetDestinationConnectionIdLength()); - - for (size_t i = 1; i < 10; i++) { - generator_.SetServerConnectionIdLength(i); - if (VersionHasIetfInvariantHeader(framer_.transport_version())) { - EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, - creator_->GetDestinationConnectionIdLength()); - } else { - EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, - creator_->GetDestinationConnectionIdLength()); - } - } -} - -// Test whether SetMaxPacketLength() works in the situation when the queue is -// empty, and we send three packets worth of data. -TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) { - delegate_.SetCanWriteAnything(); - - // Send enough data for three packets. - size_t data_len = 3 * kDefaultMaxPacketSize + 1; - size_t packet_len = kDefaultMaxPacketSize + 100; - ASSERT_LE(packet_len, kMaxOutgoingPacketSize); - generator_.SetMaxPacketLength(packet_len); - EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .Times(3) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - CreateData(data_len); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, - /*offset=*/0, FIN); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // We expect three packets, and first two of them have to be of packet_len - // size. We check multiple packets (instead of just one) because we want to - // ensure that |max_packet_length_| does not get changed incorrectly by the - // generator after first packet is serialized. - ASSERT_EQ(3u, packets_.size()); - EXPECT_EQ(packet_len, packets_[0].encrypted_length); - EXPECT_EQ(packet_len, packets_[1].encrypted_length); - CheckAllPacketsHaveSingleStreamFrame(); -} - -// Test whether SetMaxPacketLength() works in the situation when we first write -// data, then change packet size, then write data again. -TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) { - delegate_.SetCanWriteAnything(); - - // We send enough data to overflow default packet length, but not the altered - // one. - size_t data_len = kDefaultMaxPacketSize; - size_t packet_len = kDefaultMaxPacketSize + 100; - ASSERT_LE(packet_len, kMaxOutgoingPacketSize); - - // We expect to see three packets in total. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .Times(3) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - // Send two packets before packet size change. - CreateData(data_len); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, - /*offset=*/0, NO_FIN); - generator_.Flush(); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // Make sure we already have two packets. - ASSERT_EQ(2u, packets_.size()); - - // Increase packet size. - generator_.SetMaxPacketLength(packet_len); - EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); - - // Send a packet after packet size change. - CreateData(data_len); - generator_.AttachPacketFlusher(); - consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, data_len, FIN); - generator_.Flush(); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // We expect first data chunk to get fragmented, but the second one to fit - // into a single packet. - ASSERT_EQ(3u, packets_.size()); - EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); - EXPECT_LE(kDefaultMaxPacketSize, packets_[2].encrypted_length); - CheckAllPacketsHaveSingleStreamFrame(); -} - -// Test whether SetMaxPacketLength() works correctly when we force the change of -// the packet size in the middle of the batched packet. -TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) { - delegate_.SetCanWriteAnything(); - - size_t first_write_len = kDefaultMaxPacketSize / 2; - size_t packet_len = kDefaultMaxPacketSize + 100; - size_t second_write_len = packet_len + 1; - ASSERT_LE(packet_len, kMaxOutgoingPacketSize); - - // First send half of the packet worth of data. We are in the batch mode, so - // should not cause packet serialization. - CreateData(first_write_len); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, - /*offset=*/0, NO_FIN); - EXPECT_EQ(first_write_len, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - // Make sure we have no packets so far. - ASSERT_EQ(0u, packets_.size()); - - // Expect a packet to be flushed. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - // Increase packet size after flushing all frames. - // Ensure it's immediately enacted. - generator_.FlushAllQueuedFrames(); - generator_.SetMaxPacketLength(packet_len); - EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // We expect to see exactly one packet serialized after that, because we send - // a value somewhat exceeding new max packet size, and the tail data does not - // get serialized because we are still in the batch mode. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - // Send a more than a packet worth of data to the same stream. This should - // trigger serialization of one packet, and queue another one. - CreateData(second_write_len); - consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, - /*offset=*/first_write_len, FIN); - EXPECT_EQ(second_write_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - // We expect the first packet to be underfilled, and the second packet be up - // to the new max packet size. - ASSERT_EQ(2u, packets_.size()); - EXPECT_GT(kDefaultMaxPacketSize, packets_[0].encrypted_length); - EXPECT_EQ(packet_len, packets_[1].encrypted_length); - - CheckAllPacketsHaveSingleStreamFrame(); -} - -// Test sending a connectivity probing packet. -TEST_F(QuicPacketGeneratorTest, GenerateConnectivityProbingPacket) { - delegate_.SetCanWriteAnything(); - - OwningSerializedPacketPointer probing_packet; - if (VersionHasIetfQuicFrames(framer_.transport_version())) { - QuicPathFrameBuffer payload = { - {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; - probing_packet = - generator_.SerializePathChallengeConnectivityProbingPacket(&payload); - } else { - probing_packet = generator_.SerializeConnectivityProbingPacket(); - } - - ASSERT_TRUE(simple_framer_.ProcessPacket(QuicEncryptedPacket( - probing_packet->encrypted_buffer, probing_packet->encrypted_length))); - - EXPECT_EQ(2u, simple_framer_.num_frames()); - if (VersionHasIetfQuicFrames(framer_.transport_version())) { - EXPECT_EQ(1u, simple_framer_.path_challenge_frames().size()); - } else { - EXPECT_EQ(1u, simple_framer_.ping_frames().size()); - } - EXPECT_EQ(1u, simple_framer_.padding_frames().size()); -} - -// Test sending an MTU probe, without any surrounding data. -TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) { - delegate_.SetCanWriteAnything(); - - const size_t target_mtu = kDefaultMaxPacketSize + 100; - static_assert(target_mtu < kMaxOutgoingPacketSize, - "The MTU probe used by the test exceeds maximum packet size"); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - generator_.GenerateMtuDiscoveryPacket(target_mtu); - - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - ASSERT_EQ(1u, packets_.size()); - EXPECT_EQ(target_mtu, packets_[0].encrypted_length); - - PacketContents contents; - contents.num_mtu_discovery_frames = 1; - contents.num_padding_frames = 1; - CheckPacketContains(contents, 0); -} - -// Test sending an MTU probe. Surround it with data, to ensure that it resets -// the MTU to the value before the probe was sent. -TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) { - delegate_.SetCanWriteAnything(); - - const size_t target_mtu = kDefaultMaxPacketSize + 100; - static_assert(target_mtu < kMaxOutgoingPacketSize, - "The MTU probe used by the test exceeds maximum packet size"); - - // Send enough data so it would always cause two packets to be sent. - const size_t data_len = target_mtu + 1; - - // Send a total of five packets: two packets before the probe, the probe - // itself, and two packets after the probe. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .Times(5) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - // Send data before the MTU probe. - CreateData(data_len); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, - /*offset=*/0, NO_FIN); - generator_.Flush(); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // Send the MTU probe. - generator_.GenerateMtuDiscoveryPacket(target_mtu); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - // Send data after the MTU probe. - CreateData(data_len); - generator_.AttachPacketFlusher(); - consumed = generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, - /*offset=*/data_len, FIN); - generator_.Flush(); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - ASSERT_EQ(5u, packets_.size()); - EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); - EXPECT_EQ(target_mtu, packets_[2].encrypted_length); - EXPECT_EQ(kDefaultMaxPacketSize, packets_[3].encrypted_length); - - PacketContents probe_contents; - probe_contents.num_mtu_discovery_frames = 1; - probe_contents.num_padding_frames = 1; - - CheckPacketHasSingleStreamFrame(0); - CheckPacketHasSingleStreamFrame(1); - CheckPacketContains(probe_contents, 2); - CheckPacketHasSingleStreamFrame(3); - CheckPacketHasSingleStreamFrame(4); -} - -TEST_F(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) { - if (VersionSupportsMessageFrames(framer_.transport_version())) { - return; - } - // Test added to ensure the generator does not crash when an invalid frame is - // added. Because this is an indication of internal programming errors, - // DFATALs are expected. - // A 1 byte packet number length can't encode a gap of 1000. - QuicPacketCreatorPeer::SetPacketNumber(creator_, 1000); - - delegate_.SetCanNotWrite(); - delegate_.SetCanWriteAnything(); - - // This will not serialize any packets, because of the invalid frame. - EXPECT_CALL(delegate_, - OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _)); - EXPECT_QUIC_BUG(generator_.Flush(), - "packet_number_length 1 is too small " - "for least_unacked_delta: 1001"); -} - -// Regression test for b/31486443. -TEST_F(QuicPacketGeneratorTest, ConnectionCloseFrameLargerThanPacketSize) { - delegate_.SetCanWriteAnything(); - char buf[2000] = {}; - QuicStringPiece error_details(buf, 2000); - const QuicErrorCode kQuicErrorCode = QUIC_PACKET_WRITE_ERROR; - - QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame( - framer_.transport_version(), kQuicErrorCode, std::string(error_details), - /*transport_close_frame_type=*/0); - generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame), - /*bundle_ack=*/false); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); -} - -TEST_F(QuicPacketGeneratorTest, RandomPaddingAfterFinSingleStreamSinglePacket) { - const QuicByteCount kStreamFramePayloadSize = 100u; - char buf[kStreamFramePayloadSize] = {}; - const QuicStreamId kDataStreamId = 5; - // Set the packet size be enough for one stream frame with 0 stream offset and - // max size of random padding. - size_t length = - NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_), - QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, - QuicPacketCreatorPeer::GetLengthLength(creator_)) + - QuicFramer::GetMinStreamFrameSize( - framer_.transport_version(), kDataStreamId, 0, - /*last_frame_in_packet=*/false, - kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) + - kStreamFramePayloadSize + kMaxNumRandomPaddingBytes; - generator_.SetMaxPacketLength(length); - delegate_.SetCanWriteAnything(); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); - generator_.Flush(); - EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - EXPECT_EQ(1u, packets_.size()); - PacketContents contents; - // The packet has both stream and padding frames. - contents.num_padding_frames = 1; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); -} - -TEST_F(QuicPacketGeneratorTest, - RandomPaddingAfterFinSingleStreamMultiplePackets) { - const QuicByteCount kStreamFramePayloadSize = 100u; - char buf[kStreamFramePayloadSize] = {}; - const QuicStreamId kDataStreamId = 5; - // Set the packet size be enough for one stream frame with 0 stream offset + - // 1. One or more packets will accommodate. - size_t length = - NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_), - QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, - QuicPacketCreatorPeer::GetLengthLength(creator_)) + - QuicFramer::GetMinStreamFrameSize( - framer_.transport_version(), kDataStreamId, 0, - /*last_frame_in_packet=*/false, kStreamFramePayloadSize + 1) + - kStreamFramePayloadSize + 1; - generator_.SetMaxPacketLength(length); - delegate_.SetCanWriteAnything(); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); - generator_.Flush(); - EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - EXPECT_LE(1u, packets_.size()); - PacketContents contents; - // The first packet has both stream and padding frames. - contents.num_stream_frames = 1; - contents.num_padding_frames = 1; - CheckPacketContains(contents, 0); - - for (size_t i = 1; i < packets_.size(); ++i) { - // Following packets only have paddings. - contents.num_stream_frames = 0; - contents.num_padding_frames = 1; - CheckPacketContains(contents, i); - } -} - -TEST_F(QuicPacketGeneratorTest, - RandomPaddingAfterFinMultipleStreamsMultiplePackets) { - const QuicByteCount kStreamFramePayloadSize = 100u; - char buf[kStreamFramePayloadSize] = {}; - const QuicStreamId kDataStreamId1 = 5; - const QuicStreamId kDataStreamId2 = 6; - // Set the packet size be enough for first frame with 0 stream offset + second - // frame + 1 byte payload. two or more packets will accommodate. - size_t length = - NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_), - QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, - QuicPacketCreatorPeer::GetLengthLength(creator_)) + - QuicFramer::GetMinStreamFrameSize( - framer_.transport_version(), kDataStreamId1, 0, - /*last_frame_in_packet=*/false, kStreamFramePayloadSize) + - kStreamFramePayloadSize + - QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), - kDataStreamId1, 0, - /*last_frame_in_packet=*/false, 1) + - 1; - generator_.SetMaxPacketLength(length); - delegate_.SetCanWriteAnything(); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - kDataStreamId1, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); - EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); - MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); - consumed = generator_.ConsumeData(kDataStreamId2, &iov_, 1u, iov_.iov_len, 0, - FIN_AND_PADDING); - EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); - generator_.Flush(); - EXPECT_FALSE(generator_.HasPendingFrames()); - EXPECT_FALSE(generator_.HasRetransmittableFrames()); - - EXPECT_LE(2u, packets_.size()); - PacketContents contents; - // The first packet has two stream frames. - contents.num_stream_frames = 2; - CheckPacketContains(contents, 0); - - // The second packet has one stream frame and padding frames. - contents.num_stream_frames = 1; - contents.num_padding_frames = 1; - CheckPacketContains(contents, 1); - - for (size_t i = 2; i < packets_.size(); ++i) { - // Following packets only have paddings. - contents.num_stream_frames = 0; - contents.num_padding_frames = 1; - CheckPacketContains(contents, i); - } -} - -TEST_F(QuicPacketGeneratorTest, AddMessageFrame) { - if (!VersionSupportsMessageFrames(framer_.transport_version())) { - return; - } - quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); - delegate_.SetCanWriteAnything(); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - MakeIOVector("foo", &iov_); - generator_.ConsumeData( - QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(), - Perspective::IS_CLIENT), - &iov_, 1u, iov_.iov_len, 0, FIN); - EXPECT_EQ(MESSAGE_STATUS_SUCCESS, - generator_.AddMessageFrame( - 1, MakeSpan(&allocator_, "message", &storage))); - EXPECT_TRUE(generator_.HasPendingFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - // Add a message which causes the flush of current packet. - EXPECT_EQ( - MESSAGE_STATUS_SUCCESS, - generator_.AddMessageFrame( - 2, MakeSpan( - &allocator_, - std::string(generator_.GetCurrentLargestMessagePayload(), 'a'), - &storage))); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); - - // Failed to send messages which cannot fit into one packet. - EXPECT_EQ( - MESSAGE_STATUS_TOO_LARGE, - generator_.AddMessageFrame( - 3, - MakeSpan(&allocator_, - std::string( - generator_.GetCurrentLargestMessagePayload() + 10, 'a'), - &storage))); -} - -TEST_F(QuicPacketGeneratorTest, ConnectionId) { - generator_.SetServerConnectionId(TestConnectionId(0x1337)); - EXPECT_EQ(TestConnectionId(0x1337), creator_->GetDestinationConnectionId()); - EXPECT_EQ(EmptyQuicConnectionId(), creator_->GetSourceConnectionId()); - if (!framer_.version().SupportsClientConnectionIds()) { - return; - } - generator_.SetClientConnectionId(TestConnectionId(0x33)); - EXPECT_EQ(TestConnectionId(0x1337), creator_->GetDestinationConnectionId()); - EXPECT_EQ(TestConnectionId(0x33), creator_->GetSourceConnectionId()); -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.cc index b3009ce5c7a..6e6804b2a29 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.cc @@ -8,15 +8,6 @@ namespace quic { -QuicPacketNumber::QuicPacketNumber() - : packet_number_(UninitializedPacketNumber()) {} - -QuicPacketNumber::QuicPacketNumber(uint64_t packet_number) - : packet_number_(packet_number) { - DCHECK_NE(UninitializedPacketNumber(), packet_number) - << "Use default constructor for uninitialized packet number"; -} - void QuicPacketNumber::Clear() { packet_number_ = UninitializedPacketNumber(); } @@ -111,9 +102,4 @@ std::ostream& operator<<(std::ostream& os, const QuicPacketNumber& p) { return os; } -// static -uint64_t QuicPacketNumber::UninitializedPacketNumber() { - return std::numeric_limits::max(); -} - } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h index 0cf7f15d9f7..18e78bbf1bb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h @@ -21,10 +21,20 @@ namespace quic { class QUIC_EXPORT_PRIVATE QuicPacketNumber { public: // Construct an uninitialized packet number. - QuicPacketNumber(); + constexpr QuicPacketNumber() : packet_number_(UninitializedPacketNumber()) {} + // Construct a packet number from uint64_t. |packet_number| cannot equal the // sentinel value. - explicit QuicPacketNumber(uint64_t packet_number); + explicit constexpr QuicPacketNumber(uint64_t packet_number) + : packet_number_(packet_number) { + DCHECK_NE(UninitializedPacketNumber(), packet_number) + << "Use default constructor for uninitialized packet number"; + } + + // The sentinel value representing an uninitialized packet number. + static constexpr uint64_t UninitializedPacketNumber() { + return std::numeric_limits::max(); + } // Packet number becomes uninitialized after calling this function. void Clear(); @@ -79,13 +89,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketNumber { // REQUIRES: lhs >= rhs. friend inline uint64_t operator-(QuicPacketNumber lhs, QuicPacketNumber rhs); - // The sentinel value representing an uninitialized packet number. - static uint64_t UninitializedPacketNumber(); - uint64_t packet_number_; }; -class QuicPacketNumberHash { +class QUIC_EXPORT_PRIVATE QuicPacketNumberHash { public: uint64_t operator()(QuicPacketNumber packet_number) const noexcept { return packet_number.Hash(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.h index 1826ef3573b..1e644aaa07a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.h @@ -25,7 +25,7 @@ namespace quic { const int kNumPacketsPerReadMmsgCall = 16; #endif -class QuicPacketReader { +class QUIC_EXPORT_PRIVATE QuicPacketReader { public: QuicPacketReader(); QuicPacketReader(const QuicPacketReader&) = delete; @@ -70,7 +70,7 @@ class QuicPacketReader { // from exceeding maximum allowed frame size. // packets_ and mmsg_hdr_ are used to supply cbuf and buf to the recvmmsg // call. - struct PacketData { + struct QUIC_EXPORT_PRIVATE PacketData { iovec iov; // raw_address is used for address information provided by the recvmmsg // call on the packets. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h index cc3dbc29543..0b331aec6f8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h @@ -15,7 +15,7 @@ namespace quic { // Wraps a writer object to allow dynamically extending functionality. Use // cases: replace writer while dispatcher and connections hold on to the // wrapper; mix in monitoring; mix in mocks in unit tests. -class QuicPacketWriterWrapper : public QuicPacketWriter { +class QUIC_NO_EXPORT QuicPacketWriterWrapper : public QuicPacketWriter { public: QuicPacketWriterWrapper(); QuicPacketWriterWrapper(const QuicPacketWriterWrapper&) = delete; 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 dfe80cf9d00..87b310e3a26 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 @@ -456,7 +456,8 @@ SerializedPacket::SerializedPacket(QuicPacketNumber packet_number, encryption_level(ENCRYPTION_INITIAL), has_ack(has_ack), has_stop_waiting(has_stop_waiting), - transmission_type(NOT_RETRANSMISSION) {} + transmission_type(NOT_RETRANSMISSION), + has_ack_frame_copy(false) {} SerializedPacket::SerializedPacket(const SerializedPacket& other) = default; @@ -474,17 +475,46 @@ SerializedPacket::SerializedPacket(SerializedPacket&& other) has_ack(other.has_ack), has_stop_waiting(other.has_stop_waiting), transmission_type(other.transmission_type), - original_packet_number(other.original_packet_number), - largest_acked(other.largest_acked) { + largest_acked(other.largest_acked), + has_ack_frame_copy(other.has_ack_frame_copy) { retransmittable_frames.swap(other.retransmittable_frames); + nonretransmittable_frames.swap(other.nonretransmittable_frames); } SerializedPacket::~SerializedPacket() {} +SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized, + QuicBufferAllocator* allocator, + bool copy_buffer) { + SerializedPacket* copy = new SerializedPacket(serialized); + if (copy_buffer) { + copy->encrypted_buffer = CopyBuffer(serialized); + } + // Copy underlying frames. + copy->retransmittable_frames = + CopyQuicFrames(allocator, serialized.retransmittable_frames); + copy->nonretransmittable_frames.clear(); + for (const auto& frame : serialized.nonretransmittable_frames) { + if (frame.type == ACK_FRAME) { + copy->has_ack_frame_copy = true; + } + copy->nonretransmittable_frames.push_back(CopyQuicFrame(allocator, frame)); + } + return copy; +} + void ClearSerializedPacket(SerializedPacket* serialized_packet) { if (!serialized_packet->retransmittable_frames.empty()) { DeleteFrames(&serialized_packet->retransmittable_frames); } + for (auto& frame : serialized_packet->nonretransmittable_frames) { + if (!serialized_packet->has_ack_frame_copy && frame.type == ACK_FRAME) { + // Do not delete ack frame if the packet does not own a copy of it. + continue; + } + DeleteFrame(&frame); + } + serialized_packet->nonretransmittable_frames.clear(); serialized_packet->encrypted_buffer = nullptr; serialized_packet->encrypted_length = 0; serialized_packet->largest_acked.Clear(); @@ -496,6 +526,13 @@ char* CopyBuffer(const SerializedPacket& packet) { return dst_buffer; } +char* CopyBuffer(const char* encrypted_buffer, + QuicPacketLength encrypted_length) { + char* dst_buffer = new char[encrypted_length]; + memcpy(dst_buffer, encrypted_buffer, encrypted_length); + return dst_buffer; +} + ReceivedPacketInfo::ReceivedPacketInfo(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, const QuicReceivedPacket& packet) 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 82647c6e91e..93417ac1d48 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 @@ -370,6 +370,7 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket { const char* encrypted_buffer; QuicPacketLength encrypted_length; QuicFrames retransmittable_frames; + QuicFrames nonretransmittable_frames; IsHandshake has_crypto_handshake; // -1: full padding to the end of a max-sized packet // 0: no padding @@ -378,15 +379,25 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket { QuicPacketNumber packet_number; QuicPacketNumberLength packet_number_length; EncryptionLevel encryption_level; + // TODO(fayang): Remove has_ack and has_stop_waiting. bool has_ack; bool has_stop_waiting; TransmissionType transmission_type; - QuicPacketNumber original_packet_number; // The largest acked of the AckFrame in this packet if has_ack is true, // 0 otherwise. QuicPacketNumber largest_acked; + // Indicates whether this packet has a copy of ack frame in + // nonretransmittable_frames. + bool has_ack_frame_copy; }; +// Make a copy of |serialized| (including the underlying frames). |copy_buffer| +// indicates whether the encrypted buffer should be copied. +QUIC_EXPORT_PRIVATE SerializedPacket* CopySerializedPacket( + const SerializedPacket& serialized, + QuicBufferAllocator* allocator, + bool copy_buffer); + // Deletes and clears all the frames and the packet from serialized packet. QUIC_EXPORT_PRIVATE void ClearSerializedPacket( SerializedPacket* serialized_packet); @@ -394,6 +405,10 @@ QUIC_EXPORT_PRIVATE void ClearSerializedPacket( // Allocates a new char[] of size |packet.encrypted_length| and copies in // |packet.encrypted_buffer|. QUIC_EXPORT_PRIVATE char* CopyBuffer(const SerializedPacket& packet); +// Allocates a new char[] of size |encrypted_length| and copies in +// |encrypted_buffer|. +QUIC_EXPORT_PRIVATE char* CopyBuffer(const char* encrypted_buffer, + QuicPacketLength encrypted_length); struct QUIC_EXPORT_PRIVATE SerializedPacketDeleter { void operator()(SerializedPacket* packet) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc index 7ee77979a0c..e080cd8265a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" @@ -70,6 +71,46 @@ TEST_F(QuicPacketsTest, GetClientConnectionIdAsSender) { GetClientConnectionIdAsSender(header, Perspective::IS_CLIENT)); } +TEST_F(QuicPacketsTest, CopySerializedPacket) { + std::string buffer(1000, 'a'); + SimpleBufferAllocator allocator; + SerializedPacket packet(QuicPacketNumber(1), PACKET_1BYTE_PACKET_NUMBER, + buffer.data(), buffer.length(), /*has_ack=*/false, + /*has_stop_waiting=*/false); + packet.retransmittable_frames.push_back( + QuicFrame(new QuicWindowUpdateFrame())); + packet.retransmittable_frames.push_back(QuicFrame(QuicStreamFrame())); + + QuicAckFrame ack_frame(InitAckFrame(1)); + packet.nonretransmittable_frames.push_back(QuicFrame(&ack_frame)); + packet.nonretransmittable_frames.push_back(QuicFrame(QuicPaddingFrame(-1))); + + std::unique_ptr copy = QuicWrapUnique( + CopySerializedPacket(packet, &allocator, /*copy_buffer=*/true)); + EXPECT_EQ(quic::QuicPacketNumber(1), copy->packet_number); + EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, copy->packet_number_length); + ASSERT_EQ(2u, copy->retransmittable_frames.size()); + EXPECT_EQ(WINDOW_UPDATE_FRAME, copy->retransmittable_frames[0].type); + EXPECT_EQ(STREAM_FRAME, copy->retransmittable_frames[1].type); + + ASSERT_EQ(2u, copy->nonretransmittable_frames.size()); + EXPECT_EQ(ACK_FRAME, copy->nonretransmittable_frames[0].type); + EXPECT_EQ(PADDING_FRAME, copy->nonretransmittable_frames[1].type); + EXPECT_EQ(1000u, copy->encrypted_length); + test::CompareCharArraysWithHexError( + "encrypted_buffer", copy->encrypted_buffer, copy->encrypted_length, + packet.encrypted_buffer, packet.encrypted_length); + + std::unique_ptr copy2 = QuicWrapUnique( + CopySerializedPacket(packet, &allocator, /*copy_buffer=*/false)); + EXPECT_EQ(packet.encrypted_buffer, copy2->encrypted_buffer); + EXPECT_EQ(1000u, copy2->encrypted_length); + ClearSerializedPacket(&packet); + delete[] copy->encrypted_buffer; + ClearSerializedPacket(copy.get()); + ClearSerializedPacket(copy2.get()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_pending_retransmission.h b/chromium/net/third_party/quiche/src/quic/core/quic_pending_retransmission.h deleted file mode 100644 index d1e9657a093..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/quic_pending_retransmission.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QUIC_PENDING_RETRANSMISSION_H_ -#define QUICHE_QUIC_CORE_QUIC_PENDING_RETRANSMISSION_H_ - -#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_transmission_info.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" - -namespace quic { - -// Struct to store the pending retransmission information. -struct QUIC_EXPORT_PRIVATE QuicPendingRetransmission { - QuicPendingRetransmission(QuicPacketNumber packet_number, - TransmissionType transmission_type, - const QuicFrames& retransmittable_frames, - bool has_crypto_handshake, - int num_padding_bytes, - EncryptionLevel encryption_level, - QuicPacketNumberLength packet_number_length) - : packet_number(packet_number), - retransmittable_frames(retransmittable_frames), - transmission_type(transmission_type), - has_crypto_handshake(has_crypto_handshake), - num_padding_bytes(num_padding_bytes), - encryption_level(encryption_level), - packet_number_length(packet_number_length) {} - - QuicPendingRetransmission(QuicPacketNumber packet_number, - TransmissionType transmission_type, - const QuicTransmissionInfo& tranmission_info) - : packet_number(packet_number), - retransmittable_frames(tranmission_info.retransmittable_frames), - transmission_type(transmission_type), - has_crypto_handshake(tranmission_info.has_crypto_handshake), - num_padding_bytes(tranmission_info.num_padding_bytes), - encryption_level(tranmission_info.encryption_level), - packet_number_length(tranmission_info.packet_number_length) {} - - QuicPacketNumber packet_number; - const QuicFrames& retransmittable_frames; - TransmissionType transmission_type; - bool has_crypto_handshake; - int num_padding_bytes; - EncryptionLevel encryption_level; - QuicPacketNumberLength packet_number_length; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QUIC_PENDING_RETRANSMISSION_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_process_packet_interface.h b/chromium/net/third_party/quiche/src/quic/core/quic_process_packet_interface.h index fc4257e9927..3cd87ef33c0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_process_packet_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_process_packet_interface.h @@ -11,7 +11,7 @@ namespace quic { // A class to process each incoming packet. -class ProcessPacketInterface { +class QUIC_NO_EXPORT ProcessPacketInterface { public: virtual ~ProcessPacketInterface() {} virtual void ProcessPacket(const QuicSocketAddress& self_address, 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 e21f4c48b8e..908d04fb228 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 @@ -25,14 +25,6 @@ namespace { // against an ack loss const size_t kMaxPacketsAfterNewMissing = 4; -// Maximum number of retransmittable packets received before sending an ack. -const QuicPacketCount kDefaultRetransmittablePacketsBeforeAck = 2; -// Minimum number of packets received before ack decimation is enabled. -// This intends to avoid the beginning of slow start, when CWNDs may be -// rapidly increasing. -const QuicPacketCount kMinReceivedBeforeAckDecimation = 100; -// Wait for up to 10 retransmittable packets before sending an ack. -const QuicPacketCount kMaxRetransmittablePacketsBeforeAck = 10; // One quarter RTT delay when doing ack decimation. const float kAckDecimationDelay = 0.25; // One eighth RTT delay when doing ack decimation. 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 a747f0b2cd2..bd0343bdb51 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 @@ -12,7 +12,6 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h" #include "net/third_party/quiche/src/quic/core/quic_connection_stats.h" -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.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" @@ -41,19 +40,14 @@ static const int64_t kMinHandshakeTimeoutMs = 10; // per draft RFC draft-dukkipati-tcpm-tcp-loss-probe. static const size_t kDefaultMaxTailLossProbes = 2; -inline bool HasCryptoHandshake(const QuicTransmissionInfo& transmission_info) { - DCHECK(!transmission_info.has_crypto_handshake || - !transmission_info.retransmittable_frames.empty()); - return transmission_info.has_crypto_handshake; -} - // Returns true of retransmissions of the specified type should retransmit // the frames directly (as opposed to resulting in a loss notification). inline bool ShouldForceRetransmission(TransmissionType transmission_type) { return transmission_type == HANDSHAKE_RETRANSMISSION || transmission_type == TLP_RETRANSMISSION || transmission_type == PROBING_RETRANSMISSION || - transmission_type == RTO_RETRANSMISSION; + transmission_type == RTO_RETRANSMISSION || + transmission_type == PTO_RETRANSMISSION; } // If pacing rate is accurate, > 2 burst token is not likely to help first ACK @@ -97,10 +91,8 @@ QuicSentPacketManager::QuicSentPacketManager( QuicTime::Delta::FromMilliseconds(kMinTailLossProbeTimeoutMs)), min_rto_timeout_( QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs)), - ietf_style_tlp_(false), - ietf_style_2x_tlp_(false), largest_mtu_acked_(0), - handshake_confirmed_(false), + handshake_state_(HANDSHAKE_START), peer_max_ack_delay_( QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), rtt_updated_(false), @@ -108,11 +100,13 @@ QuicSentPacketManager::QuicSentPacketManager( pto_enabled_(false), max_probe_packets_per_pto_(2), consecutive_pto_count_(0), - fix_rto_retransmission_(false), handshake_mode_disabled_(false), - detect_spurious_losses_(GetQuicReloadableFlag(quic_detect_spurious_loss)), + skip_packet_number_for_pto_(false), + always_include_max_ack_delay_for_pto_timeout_(true), + pto_exponential_backoff_start_point_(0), + pto_rttvar_multiplier_(4), neuter_handshake_packets_once_( - GetQuicReloadableFlag(quic_neuter_handshake_packets_once)) { + GetQuicReloadableFlag(quic_neuter_handshake_packets_once2)) { SetSendAlgorithm(congestion_control_type); } @@ -145,40 +139,55 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { if (config.HasClientSentConnectionOption(kMAD1, perspective)) { rtt_stats_.set_initial_max_ack_delay(peer_max_ack_delay_); } - if (GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_sent_packet_manager_cleanup); - if (config.HasClientSentConnectionOption(kMAD2, perspective)) { - // Set the minimum to the alarm granularity. - min_tlp_timeout_ = QuicTime::Delta::FromMilliseconds(1); - } - if (config.HasClientSentConnectionOption(kMAD3, perspective)) { - // Set the minimum to the alarm granularity. - min_rto_timeout_ = QuicTime::Delta::FromMilliseconds(1); - } - } else { - if (config.HasClientSentConnectionOption(kMAD2, perspective)) { - min_tlp_timeout_ = QuicTime::Delta::Zero(); - } - if (config.HasClientSentConnectionOption(kMAD3, perspective)) { - min_rto_timeout_ = QuicTime::Delta::Zero(); - } - if (config.HasClientSentConnectionOption(kMAD4, perspective)) { - ietf_style_tlp_ = true; - } - if (config.HasClientSentConnectionOption(kMAD5, perspective)) { - ietf_style_2x_tlp_ = true; - } + if (config.HasClientSentConnectionOption(kMAD2, perspective)) { + // Set the minimum to the alarm granularity. + min_tlp_timeout_ = QuicTime::Delta::FromMilliseconds(1); + } + if (config.HasClientSentConnectionOption(kMAD3, perspective)) { + // Set the minimum to the alarm granularity. + min_rto_timeout_ = QuicTime::Delta::FromMilliseconds(1); } - if (GetQuicReloadableFlag(quic_enable_pto) && fix_rto_retransmission_) { + if (GetQuicReloadableFlag(quic_enable_pto)) { if (config.HasClientSentConnectionOption(k2PTO, perspective)) { pto_enabled_ = true; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 2, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 2, 8); } if (config.HasClientSentConnectionOption(k1PTO, perspective)) { pto_enabled_ = true; max_probe_packets_per_pto_ = 1; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 1, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 1, 8); + } + } + + if (GetQuicReloadableFlag(quic_skip_packet_number_for_pto) && + config.HasClientSentConnectionOption(kPTOS, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_skip_packet_number_for_pto); + if (!pto_enabled_) { + QUIC_PEER_BUG + << "PTO is not enabled when receiving PTOS connection option."; + pto_enabled_ = true; + max_probe_packets_per_pto_ = 1; + } + skip_packet_number_for_pto_ = true; + } + + if (pto_enabled_) { + if (config.HasClientSentConnectionOption(kPTOA, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 5, 8); + always_include_max_ack_delay_for_pto_timeout_ = false; + } + if (config.HasClientSentConnectionOption(kPEB1, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 6, 8); + StartExponentialBackoffAfterNthPto(1); + } + if (config.HasClientSentConnectionOption(kPEB2, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 7, 8); + StartExponentialBackoffAfterNthPto(2); + } + if (config.HasClientSentConnectionOption(kPVS1, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 8, 8); + pto_rttvar_multiplier_ = 2; } } @@ -252,26 +261,31 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { } if (GetQuicReloadableFlag(quic_enable_ietf_loss_detection)) { if (config.HasClientRequestedIndependentOption(kILD0, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 1, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 1, 5); uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); } if (config.HasClientRequestedIndependentOption(kILD1, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 2, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 2, 5); uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); } - if (GetQuicReloadableFlag(quic_detect_spurious_loss)) { - if (config.HasClientRequestedIndependentOption(kILD2, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 3, 4); - uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); - uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); - } - if (config.HasClientRequestedIndependentOption(kILD3, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 4, 4); - uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); - uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); - uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); - } + if (config.HasClientRequestedIndependentOption(kILD2, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 3, 5); + uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); + uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); + } + if (config.HasClientRequestedIndependentOption(kILD3, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 4, 5); + uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); + uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); + uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); + } + if (config.HasClientRequestedIndependentOption(kILD4, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 5, 5); + uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); + uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); + uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); + uber_loss_algorithm_.EnableAdaptiveTimeThreshold(); } } if (config.HasClientSentConnectionOption(kCONH, perspective)) { @@ -293,13 +307,17 @@ void QuicSentPacketManager::ResumeConnectionState( : cached_network_params.bandwidth_estimate_bytes_per_second()); QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); - AdjustNetworkParameters(bandwidth, rtt, /*allow_cwnd_to_decrease=*/false); + // This calls the old AdjustNetworkParameters interface, and fills certain + // fields in SendAlgorithmInterface::NetworkParams + // (e.g., quic_bbr_fix_pacing_rate) using GFE flags. + AdjustNetworkParameters(SendAlgorithmInterface::NetworkParams( + bandwidth, rtt, /*allow_cwnd_to_decrease = */ false)); } void QuicSentPacketManager::AdjustNetworkParameters( - QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease) { + const SendAlgorithmInterface::NetworkParams& params) { + const QuicBandwidth& bandwidth = params.bandwidth; + const QuicTime::Delta& rtt = params.rtt; if (!rtt.IsZero()) { SetInitialRtt(rtt); } @@ -309,8 +327,7 @@ void QuicSentPacketManager::AdjustNetworkParameters( QUIC_RELOADABLE_FLAG_COUNT(quic_conservative_bursts); pacing_sender_.SetBurstTokens(kConservativeUnpacedBurst); } - send_algorithm_->AdjustNetworkParameters(bandwidth, rtt, - allow_cwnd_to_decrease); + send_algorithm_->AdjustNetworkParameters(params); if (debug_delegate_ != nullptr) { debug_delegate_->OnAdjustNetworkParameters( bandwidth, rtt.IsZero() ? rtt_stats_.SmoothedOrInitialRtt() : rtt, @@ -319,11 +336,12 @@ void QuicSentPacketManager::AdjustNetworkParameters( } void QuicSentPacketManager::SetHandshakeConfirmed() { - if (!neuter_handshake_packets_once_ || !handshake_confirmed_) { + if (!neuter_handshake_packets_once_ || + handshake_state_ < HANDSHAKE_COMPLETE) { if (neuter_handshake_packets_once_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_neuter_handshake_packets_once); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_neuter_handshake_packets_once2, 1, 3); } - handshake_confirmed_ = true; + handshake_state_ = HANDSHAKE_COMPLETE; NeuterHandshakePackets(); } } @@ -334,10 +352,8 @@ void QuicSentPacketManager::PostProcessNewlyAckedPackets( QuicTime ack_receive_time, bool rtt_updated, QuicByteCount prior_bytes_in_flight) { - if (session_decides_what_to_write()) { - unacked_packets_.NotifyAggregatedStreamFrameAcked( - last_ack_frame_.ack_delay_time); - } + unacked_packets_.NotifyAggregatedStreamFrameAcked( + last_ack_frame_.ack_delay_time); InvokeLossDetection(ack_receive_time); // Ignore losses in RTO mode. if (consecutive_rto_count_ > 0 && !use_new_rto_) { @@ -435,53 +451,72 @@ void QuicSentPacketManager::RetransmitUnackedPackets( void QuicSentPacketManager::NeuterUnencryptedPackets() { QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked(); - if (session_decides_what_to_write()) { - for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); - it != unacked_packets_.end(); ++it, ++packet_number) { - if (!it->retransmittable_frames.empty() && - it->encryption_level == ENCRYPTION_INITIAL) { - // Once the connection swithes to forward secure, no unencrypted packets - // will be sent. The data has been abandoned in the cryto stream. Remove - // it from in flight. - unacked_packets_.RemoveFromInFlight(packet_number); - } - } - return; - } - for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); + for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { - if (it->encryption_level == ENCRYPTION_INITIAL) { - // Once you're forward secure, no unencrypted packets will be sent, - // crypto or otherwise. Unencrypted packets are neutered and abandoned, - // to ensure they are not retransmitted or considered lost from a - // congestion control perspective. - pending_retransmissions_.erase(packet_number); + if (!it->retransmittable_frames.empty() && + it->encryption_level == ENCRYPTION_INITIAL) { + // Once the connection swithes to forward secure, no unencrypted packets + // will be sent. The data has been abandoned in the cryto stream. Remove + // it from in flight. unacked_packets_.RemoveFromInFlight(packet_number); - unacked_packets_.RemoveRetransmittability(packet_number); + if (neuter_handshake_packets_once_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_neuter_handshake_packets_once2, 2, 3); + it->state = NEUTERED; + DCHECK(!unacked_packets_.HasRetransmittableFrames(*it)); + } } } } void QuicSentPacketManager::NeuterHandshakePackets() { QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked(); - for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); + for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { - if (session_decides_what_to_write()) { - if (!it->retransmittable_frames.empty() && - unacked_packets_.GetPacketNumberSpace(it->encryption_level) == - HANDSHAKE_DATA) { - unacked_packets_.RemoveFromInFlight(packet_number); + if (!it->retransmittable_frames.empty() && + unacked_packets_.GetPacketNumberSpace(it->encryption_level) == + HANDSHAKE_DATA) { + unacked_packets_.RemoveFromInFlight(packet_number); + if (neuter_handshake_packets_once_) { + // Notify session that the data has been delivered (but do not notify + // send algorithm). + QUIC_RELOADABLE_FLAG_COUNT_N(quic_neuter_handshake_packets_once2, 3, 3); + it->state = NEUTERED; + unacked_packets_.NotifyFramesAcked(*it, QuicTime::Delta::Zero(), + QuicTime::Zero()); } - continue; } - if (unacked_packets_.GetPacketNumberSpace(it->encryption_level) == - HANDSHAKE_DATA && - unacked_packets_.HasRetransmittableFrames(*it)) { - pending_retransmissions_.erase(packet_number); - unacked_packets_.RemoveFromInFlight(packet_number); - unacked_packets_.RemoveRetransmittability(packet_number); + } +} + +bool QuicSentPacketManager::ShouldAddMaxAckDelay() const { + DCHECK(pto_enabled_); + if (always_include_max_ack_delay_for_pto_timeout_) { + return true; + } + if (!unacked_packets_ + .GetLargestSentRetransmittableOfPacketNumberSpace(APPLICATION_DATA) + .IsInitialized() || + unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace( + APPLICATION_DATA) < + FirstSendingPacketNumber() + kMinReceivedBeforeAckDecimation - 1) { + // Peer is doing TCP style acking. Expect an immediate ACK if more than 1 + // packet are outstanding. + if (unacked_packets_.packets_in_flight() >= + kDefaultRetransmittablePacketsBeforeAck) { + return false; } + } else if (unacked_packets_.packets_in_flight() >= + kMaxRetransmittablePacketsBeforeAck) { + // Peer is doing ack decimation. Expect an immediate ACK if >= 10 + // packets are outstanding. + return false; + } + if (skip_packet_number_for_pto_ && consecutive_pto_count_ > 0) { + // An immediate ACK is expected when doing PTOS. Please note, this will miss + // cases when PTO fires and turns out to be spurious. + return false; } + return true; } void QuicSentPacketManager::MarkForRetransmission( @@ -489,26 +524,15 @@ void QuicSentPacketManager::MarkForRetransmission( TransmissionType transmission_type) { QuicTransmissionInfo* transmission_info = unacked_packets_.GetMutableTransmissionInfo(packet_number); - // When session decides what to write, a previous RTO retransmission may cause - // connection close; packets without retransmittable frames can be marked for - // loss retransmissions. - QUIC_BUG_IF((transmission_type != LOSS_RETRANSMISSION && - (!session_decides_what_to_write() || - transmission_type != RTO_RETRANSMISSION)) && + // A previous RTO retransmission may cause connection close; packets without + // retransmittable frames can be marked for loss retransmissions. + QUIC_BUG_IF(transmission_type != LOSS_RETRANSMISSION && + transmission_type != RTO_RETRANSMISSION && !unacked_packets_.HasRetransmittableFrames(*transmission_info)) << "transmission_type: " << TransmissionTypeToString(transmission_type); // Handshake packets should never be sent as probing retransmissions. - DCHECK(pto_enabled_ || !transmission_info->has_crypto_handshake || + DCHECK(!transmission_info->has_crypto_handshake || transmission_type != PROBING_RETRANSMISSION); - if (!session_decides_what_to_write()) { - if (!unacked_packets_.HasRetransmittableFrames(*transmission_info)) { - return; - } - if (!QuicContainsKey(pending_retransmissions_, packet_number)) { - pending_retransmissions_[packet_number] = transmission_type; - } - return; - } HandleRetransmission(transmission_type, transmission_info); @@ -520,7 +544,6 @@ void QuicSentPacketManager::MarkForRetransmission( void QuicSentPacketManager::HandleRetransmission( TransmissionType transmission_type, QuicTransmissionInfo* transmission_info) { - DCHECK(session_decides_what_to_write()); if (ShouldForceRetransmission(transmission_type)) { // TODO(fayang): Consider to make RTO and PROBING retransmission // strategies be configurable by applications. Today, TLP, RTO and PROBING @@ -561,149 +584,47 @@ void QuicSentPacketManager::RecordOneSpuriousRetransmission( } } -void QuicSentPacketManager::RecordSpuriousRetransmissions( - const QuicTransmissionInfo& info, - QuicPacketNumber acked_packet_number) { - if (session_decides_what_to_write()) { - RecordOneSpuriousRetransmission(info); - if (!detect_spurious_losses_ && - info.transmission_type == LOSS_RETRANSMISSION) { - // Only inform the loss detection of spurious retransmits it caused. - loss_algorithm_->SpuriousRetransmitDetected( - unacked_packets_, clock_->Now(), rtt_stats_, acked_packet_number); - } - return; - } - QuicPacketNumber retransmission = info.retransmission; - while (retransmission.IsInitialized()) { - const QuicTransmissionInfo& retransmit_info = - unacked_packets_.GetTransmissionInfo(retransmission); - retransmission = retransmit_info.retransmission; - RecordOneSpuriousRetransmission(retransmit_info); - } - // Only inform the loss detection of spurious retransmits it caused. - if (unacked_packets_.GetTransmissionInfo(info.retransmission) - .transmission_type == LOSS_RETRANSMISSION) { - loss_algorithm_->SpuriousRetransmitDetected( - unacked_packets_, clock_->Now(), rtt_stats_, info.retransmission); - } -} - -QuicPendingRetransmission QuicSentPacketManager::NextPendingRetransmission() { - QUIC_BUG_IF(pending_retransmissions_.empty()) - << "Unexpected call to NextPendingRetransmission() with empty pending " - << "retransmission list. Corrupted memory usage imminent."; - QUIC_BUG_IF(session_decides_what_to_write()) - << "Unexpected call to NextPendingRetransmission() when session handles " - "retransmissions"; - QuicPacketNumber packet_number = pending_retransmissions_.begin()->first; - TransmissionType transmission_type = pending_retransmissions_.begin()->second; - if (unacked_packets_.HasPendingCryptoPackets()) { - // Ensure crypto packets are retransmitted before other packets. - for (const auto& pair : pending_retransmissions_) { - if (HasCryptoHandshake( - unacked_packets_.GetTransmissionInfo(pair.first))) { - packet_number = pair.first; - transmission_type = pair.second; - break; - } - } - } - DCHECK(unacked_packets_.IsUnacked(packet_number)) << packet_number; - const QuicTransmissionInfo& transmission_info = - unacked_packets_.GetTransmissionInfo(packet_number); - DCHECK(unacked_packets_.HasRetransmittableFrames(transmission_info)); - - return QuicPendingRetransmission(packet_number, transmission_type, - transmission_info); -} - -QuicPacketNumber QuicSentPacketManager::GetNewestRetransmission( - QuicPacketNumber packet_number, - const QuicTransmissionInfo& transmission_info) const { - if (session_decides_what_to_write()) { - return packet_number; - } - QuicPacketNumber retransmission = transmission_info.retransmission; - while (retransmission.IsInitialized()) { - packet_number = retransmission; - retransmission = - unacked_packets_.GetTransmissionInfo(retransmission).retransmission; - } - return packet_number; -} - void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, QuicTransmissionInfo* info, QuicTime ack_receive_time, QuicTime::Delta ack_delay_time, QuicTime receive_timestamp) { - QuicPacketNumber newest_transmission = - GetNewestRetransmission(packet_number, *info); - // Remove the most recent packet, if it is pending retransmission. - pending_retransmissions_.erase(newest_transmission); - - if (newest_transmission == packet_number) { - // Try to aggregate acked stream frames if acked packet is not a - // retransmission. - const bool fast_path = session_decides_what_to_write() && - info->transmission_type == NOT_RETRANSMISSION; - if (fast_path) { - unacked_packets_.MaybeAggregateAckedStreamFrame(*info, ack_delay_time, - receive_timestamp); - } else { - if (session_decides_what_to_write()) { - unacked_packets_.NotifyAggregatedStreamFrameAcked(ack_delay_time); - } - const bool new_data_acked = unacked_packets_.NotifyFramesAcked( - *info, ack_delay_time, receive_timestamp); - if (session_decides_what_to_write() && !new_data_acked && - info->transmission_type != NOT_RETRANSMISSION) { - // Record as a spurious retransmission if this packet is a - // retransmission and no new data gets acked. - QUIC_DVLOG(1) << "Detect spurious retransmitted packet " - << packet_number << " transmission type: " - << TransmissionTypeToString(info->transmission_type); - RecordSpuriousRetransmissions(*info, packet_number); - } - } - if (detect_spurious_losses_ && session_decides_what_to_write() && - info->state == LOST) { - // Record as a spurious loss as a packet previously declared lost gets - // acked. - QUIC_RELOADABLE_FLAG_COUNT(quic_detect_spurious_loss); - const PacketNumberSpace packet_number_space = - unacked_packets_.GetPacketNumberSpace(info->encryption_level); - const QuicPacketNumber previous_largest_acked = - supports_multiple_packet_number_spaces() - ? unacked_packets_.GetLargestAckedOfPacketNumberSpace( - packet_number_space) - : unacked_packets_.largest_acked(); - QUIC_DVLOG(1) << "Packet " << packet_number - << " was detected lost spuriously, " - "previous_largest_acked: " - << previous_largest_acked; - loss_algorithm_->SpuriousLossDetected(unacked_packets_, rtt_stats_, - ack_receive_time, packet_number, - previous_largest_acked); - } + // Try to aggregate acked stream frames if acked packet is not a + // retransmission. + if (info->transmission_type == NOT_RETRANSMISSION) { + unacked_packets_.MaybeAggregateAckedStreamFrame(*info, ack_delay_time, + receive_timestamp); } else { - DCHECK(!session_decides_what_to_write()); - RecordSpuriousRetransmissions(*info, packet_number); - // Remove the most recent packet from flight if it's a crypto handshake - // packet, since they won't be acked now that one has been processed. - // Other crypto handshake packets won't be in flight, only the newest - // transmission of a crypto packet is in flight at once. - // TODO(ianswett): Instead of handling all crypto packets special, - // only handle null encrypted packets in a special way. - const QuicTransmissionInfo& newest_transmission_info = - unacked_packets_.GetTransmissionInfo(newest_transmission); - unacked_packets_.NotifyFramesAcked(newest_transmission_info, ack_delay_time, - receive_timestamp); - if (HasCryptoHandshake(newest_transmission_info)) { - unacked_packets_.RemoveFromInFlight(newest_transmission); + unacked_packets_.NotifyAggregatedStreamFrameAcked(ack_delay_time); + const bool new_data_acked = unacked_packets_.NotifyFramesAcked( + *info, ack_delay_time, receive_timestamp); + if (!new_data_acked && info->transmission_type != NOT_RETRANSMISSION) { + // Record as a spurious retransmission if this packet is a + // retransmission and no new data gets acked. + QUIC_DVLOG(1) << "Detect spurious retransmitted packet " << packet_number + << " transmission type: " + << TransmissionTypeToString(info->transmission_type); + RecordOneSpuriousRetransmission(*info); } } + if (info->state == LOST) { + // Record as a spurious loss as a packet previously declared lost gets + // acked. + const PacketNumberSpace packet_number_space = + unacked_packets_.GetPacketNumberSpace(info->encryption_level); + const QuicPacketNumber previous_largest_acked = + supports_multiple_packet_number_spaces() + ? unacked_packets_.GetLargestAckedOfPacketNumberSpace( + packet_number_space) + : unacked_packets_.largest_acked(); + QUIC_DVLOG(1) << "Packet " << packet_number + << " was detected lost spuriously, " + "previous_largest_acked: " + << previous_largest_acked; + loss_algorithm_->SpuriousLossDetected(unacked_packets_, rtt_stats_, + ack_receive_time, packet_number, + previous_largest_acked); + } if (network_change_visitor_ != nullptr && info->bytes_sent > largest_mtu_acked_) { @@ -717,7 +638,6 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, bool QuicSentPacketManager::OnPacketSent( SerializedPacket* serialized_packet, - QuicPacketNumber original_packet_number, QuicTime sent_time, TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) { @@ -726,11 +646,6 @@ bool QuicSentPacketManager::OnPacketSent( DCHECK(!unacked_packets_.IsUnacked(packet_number)); QUIC_BUG_IF(serialized_packet->encrypted_length == 0) << "Cannot send empty packets."; - - if (original_packet_number.IsInitialized()) { - pending_retransmissions_.erase(original_packet_number); - } - if (pending_timer_transmission_count_ > 0) { --pending_timer_transmission_count_; } @@ -746,8 +661,8 @@ bool QuicSentPacketManager::OnPacketSent( serialized_packet->encrypted_length, has_retransmittable_data); } - unacked_packets_.AddSentPacket(serialized_packet, original_packet_number, - transmission_type, sent_time, in_flight); + unacked_packets_.AddSentPacket(serialized_packet, transmission_type, + sent_time, in_flight); // Reset the retransmission timer anytime a pending packet is sent. return in_flight; } @@ -755,7 +670,7 @@ bool QuicSentPacketManager::OnPacketSent( QuicSentPacketManager::RetransmissionTimeoutMode QuicSentPacketManager::OnRetransmissionTimeout() { DCHECK(unacked_packets_.HasInFlightPackets() || - (handshake_mode_disabled_ && !handshake_confirmed_)); + (handshake_mode_disabled_ && handshake_state_ < HANDSHAKE_COMPLETE)); DCHECK_EQ(0u, pending_timer_transmission_count_); // Handshake retransmission, timer based loss detection, TLP, and RTO are // implemented with a single alarm. The handshake alarm is set when the @@ -805,25 +720,18 @@ void QuicSentPacketManager::RetransmitCryptoPackets() { for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { // Only retransmit frames which are in flight, and therefore have been sent. - if (!it->in_flight || - (session_decides_what_to_write() && it->state != OUTSTANDING) || + if (!it->in_flight || it->state != OUTSTANDING || !it->has_crypto_handshake || !unacked_packets_.HasRetransmittableFrames(*it)) { continue; } packet_retransmitted = true; - if (session_decides_what_to_write()) { - crypto_retransmissions.push_back(packet_number); - } else { - MarkForRetransmission(packet_number, HANDSHAKE_RETRANSMISSION); - } + crypto_retransmissions.push_back(packet_number); ++pending_timer_transmission_count_; } DCHECK(packet_retransmitted) << "No crypto packets found to retransmit."; - if (session_decides_what_to_write()) { - for (QuicPacketNumber retransmission : crypto_retransmissions) { - MarkForRetransmission(retransmission, HANDSHAKE_RETRANSMISSION); - } + for (QuicPacketNumber retransmission : crypto_retransmissions) { + MarkForRetransmission(retransmission, HANDSHAKE_RETRANSMISSION); } } @@ -843,8 +751,7 @@ bool QuicSentPacketManager::MaybeRetransmitOldestPacket(TransmissionType type) { for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { // Only retransmit frames which are in flight, and therefore have been sent. - if (!it->in_flight || - (session_decides_what_to_write() && it->state != OUTSTANDING) || + if (!it->in_flight || it->state != OUTSTANDING || !unacked_packets_.HasRetransmittableFrames(*it)) { continue; } @@ -865,33 +772,13 @@ void QuicSentPacketManager::RetransmitRtoPackets() { std::vector retransmissions; for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { - if ((!session_decides_what_to_write() || it->state == OUTSTANDING) && + if (it->state == OUTSTANDING && unacked_packets_.HasRetransmittableFrames(*it) && pending_timer_transmission_count_ < max_rto_packets_) { - if (session_decides_what_to_write()) { - retransmissions.push_back(packet_number); - } else { - MarkForRetransmission(packet_number, RTO_RETRANSMISSION); - } + DCHECK(!neuter_handshake_packets_once_ || it->in_flight); + retransmissions.push_back(packet_number); ++pending_timer_transmission_count_; } - // Abandon non-retransmittable data that's in flight to ensure it doesn't - // fill up the congestion window. - bool has_retransmissions = it->retransmission.IsInitialized(); - if (session_decides_what_to_write()) { - has_retransmissions = it->state != OUTSTANDING; - } - if (!fix_rto_retransmission_ && it->in_flight && !has_retransmissions && - !unacked_packets_.HasRetransmittableFrames(*it)) { - // Log only for non-retransmittable data. - // Retransmittable data is marked as lost during loss detection, and will - // be logged later. - unacked_packets_.RemoveFromInFlight(packet_number); - if (debug_delegate_ != nullptr) { - debug_delegate_->OnPacketLoss(packet_number, RTO_RETRANSMISSION, - clock_->Now()); - } - } } if (pending_timer_transmission_count_ > 0) { if (consecutive_rto_count_ == 0) { @@ -899,17 +786,15 @@ void QuicSentPacketManager::RetransmitRtoPackets() { } ++consecutive_rto_count_; } - if (session_decides_what_to_write()) { - for (QuicPacketNumber retransmission : retransmissions) { - MarkForRetransmission(retransmission, RTO_RETRANSMISSION); - } - if (fix_rto_retransmission_ && retransmissions.empty()) { - QUIC_BUG_IF(pending_timer_transmission_count_ != 0); - // No packets to be RTO retransmitted, raise up a credit to allow - // connection to send. - QUIC_CODE_COUNT(no_packets_to_be_rto_retransmitted); - pending_timer_transmission_count_ = 1; - } + for (QuicPacketNumber retransmission : retransmissions) { + MarkForRetransmission(retransmission, RTO_RETRANSMISSION); + } + if (retransmissions.empty()) { + QUIC_BUG_IF(pending_timer_transmission_count_ != 0); + // No packets to be RTO retransmitted, raise up a credit to allow + // connection to send. + QUIC_CODE_COUNT(no_packets_to_be_rto_retransmitted); + pending_timer_transmission_count_ = 1; } } @@ -923,6 +808,7 @@ void QuicSentPacketManager::MaybeSendProbePackets() { it != unacked_packets_.end(); ++it, ++packet_number) { if (it->state == OUTSTANDING && unacked_packets_.HasRetransmittableFrames(*it)) { + DCHECK(!neuter_handshake_packets_once_ || it->in_flight); probing_packets.push_back(packet_number); if (probing_packets.size() == pending_timer_transmission_count_) { break; @@ -933,7 +819,7 @@ void QuicSentPacketManager::MaybeSendProbePackets() { for (QuicPacketNumber retransmission : probing_packets) { QUIC_DVLOG(1) << ENDPOINT << "Marking " << retransmission << " for probing retransmission"; - MarkForRetransmission(retransmission, PROBING_RETRANSMISSION); + MarkForRetransmission(retransmission, PTO_RETRANSMISSION); } // It is possible that there is not enough outstanding data for probing. } @@ -949,18 +835,21 @@ void QuicSentPacketManager::AdjustPendingTimerTransmissions() { } void QuicSentPacketManager::EnableIetfPtoAndLossDetection() { - DCHECK(session_decides_what_to_write()); - fix_rto_retransmission_ = true; pto_enabled_ = true; handshake_mode_disabled_ = true; uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); } +void QuicSentPacketManager::StartExponentialBackoffAfterNthPto( + size_t exponential_backoff_start_point) { + pto_exponential_backoff_start_point_ = exponential_backoff_start_point; +} + QuicSentPacketManager::RetransmissionTimeoutMode QuicSentPacketManager::GetRetransmissionMode() const { DCHECK(unacked_packets_.HasInFlightPackets() || - (handshake_mode_disabled_ && !handshake_confirmed_)); - if (!handshake_mode_disabled_ && !handshake_confirmed_ && + (handshake_mode_disabled_ && handshake_state_ < HANDSHAKE_COMPLETE)); + if (!handshake_mode_disabled_ && handshake_state_ < HANDSHAKE_COMPLETE && unacked_packets_.HasPendingCryptoPackets()) { return HANDSHAKE_MODE; } @@ -1045,7 +934,7 @@ QuicTime::Delta QuicSentPacketManager::TimeUntilSend(QuicTime now) const { const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { if (!unacked_packets_.HasInFlightPackets() && - (!handshake_mode_disabled_ || handshake_confirmed_ || + (!handshake_mode_disabled_ || handshake_state_ >= HANDSHAKE_COMPLETE || unacked_packets_.perspective() == Perspective::IS_SERVER)) { // Do not set the timer if there is nothing in flight. However, to avoid // handshake deadlock due to anti-amplification limit, client needs to set @@ -1057,10 +946,6 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { // Do not set the timer if there is any credit left. return QuicTime::Zero(); } - if (!fix_rto_retransmission_ && - !unacked_packets_.HasUnackedRetransmittableFrames()) { - return QuicTime::Zero(); - } switch (GetRetransmissionMode()) { case HANDSHAKE_MODE: return unacked_packets_.GetLastCryptoPacketSentTime() + @@ -1089,14 +974,6 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { return std::max(tlp_time, rto_time); } case PTO_MODE: { - if (!unacked_packets().simple_inflight_time() && - handshake_mode_disabled_ && !handshake_confirmed_ && - !unacked_packets_.HasInFlightPackets()) { - DCHECK_EQ(Perspective::IS_CLIENT, unacked_packets_.perspective()); - return std::max(clock_->ApproximateNow(), - unacked_packets_.GetLastCryptoPacketSentTime() + - GetProbeTimeoutDelay()); - } // Ensure PTO never gets set to a time in the past. return std::max(clock_->ApproximateNow(), unacked_packets_.GetLastInFlightPacketSentTime() + @@ -1141,20 +1018,11 @@ const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay( size_t consecutive_tlp_count) const { QuicTime::Delta srtt = rtt_stats_.SmoothedOrInitialRtt(); if (enable_half_rtt_tail_loss_probe_ && consecutive_tlp_count == 0u) { - if (!session_decides_what_to_write()) { - return std::max(min_tlp_timeout_, srtt * 0.5); - } if (unacked_packets().HasUnackedStreamData()) { // Enable TLPR if there are pending data packets. return std::max(min_tlp_timeout_, srtt * 0.5); } } - if (ietf_style_tlp_) { - return std::max(min_tlp_timeout_, 1.5 * srtt + rtt_stats_.max_ack_delay()); - } - if (ietf_style_2x_tlp_) { - return std::max(min_tlp_timeout_, 2 * srtt + rtt_stats_.max_ack_delay()); - } if (!unacked_packets_.HasMultipleInFlightPackets()) { // This expression really should be using the delayed ack time, but in TCP // MinRTO was traditionally set to 2x the delayed ack timer and this @@ -1200,45 +1068,27 @@ const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay() const { } const QuicTime::Delta pto_delay = rtt_stats_.smoothed_rtt() + - std::max(4 * rtt_stats_.mean_deviation(), + std::max(pto_rttvar_multiplier_ * rtt_stats_.mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + - peer_max_ack_delay_; - return pto_delay * (1 << consecutive_pto_count_); + (ShouldAddMaxAckDelay() ? peer_max_ack_delay_ : QuicTime::Delta::Zero()); + return pto_delay * (1 << (consecutive_pto_count_ - + std::min(consecutive_pto_count_, + pto_exponential_backoff_start_point_))); } QuicTime::Delta QuicSentPacketManager::GetSlowStartDuration() const { - if (send_algorithm_->GetCongestionControlType() != kBBR) { - return QuicTime::Delta::Infinite(); - } - - if (!send_algorithm_->InSlowStart()) { - return stats_->slowstart_duration; + if (send_algorithm_->GetCongestionControlType() == kBBR || + send_algorithm_->GetCongestionControlType() == kBBRv2) { + return stats_->slowstart_duration.GetTotalElapsedTime( + clock_->ApproximateNow()); } - - return clock_->ApproximateNow() - stats_->slowstart_start_time + - stats_->slowstart_duration; + return QuicTime::Delta::Infinite(); } std::string QuicSentPacketManager::GetDebugState() const { return send_algorithm_->GetDebugState(); } -void QuicSentPacketManager::CancelRetransmissionsForStream( - QuicStreamId stream_id) { - if (session_decides_what_to_write()) { - return; - } - unacked_packets_.CancelRetransmissionsForStream(stream_id); - auto it = pending_retransmissions_.begin(); - while (it != pending_retransmissions_.end()) { - if (unacked_packets_.HasRetransmittableFrames(it->first)) { - ++it; - continue; - } - it = pending_retransmissions_.erase(it); - } -} - void QuicSentPacketManager::SetSendAlgorithm( CongestionControlType congestion_control_type) { SetSendAlgorithm(SendAlgorithmInterface::Create( @@ -1331,7 +1181,7 @@ AckResult QuicSentPacketManager::OnAckFrameEnd( EncryptionLevel ack_decrypted_level) { QuicByteCount prior_bytes_in_flight = unacked_packets_.bytes_in_flight(); // Reverse packets_acked_ so that it is in ascending order. - reverse(packets_acked_.begin(), packets_acked_.end()); + std::reverse(packets_acked_.begin(), packets_acked_.end()); for (AckedPacket& acked_packet : packets_acked_) { QuicTransmissionInfo* info = unacked_packets_.GetMutableTransmissionInfo(acked_packet.packet_number); @@ -1370,6 +1220,9 @@ AckResult QuicSentPacketManager::OnAckFrameEnd( return PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE; } last_ack_frame_.packets.Add(acked_packet.packet_number); + if (info->encryption_level == ENCRYPTION_FORWARD_SECURE) { + handshake_state_ = HANDSHAKE_CONFIRMED; + } largest_packet_peer_knows_is_acked_.UpdateMax(info->largest_acked); if (supports_multiple_packet_number_spaces()) { largest_packets_peer_knows_is_acked_[packet_number_space].UpdateMax( @@ -1424,16 +1277,6 @@ void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) { rtt_stats_.set_initial_rtt(std::max(min_rtt, std::min(max_rtt, rtt))); } -void QuicSentPacketManager::SetSessionDecideWhatToWrite( - bool session_decides_what_to_write) { - if (GetQuicReloadableFlag(quic_fix_rto_retransmission3) && - session_decides_what_to_write) { - fix_rto_retransmission_ = true; - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_rto_retransmission3); - } - unacked_packets_.SetSessionDecideWhatToWrite(session_decides_what_to_write); -} - void QuicSentPacketManager::EnableMultiplePacketNumberSpacesSupport() { unacked_packets_.EnableMultiplePacketNumberSpacesSupport(); } 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 9e903fdfa2d..5a3f2ca05d7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h @@ -19,7 +19,6 @@ #include "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_packets.h" -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.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" #include "net/third_party/quiche/src/quic/core/quic_types.h" @@ -108,6 +107,25 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { PTO_MODE, }; + // Handshake state of this connection. + enum HandshakeState { + // Initial state. + HANDSHAKE_START, + // Only used in IETF QUIC with TLS handshake. State proceeds to + // HANDSHAKE_PROCESSED after a packet of HANDSHAKE packet number space + // gets successfully processed, and the initial key can be dropped. + HANDSHAKE_PROCESSED, + // In QUIC crypto, state proceeds to HANDSHAKE_COMPLETE if client receives + // SHLO or server successfully processes an ENCRYPTION_FORWARD_SECURE + // packet, such that the handshake packets can be neutered. In IETF QUIC + // with TLS handshake, state proceeds to HANDSHAKE_COMPLETE once the + // endpoint has both 1-RTT send and receive keys. + HANDSHAKE_COMPLETE, + // Only used in IETF QUIC with TLS handshake. State proceeds to + // HANDSHAKE_CONFIRMED if a 1-RTT packet gets acknowledged. + HANDSHAKE_CONFIRMED, + }; + QuicSentPacketManager(Perspective perspective, const QuicClock* clock, QuicRandom* random, @@ -133,8 +151,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { return pacing_sender_.max_pacing_rate(); } - // Set handshake_confirmed_ to true and neuter packets in HANDSHAKE packet - // number space. + // Called to mark the handshake state complete, and all handshake packets are + // neutered. + // TODO(fayang): Rename this function to OnHandshakeComplete. void SetHandshakeConfirmed(); // Requests retransmission of all unacked packets of |retransmission_type|. @@ -149,9 +168,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Notify the sent packet manager of an external network measurement or // prediction for either |bandwidth| or |rtt|; either can be empty. - void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt, - bool allow_cwnd_to_decrease); + void AdjustNetworkParameters( + const SendAlgorithmInterface::NetworkParams& params); // Retransmits the oldest pending packet there is still a tail loss probe // pending. Invoked after OnRetransmissionTimeout. @@ -165,16 +183,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // TODO(fayang): Consider replace this function with NeuterHandshakePackets. void NeuterUnencryptedPackets(); - // Returns true if there are pending retransmissions. - // Not const because retransmissions may be cancelled before returning. - bool HasPendingRetransmissions() const { - return !pending_retransmissions_.empty(); - } - - // Retrieves the next pending retransmission. You must ensure that - // there are pending retransmissions prior to calling this function. - QuicPendingRetransmission NextPendingRetransmission(); - // Returns true if there's outstanding crypto data. bool HasUnackedCryptoPackets() const { return unacked_packets_.HasPendingCryptoPackets(); @@ -195,7 +203,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // 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, - QuicPacketNumber original_packet_number, QuicTime sent_time, TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data); @@ -276,9 +283,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { return unacked_packets_.bytes_in_flight(); } - // No longer retransmit data for |stream_id|. - void CancelRetransmissionsForStream(QuicStreamId stream_id); - // Called when peer address changes and the connection migrates. void OnConnectionMigration(AddressChangeType type); @@ -300,9 +304,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { QuicPacketNumber ack_packet_number, EncryptionLevel ack_decrypted_level); - // Called to enable/disable letting session decide what to write. - void SetSessionDecideWhatToWrite(bool session_decides_what_to_write); - void EnableMultiplePacketNumberSpacesSupport(); void SetDebugDelegate(DebugDelegate* debug_delegate); @@ -363,11 +364,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { return largest_packet_peer_knows_is_acked_; } - bool handshake_confirmed() const { return handshake_confirmed_; } - - bool session_decides_what_to_write() const { - return unacked_packets_.session_decides_what_to_write(); - } + HandshakeState handshake_state() const { return handshake_state_; } size_t pending_timer_transmission_count() const { return pending_timer_transmission_count_; @@ -405,25 +402,27 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Also enable IETF loss detection. void EnableIetfPtoAndLossDetection(); + // Called to set the start point of doing exponential backoff when calculating + // PTO timeout. + void StartExponentialBackoffAfterNthPto( + size_t exponential_backoff_start_point); + bool supports_multiple_packet_number_spaces() const { return unacked_packets_.supports_multiple_packet_number_spaces(); } - bool fix_rto_retransmission() const { return fix_rto_retransmission_; } - bool pto_enabled() const { return pto_enabled_; } bool handshake_mode_disabled() const { return handshake_mode_disabled_; } + bool skip_packet_number_for_pto() const { + return skip_packet_number_for_pto_; + } + private: friend class test::QuicConnectionPeer; friend class test::QuicSentPacketManagerPeer; - typedef QuicLinkedHashMap - PendingRetransmissionMap; - // Returns the current retransmission mode. RetransmissionTimeoutMode GetRetransmissionMode() const; @@ -463,11 +462,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Returns the probe timeout. const QuicTime::Delta GetProbeTimeoutDelay() const; - // Returns the newest transmission associated with a packet. - QuicPacketNumber GetNewestRetransmission( - QuicPacketNumber packet_number, - const QuicTransmissionInfo& transmission_info) const; - // Update the RTT if the ack is for the largest acked packet number. // Returns true if the rtt was updated. bool MaybeUpdateRTT(QuicPacketNumber largest_acked, @@ -521,11 +515,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // this function. void RecordOneSpuriousRetransmission(const QuicTransmissionInfo& info); - // Notify observers about spurious retransmits of packet with - // QuicTransmissionInfo |info|. - void RecordSpuriousRetransmissions(const QuicTransmissionInfo& info, - QuicPacketNumber acked_packet_number); - // Sets the initial RTT of the connection. void SetInitialRtt(QuicTime::Delta rtt); @@ -539,6 +528,10 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // switches to IETF QUIC with QUIC TLS. void NeuterHandshakePackets(); + // Indicates whether including peer_max_ack_delay_ when calculating PTO + // timeout. + bool ShouldAddMaxAckDelay() const; + // 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 @@ -549,9 +542,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // set to nullptr. QuicUnackedPacketMap unacked_packets_; - // Pending retransmissions which have not been packetized and sent yet. - PendingRetransmissionMap pending_retransmissions_; - const QuicClock* clock_; QuicRandom* random_; QuicConnectionStats* stats_; @@ -592,10 +582,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { QuicTime::Delta min_tlp_timeout_; // The minimum RTO. QuicTime::Delta min_rto_timeout_; - // Whether to use IETF style TLP that includes the max ack delay. - bool ietf_style_tlp_; - // IETF style TLP, but with a 2x multiplier instead of 1.5x. - bool ietf_style_2x_tlp_; // Vectors packets acked and lost as a result of the last congestion event. AckedPacketVector packets_acked_; @@ -609,11 +595,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Calls into |send_algorithm_| for the underlying congestion control. PacingSender pacing_sender_; - // Set to true after the crypto handshake has successfully completed. After - // this is true we no longer use HANDSHAKE_MODE, and further frames sent on - // the crypto stream (i.e. SCUP messages) are treated like normal - // retransmittable frames. - bool handshake_confirmed_; + // Indicates current handshake state. + HandshakeState handshake_state_; // Records bandwidth from server to client in normal operation, over periods // of time with no loss events. @@ -652,17 +635,24 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Number of times the PTO timer has fired in a row without receiving an ack. size_t consecutive_pto_count_; - // Latched value of quic_fix_rto_retransmission3 and - // session_decides_what_to_write. - bool fix_rto_retransmission_; - // True if HANDSHAKE mode has been disabled. bool handshake_mode_disabled_; - // Latched value of quic_detect_spurious_loss. - const bool detect_spurious_losses_; + // If true, skip packet number before sending the last PTO retransmission. + bool skip_packet_number_for_pto_; + + // If true, always include peer_max_ack_delay_ when calculating PTO timeout. + bool always_include_max_ack_delay_for_pto_timeout_; + + // When calculating PTO timeout, the start point of doing exponential backoff. + // For example, 0 : always do exponential backoff. n : do exponential backoff + // since nth PTO. + size_t pto_exponential_backoff_start_point_; + + // The multiplier of rttvar when calculating PTO timeout. + int pto_rttvar_multiplier_; - // Latched value of quic_neuter_handshake_packets_once. + // Latched value of quic_neuter_handshake_packets_once2. const bool neuter_handshake_packets_once_; }; 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 4ee9fd31d86..8dd0c30faea 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,7 +7,6 @@ #include #include -#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -53,7 +52,7 @@ class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate { QuicTime detection_time)); }; -class QuicSentPacketManagerTest : public QuicTestWithParam { +class QuicSentPacketManagerTest : public QuicTest { public: void RetransmitCryptoPacket(uint64_t packet_number) { EXPECT_CALL( @@ -64,8 +63,8 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { packet.retransmittable_frames.push_back( QuicFrame(QuicStreamFrame(1, false, 0, QuicStringPiece()))); packet.has_crypto_handshake = IS_HANDSHAKE; - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - HANDSHAKE_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + manager_.OnPacketSent(&packet, clock_.Now(), HANDSHAKE_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); } void RetransmitDataPacket(uint64_t packet_number, @@ -77,7 +76,7 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { kDefaultLength, HAS_RETRANSMITTABLE_DATA)); SerializedPacket packet(CreatePacket(packet_number, true)); packet.encryption_level = level; - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), type, + manager_.OnPacketSent(&packet, clock_.Now(), type, HAS_RETRANSMITTABLE_DATA); } @@ -102,7 +101,6 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); manager_.SetNetworkChangeVisitor(network_change_visitor_.get()); manager_.SetSessionNotifier(¬ifier_); - manager_.SetSessionDecideWhatToWrite(GetParam()); EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate()) .Times(AnyNumber()); @@ -210,53 +208,31 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { uint64_t new_packet_number, TransmissionType transmission_type) { bool is_lost = false; - if (manager_.session_decides_what_to_write()) { - if (transmission_type == HANDSHAKE_RETRANSMISSION || - transmission_type == TLP_RETRANSMISSION || - transmission_type == RTO_RETRANSMISSION || - transmission_type == PROBING_RETRANSMISSION) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>( - Invoke([this, new_packet_number](TransmissionType type) { - RetransmitDataPacket(new_packet_number, type); - }))); - } else { - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); - is_lost = true; - } + if (transmission_type == HANDSHAKE_RETRANSMISSION || + transmission_type == TLP_RETRANSMISSION || + transmission_type == RTO_RETRANSMISSION || + transmission_type == PROBING_RETRANSMISSION) { + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>( + Invoke([this, new_packet_number](TransmissionType type) { + RetransmitDataPacket(new_packet_number, type); + }))); + } else { + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); + is_lost = true; } QuicSentPacketManagerPeer::MarkForRetransmission( &manager_, old_packet_number, transmission_type); - if (manager_.session_decides_what_to_write()) { - if (!is_lost) { - return; - } - EXPECT_CALL( - *send_algorithm_, - OnPacketSent(_, BytesInFlight(), QuicPacketNumber(new_packet_number), - kDefaultLength, HAS_RETRANSMITTABLE_DATA)); - SerializedPacket packet(CreatePacket(new_packet_number, true)); - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - transmission_type, HAS_RETRANSMITTABLE_DATA); + if (!is_lost) { return; } - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - QuicPendingRetransmission next_retransmission = - manager_.NextPendingRetransmission(); - EXPECT_EQ(QuicPacketNumber(old_packet_number), - next_retransmission.packet_number); - EXPECT_EQ(transmission_type, next_retransmission.transmission_type); - EXPECT_CALL( *send_algorithm_, OnPacketSent(_, BytesInFlight(), QuicPacketNumber(new_packet_number), kDefaultLength, HAS_RETRANSMITTABLE_DATA)); - SerializedPacket packet(CreatePacket(new_packet_number, false)); - manager_.OnPacketSent(&packet, QuicPacketNumber(old_packet_number), - clock_.Now(), transmission_type, + SerializedPacket packet(CreatePacket(new_packet_number, true)); + manager_.OnPacketSent(&packet, clock_.Now(), transmission_type, HAS_RETRANSMITTABLE_DATA); - EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_, - new_packet_number)); } SerializedPacket CreateDataPacket(uint64_t packet_number) { @@ -293,8 +269,8 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { QuicPacketNumber(packet_number), _, _)); SerializedPacket packet(CreateDataPacket(packet_number)); packet.encryption_level = encryption_level; - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); } void SendPingPacket(uint64_t packet_number, @@ -304,8 +280,8 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { QuicPacketNumber(packet_number), _, _)); SerializedPacket packet(CreatePingPacket(packet_number)); packet.encryption_level = encryption_level; - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); } void SendCryptoPacket(uint64_t packet_number) { @@ -317,12 +293,9 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { packet.retransmittable_frames.push_back( QuicFrame(QuicStreamFrame(1, false, 0, QuicStringPiece()))); packet.has_crypto_handshake = IS_HANDSHAKE; - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, HasUnackedCryptoData()) - .WillRepeatedly(Return(true)); - } + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(true)); } void SendAckPacket(uint64_t packet_number, uint64_t largest_acked) { @@ -339,27 +312,11 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { SerializedPacket packet(CreatePacket(packet_number, false)); packet.largest_acked = QuicPacketNumber(largest_acked); packet.encryption_level = level; - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); - } - - // Based on QuicConnection's WritePendingRetransmissions. - void RetransmitNextPacket(uint64_t retransmission_packet_number) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_CALL( - *send_algorithm_, - OnPacketSent(_, _, QuicPacketNumber(retransmission_packet_number), - kDefaultLength, HAS_RETRANSMITTABLE_DATA)); - const QuicPendingRetransmission pending = - manager_.NextPendingRetransmission(); - SerializedPacket packet(CreatePacket(retransmission_packet_number, false)); - manager_.OnPacketSent(&packet, pending.packet_number, clock_.Now(), - pending.transmission_type, HAS_RETRANSMITTABLE_DATA); + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + NO_RETRANSMITTABLE_DATA); } void EnablePto(QuicTag tag) { - SetQuicReloadableFlag(quic_fix_rto_retransmission3, true); - manager_.SetSessionDecideWhatToWrite(true); SetQuicReloadableFlag(quic_enable_pto, true); QuicConfig config; QuicTagVector options; @@ -379,12 +336,7 @@ class QuicSentPacketManagerTest : public QuicTestWithParam { StrictMock notifier_; }; -INSTANTIATE_TEST_SUITE_P(Tests, - QuicSentPacketManagerTest, - ::testing::Bool(), - ::testing::PrintToStringParamName()); - -TEST_P(QuicSentPacketManagerTest, IsUnacked) { +TEST_F(QuicSentPacketManagerTest, IsUnacked) { VerifyUnackedPackets(nullptr, 0); SendDataPacket(1); @@ -395,23 +347,18 @@ TEST_P(QuicSentPacketManagerTest, IsUnacked) { QUIC_ARRAYSIZE(retransmittable)); } -TEST_P(QuicSentPacketManagerTest, IsUnAckedRetransmit) { +TEST_F(QuicSentPacketManagerTest, IsUnAckedRetransmit) { SendDataPacket(1); RetransmitAndSendPacket(1, 2); EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_, 2)); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - std::vector retransmittable; - if (manager_.session_decides_what_to_write()) { - retransmittable = {1, 2}; - } else { - retransmittable = {2}; - } + std::vector retransmittable = {1, 2}; VerifyRetransmittablePackets(&retransmittable[0], retransmittable.size()); } -TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) { +TEST_F(QuicSentPacketManagerTest, RetransmitThenAck) { SendDataPacket(1); RetransmitAndSendPacket(1, 2); @@ -423,9 +370,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); // Packet 1 is unacked, pending, but not retransmittable. uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -433,21 +378,13 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) { VerifyRetransmittablePackets(nullptr, 0); } -TEST_P(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) { +TEST_F(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) { SendDataPacket(1); - if (manager_.session_decides_what_to_write()) { - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(2, type); - }))); - } - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); QuicSentPacketManagerPeer::MarkForRetransmission(&manager_, 1, TLP_RETRANSMISSION); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - } // Ack 1. ExpectAck(1); manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), @@ -457,40 +394,21 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) { manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); - // There should no longer be a pending retransmission. - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - uint64_t unacked[] = {2}; - VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - // We do not know packet 2 is a spurious retransmission until it gets acked. - } else { - // No unacked packets remain. - VerifyUnackedPackets(nullptr, 0); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); + uint64_t unacked[] = {2}; + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + // We do not know packet 2 is a spurious retransmission until it gets acked. VerifyRetransmittablePackets(nullptr, 0); EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted); } -TEST_P(QuicSentPacketManagerTest, RetransmitThenStopRetransmittingBeforeSend) { +TEST_F(QuicSentPacketManagerTest, RetransmitThenStopRetransmittingBeforeSend) { SendDataPacket(1); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)); QuicSentPacketManagerPeer::MarkForRetransmission(&manager_, 1, TLP_RETRANSMISSION); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - } - manager_.CancelRetransmissionsForStream(kStreamId); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } - - // There should no longer be a pending retransmission. - EXPECT_FALSE(manager_.HasPendingRetransmissions()); + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -498,7 +416,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenStopRetransmittingBeforeSend) { EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted); } -TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { +TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { SendDataPacket(1); RetransmitAndSendPacket(1, 2); QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15); @@ -512,30 +430,26 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); // 2 remains unacked, but no packets have retransmittable data. uint64_t unacked[] = {2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_TRUE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); - if (manager_.session_decides_what_to_write()) { - // Ack 2 causes 2 be considered as spurious retransmission. - EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)).WillOnce(Return(false)); - ExpectAck(2); - manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), - clock_.Now()); - manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3)); - EXPECT_EQ(PACKETS_NEWLY_ACKED, - manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2), - ENCRYPTION_INITIAL)); - } + // Ack 2 causes 2 be considered as spurious retransmission. + EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)).WillOnce(Return(false)); + ExpectAck(2); + manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2), + ENCRYPTION_INITIAL)); EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted); } -TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { +TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { SendDataPacket(1); RetransmitAndSendPacket(1, 2); QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15); @@ -575,13 +489,11 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { ENCRYPTION_INITIAL)); ExpectAckAndLoss(true, 5, 2); - if (manager_.session_decides_what_to_write()) { - // Frames in all packets are acked. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - // Notify session that stream frame in packet 2 gets lost although it is - // not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); - } + // Frames in all packets are acked. + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); + // Notify session that stream frame in packet 2 gets lost although it is + // not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6)); @@ -590,13 +502,8 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - uint64_t unacked[] = {2}; - VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - } else { - // No packets remain unacked. - VerifyUnackedPackets(nullptr, 0); - } + uint64_t unacked[] = {2}; + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_FALSE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); @@ -605,7 +512,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, DISABLED_RetransmitTwiceThenAckPreviousBeforeSend) { SendDataPacket(1); RetransmitAndSendPacket(1, 2); @@ -614,7 +521,6 @@ TEST_P(QuicSentPacketManagerTest, EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); manager_.OnRetransmissionTimeout(); - EXPECT_TRUE(manager_.HasPendingRetransmissions()); // Ack 1 but not 2, before 2 is able to be sent. // Since 1 has been retransmitted, it has already been lost, and so the @@ -639,17 +545,11 @@ TEST_P(QuicSentPacketManagerTest, EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { +TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { StrictMock debug_delegate; - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmission( - TLP_RETRANSMISSION, kDefaultLength)) - .Times(1); - } else { - EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmission( - TLP_RETRANSMISSION, kDefaultLength)) - .Times(2); - } + EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmission(TLP_RETRANSMISSION, + kDefaultLength)) + .Times(1); manager_.SetDebugDelegate(&debug_delegate); SendDataPacket(1); @@ -666,12 +566,10 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - // Frames in packets 2 and 3 are acked. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .Times(2) - .WillRepeatedly(Return(false)); - } + // Frames in packets 2 and 3 are acked. + EXPECT_CALL(notifier_, IsFrameOutstanding(_)) + .Times(2) + .WillRepeatedly(Return(false)); // 2 and 3 remain unacked, but no packets have retransmittable data. uint64_t unacked[] = {2, 3}; @@ -681,12 +579,10 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { // Ensure packet 2 is lost when 4 is sent and 3 and 4 are acked. SendDataPacket(4); - if (manager_.session_decides_what_to_write()) { - // No new data gets acked in packet 3. - EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)) - .WillOnce(Return(false)) - .WillRepeatedly(Return(true)); - } + // No new data gets acked in packet 3. + EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)) + .WillOnce(Return(false)) + .WillRepeatedly(Return(true)); uint64_t acked[] = {3, 4}; ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(), @@ -705,13 +601,11 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { ExpectAckAndLoss(true, 5, 2); EXPECT_CALL(debug_delegate, OnPacketLoss(QuicPacketNumber(2), LOSS_RETRANSMISSION, _)); - if (manager_.session_decides_what_to_write()) { - // Frames in all packets are acked. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - // Notify session that stream frame in packet 2 gets lost although it is - // not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); - } + // Frames in all packets are acked. + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); + // Notify session that stream frame in packet 2 gets lost although it is + // not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6)); @@ -720,23 +614,15 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - uint64_t unacked[] = {2}; - VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - } else { - VerifyUnackedPackets(nullptr, 0); - } + uint64_t unacked3[] = {2}; + VerifyUnackedPackets(unacked3, QUIC_ARRAYSIZE(unacked3)); EXPECT_FALSE(manager_.HasInFlightPackets()); - if (manager_.session_decides_what_to_write()) { - // Spurious retransmission is detected when packet 3 gets acked. We cannot - // know packet 2 is a spurious until it gets acked. - EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted); - } else { - EXPECT_EQ(2u, stats_.packets_spuriously_retransmitted); - } + // Spurious retransmission is detected when packet 3 gets acked. We cannot + // know packet 2 is a spurious until it gets acked. + EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted); } -TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) { +TEST_F(QuicSentPacketManagerTest, AckOriginalTransmission) { auto loss_algorithm = std::make_unique(); QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm.get()); @@ -777,15 +663,9 @@ TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) { uint64_t acked[] = {3}; ExpectAcksAndLosses(false, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _)); - if (GetQuicReloadableFlag(quic_detect_spurious_loss) && - manager_.session_decides_what_to_write()) { - EXPECT_CALL(*loss_algorithm, - SpuriousLossDetected(_, _, _, QuicPacketNumber(3), - QuicPacketNumber(4))); - } else { - EXPECT_CALL(*loss_algorithm, - SpuriousRetransmitDetected(_, _, _, QuicPacketNumber(5))); - } + EXPECT_CALL(*loss_algorithm, + SpuriousLossDetected(_, _, _, QuicPacketNumber(3), + QuicPacketNumber(4))); manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5)); @@ -793,34 +673,32 @@ TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - // Ack 3 will not cause 5 be considered as a spurious retransmission. Ack - // 5 will cause 5 be considered as a spurious retransmission as no new - // data gets acked. - ExpectAck(5); - EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _)); - EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)).WillOnce(Return(false)); - manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), - clock_.Now()); - manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6)); - manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); - EXPECT_EQ(PACKETS_NEWLY_ACKED, - manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4), - ENCRYPTION_INITIAL)); - } + // Ack 3 will not cause 5 be considered as a spurious retransmission. Ack + // 5 will cause 5 be considered as a spurious retransmission as no new + // data gets acked. + ExpectAck(5); + EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _)); + EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)).WillOnce(Return(false)); + manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6)); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4), + ENCRYPTION_INITIAL)); } } -TEST_P(QuicSentPacketManagerTest, GetLeastUnacked) { +TEST_F(QuicSentPacketManagerTest, GetLeastUnacked) { EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked()); } -TEST_P(QuicSentPacketManagerTest, GetLeastUnackedUnacked) { +TEST_F(QuicSentPacketManagerTest, GetLeastUnackedUnacked) { SendDataPacket(1); EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked()); } -TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { +TEST_F(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { EXPECT_FALSE(manager_.largest_packet_peer_knows_is_acked().IsInitialized()); SendDataPacket(1); SendAckPacket(2, 1); @@ -851,7 +729,7 @@ TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { manager_.largest_packet_peer_knows_is_acked()); } -TEST_P(QuicSentPacketManagerTest, Rtt) { +TEST_F(QuicSentPacketManagerTest, Rtt) { QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(20); SendDataPacket(1); clock_.AdvanceTime(expected_rtt); @@ -866,7 +744,7 @@ TEST_P(QuicSentPacketManagerTest, Rtt) { EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } -TEST_P(QuicSentPacketManagerTest, RttWithInvalidDelta) { +TEST_F(QuicSentPacketManagerTest, RttWithInvalidDelta) { // Expect that the RTT is equal to the local time elapsed, since the // ack_delay_time is larger than the local time elapsed // and is hence invalid. @@ -884,7 +762,7 @@ TEST_P(QuicSentPacketManagerTest, RttWithInvalidDelta) { EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } -TEST_P(QuicSentPacketManagerTest, RttWithInfiniteDelta) { +TEST_F(QuicSentPacketManagerTest, RttWithInfiniteDelta) { // Expect that the RTT is equal to the local time elapsed, since the // ack_delay_time is infinite, and is hence invalid. QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10); @@ -901,7 +779,7 @@ TEST_P(QuicSentPacketManagerTest, RttWithInfiniteDelta) { EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } -TEST_P(QuicSentPacketManagerTest, RttZeroDelta) { +TEST_F(QuicSentPacketManagerTest, RttZeroDelta) { // Expect that the RTT is the time between send and receive since the // ack_delay_time is zero. QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10); @@ -918,7 +796,7 @@ TEST_P(QuicSentPacketManagerTest, RttZeroDelta) { EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } -TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { +TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) { QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send 1 packet. @@ -927,36 +805,20 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { // The first tail loss probe retransmits 1 packet. manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); manager_.MaybeRetransmitTailLossProbe(); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(2); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } // The second tail loss probe retransmits 1 packet. manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); manager_.MaybeRetransmitTailLossProbe(); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(3); - } EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); // Ack the third and ensure the first two are still pending. ExpectAck(3); @@ -977,13 +839,11 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { uint64_t lost[] = {1, 2}; ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), lost, QUIC_ARRAYSIZE(lost)); - if (manager_.session_decides_what_to_write()) { - // Frames in all packets are acked. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - // Notify session that stream frame in packets 1 and 2 get lost although - // they are not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); - } + // Frames in all packets are acked. + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); + // Notify session that stream frame in packets 1 and 2 get lost although + // they are not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6)); @@ -991,13 +851,12 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2), ENCRYPTION_INITIAL)); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_FALSE(manager_.HasInFlightPackets()); EXPECT_EQ(2u, stats_.tlp_count); EXPECT_EQ(0u, stats_.rto_count); } -TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { +TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) { QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send 100 packets. @@ -1012,38 +871,21 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { // The first tail loss probe retransmits 1 packet. manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(101, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(101, type); }))); manager_.MaybeRetransmitTailLossProbe(); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(101); - } EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); clock_.AdvanceTime(manager_.GetRetransmissionTime() - clock_.Now()); // The second tail loss probe retransmits 1 packet. manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(102, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(102, type); }))); EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe()); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(102); - } EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now())); @@ -1055,43 +897,29 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { // Advance the time enough to ensure all packets are RTO'd. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(103, type); - }))) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(104, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(103, type); }))) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(104, type); }))); manager_.OnRetransmissionTimeout(); EXPECT_EQ(2u, stats_.tlp_count); EXPECT_EQ(1u, stats_.rto_count); - if (manager_.session_decides_what_to_write()) { - // There are 2 RTO retransmissions. - EXPECT_EQ(104 * kDefaultLength, manager_.GetBytesInFlight()); - } - if (!manager_.session_decides_what_to_write()) { - // Send and Ack the RTO and ensure OnRetransmissionTimeout is called. - EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(103); - } + // There are 2 RTO retransmissions. + EXPECT_EQ(104 * kDefaultLength, manager_.GetBytesInFlight()); QuicPacketNumber largest_acked = QuicPacketNumber(103); EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent( true, _, _, Pointwise(PacketNumberEq(), {largest_acked}), _)); EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); - if (manager_.session_decides_what_to_write()) { - // Although frames in packet 3 gets acked, it would be kept for another - // RTT. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); - // Packets [1, 102] are lost, although stream frame in packet 3 is not - // outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102); - } + // Although frames in packet 3 gets acked, it would be kept for another + // RTT. + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); + // Packets [1, 102] are lost, although stream frame in packet 3 is not + // outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102); manager_.OnAckFrameStart(QuicPacketNumber(103), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(103), QuicPacketNumber(104)); @@ -1099,15 +927,11 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); // All packets before 103 should be lost. - if (manager_.session_decides_what_to_write()) { - // Packet 104 is still in flight. - EXPECT_EQ(1000u, manager_.GetBytesInFlight()); - } else { - EXPECT_EQ(0u, manager_.GetBytesInFlight()); - } + // Packet 104 is still in flight. + EXPECT_EQ(1000u, manager_.GetBytesInFlight()); } -TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { // Send 2 crypto packets and 3 data packets. const size_t kNumSentCryptoPackets = 2; for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) { @@ -1121,37 +945,21 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { EXPECT_EQ(5 * kDefaultLength, manager_.GetBytesInFlight()); // The first retransmits 2 packets. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(6); })) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(7); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(6); })) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(7); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - RetransmitNextPacket(6); - RetransmitNextPacket(7); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } // Expect all 4 handshake packets to be in flight and 3 data packets. EXPECT_EQ(7 * kDefaultLength, manager_.GetBytesInFlight()); EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // The second retransmits 2 packets. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(8); })) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(9); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(8); })) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(9); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - RetransmitNextPacket(8); - RetransmitNextPacket(9); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } EXPECT_EQ(9 * kDefaultLength, manager_.GetBytesInFlight()); EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); @@ -1162,13 +970,8 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { uint64_t lost[] = {1, 2, 6}; ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), lost, QUIC_ARRAYSIZE(lost)); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(3); - } - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, HasUnackedCryptoData()) - .WillRepeatedly(Return(false)); - } + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(3); + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); manager_.OnAckFrameStart(QuicPacketNumber(9), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10)); @@ -1180,7 +983,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); } -TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { // Send 2 crypto packets and 3 data packets. const size_t kNumSentCryptoPackets = 2; for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) { @@ -1192,51 +995,26 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { } EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(6); })) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(7); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(6); })) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(7); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(6); - RetransmitNextPacket(7); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Now act like a version negotiation packet arrived, which would cause all // unacked packets to be retransmitted. - if (manager_.session_decides_what_to_write()) { - // Mark packets [1, 7] lost. And the frames in 6 and 7 are same as packets 1 - // and 2, respectively. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(7); - } + // Mark packets [1, 7] lost. And the frames in 6 and 7 are same as packets 1 + // and 2, respectively. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(7); manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); // Ensure the first two pending packets are the crypto retransmits. - if (manager_.session_decides_what_to_write()) { - RetransmitCryptoPacket(8); - RetransmitCryptoPacket(9); - RetransmitDataPacket(10, ALL_UNACKED_RETRANSMISSION); - RetransmitDataPacket(11, ALL_UNACKED_RETRANSMISSION); - RetransmitDataPacket(12, ALL_UNACKED_RETRANSMISSION); - } else { - ASSERT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(QuicPacketNumber(6u), - manager_.NextPendingRetransmission().packet_number); - RetransmitNextPacket(8); - EXPECT_EQ(QuicPacketNumber(7u), - manager_.NextPendingRetransmission().packet_number); - RetransmitNextPacket(9); - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - // Send 3 more data packets and ensure the least unacked is raised. - RetransmitNextPacket(10); - RetransmitNextPacket(11); - RetransmitNextPacket(12); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + RetransmitCryptoPacket(8); + RetransmitCryptoPacket(9); + RetransmitDataPacket(10, ALL_UNACKED_RETRANSMISSION); + RetransmitDataPacket(11, ALL_UNACKED_RETRANSMISSION); + RetransmitDataPacket(12, ALL_UNACKED_RETRANSMISSION); EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked()); // Least unacked isn't raised until an ack is received, so ack the @@ -1249,47 +1027,31 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, HasUnackedCryptoData()) - .WillRepeatedly(Return(false)); - } + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); EXPECT_EQ(QuicPacketNumber(10u), manager_.GetLeastUnacked()); } -TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { // Send 1 crypto packet. SendCryptoPacket(1); EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 2. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(2); - } // Retransmit the crypto packet as 3. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(3); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(3); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(3); - } // Now ack the second crypto packet, and ensure the first gets removed, but // the third does not. uint64_t acked[] = {2}; ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, HasUnackedCryptoData()) - .WillRepeatedly(Return(false)); - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3)); @@ -1302,7 +1064,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); } -TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { // Send 2 crypto packets and 1 data packet. const size_t kNumSentCryptoPackets = 2; for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) { @@ -1312,22 +1074,15 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit 2 crypto packets, but not the serialized packet. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(4); })) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(5); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(4); })) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(5); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(4); - RetransmitNextPacket(5); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeRetransmissionThenRetransmitAll) { // Send 1 crypto packet. SendCryptoPacket(1); @@ -1335,36 +1090,21 @@ TEST_P(QuicSentPacketManagerTest, EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 2. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(2); - } // Now retransmit all the unacked packets, which occurs when there is a // version negotiation. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); - } + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); - if (manager_.session_decides_what_to_write()) { - // Both packets 1 and 2 are unackable. - EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(1))); - EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(2))); - } else { - // Packet 2 is useful because it does not get retransmitted and still has - // retransmittable frames. - uint64_t unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - } + // Both packets 1 and 2 are unackable. + EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(1))); + EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(2))); EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); EXPECT_FALSE(manager_.HasInFlightPackets()); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeRetransmissionThenNeuterAndAck) { // Send 1 crypto packet. SendCryptoPacket(1); @@ -1372,40 +1112,26 @@ TEST_P(QuicSentPacketManagerTest, EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 2. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(2); - } EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 3. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(3); })); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(3); })); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(3); - } EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Now neuter all unacked unencrypted packets, which occurs when the // connection goes forward secure. + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); manager_.NeuterUnencryptedPackets(); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, HasUnackedCryptoData()) - .WillRepeatedly(Return(false)); - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); uint64_t unacked[] = {1, 2, 3}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); EXPECT_FALSE(manager_.HasInFlightPackets()); @@ -1422,7 +1148,7 @@ TEST_P(QuicSentPacketManagerTest, VerifyRetransmittablePackets(nullptr, 0); } -TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) { +TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) { StrictMock debug_delegate; manager_.SetDebugDelegate(&debug_delegate); @@ -1433,27 +1159,14 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) { } EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(101, type); - }))) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(102, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(101, type); }))) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(102, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - ASSERT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(100 * kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(101); - ASSERT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(102); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); // Ack a retransmission. // Ensure no packets are lost. @@ -1470,12 +1183,10 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) { EXPECT_CALL(debug_delegate, OnPacketLoss(QuicPacketNumber(i), LOSS_RETRANSMISSION, _)); } - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); - // Packets [1, 99] are considered as lost, although stream frame in packet - // 2 is not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); + // Packets [1, 99] are considered as lost, although stream frame in packet + // 2 is not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103)); @@ -1484,7 +1195,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) { ENCRYPTION_INITIAL)); } -TEST_P(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) { +TEST_F(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) { // Set the 1RTO connection option. QuicConfig client_config; QuicTagVector options; @@ -1510,25 +1221,15 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) { } EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(1) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(101, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(1) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(101, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(101 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - ASSERT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(100 * kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(101); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(101 * kDefaultLength, manager_.GetBytesInFlight()); } -TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) { +TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) { QuicConfig client_config; QuicTagVector options; options.push_back(kNRTO); @@ -1551,26 +1252,14 @@ TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) { } EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(101, type); - }))) - .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { - RetransmitDataPacket(102, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(101, type); }))) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(102, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(100 * kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(101); - RetransmitNextPacket(102); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); // Ack a retransmission and expect no call to OnRetransmissionTimeout. // This will include packets in the lost packet map. @@ -1580,12 +1269,10 @@ TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) { Pointwise(PacketNumberEq(), {largest_acked}), /*lost_packets=*/Not(IsEmpty()))); EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); - // Packets [1, 99] are considered as lost, although stream frame in packet - // 2 is not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); + // Packets [1, 99] are considered as lost, although stream frame in packet + // 2 is not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103)); @@ -1594,40 +1281,22 @@ TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) { ENCRYPTION_INITIAL)); } -TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { +TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { // Send 1 packet. SendDataPacket(1); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(2); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); // Rto a second time. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(3 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(3); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(3 * kDefaultLength, manager_.GetBytesInFlight()); // Ack a retransmission and ensure OnRetransmissionTimeout is called. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); @@ -1643,40 +1312,22 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); } -TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { +TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { // Send 1 packet. SendDataPacket(1); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(2, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(2); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); // Rto a second time. - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); manager_.OnRetransmissionTimeout(); - if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(3 * kDefaultLength, manager_.GetBytesInFlight()); - } else { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(3); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - } + EXPECT_EQ(3 * kDefaultLength, manager_.GetBytesInFlight()); // Ack a retransmission and ensure OnRetransmissionTimeout is called. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); @@ -1692,11 +1343,11 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); } -TEST_P(QuicSentPacketManagerTest, GetTransmissionTime) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionTime) { EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { QuicTime crypto_packet_send_time = clock_.Now(); SendCryptoPacket(1); @@ -1715,16 +1366,11 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { // Retransmit the packet by invoking the retransmission timeout. clock_.AdvanceTime(1.5 * srtt); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); - // When session decides what to write, crypto_packet_send_time gets updated. - crypto_packet_send_time = clock_.Now(); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); + // When session decides what to write, crypto_packet_send_time gets updated. + crypto_packet_send_time = clock_.Now(); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(2); - } // The retransmission time should now be twice as far in the future. expected_time = crypto_packet_send_time + srtt * 2 * 1.5; @@ -1732,23 +1378,18 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { // Retransmit the packet for the 2nd time. clock_.AdvanceTime(2 * 1.5 * srtt); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(3); })); - // When session decides what to write, crypto_packet_send_time gets updated. - crypto_packet_send_time = clock_.Now(); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(3); })); + // When session decides what to write, crypto_packet_send_time gets updated. + crypto_packet_send_time = clock_.Now(); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(3); - } // Verify exponential backoff of the retransmission timeout. expected_time = crypto_packet_send_time + srtt * 4 * 1.5; EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, GetConservativeTransmissionTimeCryptoHandshake) { QuicConfig config; QuicTagVector options; @@ -1781,22 +1422,17 @@ TEST_P(QuicSentPacketManagerTest, // Retransmit the packet by invoking the retransmission timeout. clock_.AdvanceTime(2 * srtt); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); - crypto_packet_send_time = clock_.Now(); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); + crypto_packet_send_time = clock_.Now(); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(2); - } // The retransmission time should now be twice as far in the future. expected_time = crypto_packet_send_time + srtt * 2 * 2; EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) { QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); SendDataPacket(1); SendDataPacket(2); @@ -1818,30 +1454,18 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) { clock_.AdvanceTime(expected_tlp_delay); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); - } - EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe()); - if (!manager_.session_decides_what_to_write()) { - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - RetransmitNextPacket(3); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); + EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe()); EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); expected_time = clock_.Now() + expected_tlp_delay; EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { - if (!manager_.session_decides_what_to_write()) { - return; - } - +TEST_F(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { QuicConfig config; QuicTagVector options; @@ -1877,7 +1501,6 @@ TEST_P(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { clock_.AdvanceTime(expected_tlp_delay); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_CALL(notifier_, RetransmitFrames(_, _)) .WillOnce(WithArgs<1>(Invoke( [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); @@ -1885,7 +1508,6 @@ TEST_P(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); // 2nd TLP. expected_tlp_delay = 2 * srtt; @@ -1893,11 +1515,7 @@ TEST_P(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { manager_.GetRetransmissionTime() - clock_.Now()); } -TEST_P(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) { - if (!manager_.session_decides_what_to_write()) { - return; - } - +TEST_F(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) { QuicConfig config; QuicTagVector options; @@ -1932,14 +1550,12 @@ TEST_P(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) { clock_.AdvanceTime(expected_tlp_delay); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_CALL(notifier_, RetransmitFrames(_, _)) .WillOnce(WithArgs<1>(Invoke( [this](TransmissionType type) { RetransmitDataPacket(3, type); }))); EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe()); EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now())); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); // 2nd TLP. expected_tlp_delay = 2 * srtt; @@ -1947,7 +1563,7 @@ TEST_P(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) { manager_.GetRetransmissionTime() - clock_.Now()); } -TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), QuicTime::Delta::Zero(), QuicTime::Zero()); @@ -1964,24 +1580,15 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { // Retransmit the packet by invoking the retransmission timeout. clock_.AdvanceTime(expected_rto_delay); - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(5, type); }))) - .WillOnce(WithArgs<1>(Invoke( - [this](TransmissionType type) { RetransmitDataPacket(6, type); }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(5, type); }))) + .WillOnce(WithArgs<1>(Invoke( + [this](TransmissionType type) { RetransmitDataPacket(6, type); }))); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - // All packets are still considered inflight. - EXPECT_EQ(4 * kDefaultLength, manager_.GetBytesInFlight()); - RetransmitNextPacket(5); - RetransmitNextPacket(6); - } // All previous packets are inflight, plus two rto retransmissions. EXPECT_EQ(6 * kDefaultLength, manager_.GetBytesInFlight()); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); // The delay should double the second time. expected_time = clock_.Now() + expected_rto_delay + expected_rto_delay; @@ -1998,7 +1605,6 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); - EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_EQ(5 * kDefaultLength, manager_.GetBytesInFlight()); // Wait 2RTTs from now for the RTO, since it's the max of the RTO time @@ -2011,7 +1617,7 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMin) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) { SendDataPacket(1); // Provide a 1ms RTT sample. const_cast(manager_.GetRttStats()) @@ -2027,20 +1633,15 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMin) { EXPECT_EQ(delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, i)); delay = delay + delay; - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke([this, i](TransmissionType type) { - RetransmitDataPacket(i + 2, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this, i](TransmissionType type) { + RetransmitDataPacket(i + 2, type); + }))); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(i + 2); - } } } -TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMax) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMax) { SendDataPacket(1); // Provide a 60s RTT sample. const_cast(manager_.GetRttStats()) @@ -2053,7 +1654,7 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMax) { QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); } -TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { +TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { SendDataPacket(1); QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500); @@ -2064,20 +1665,15 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { EXPECT_EQ(delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, i)); delay = delay + delay; - if (manager_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(WithArgs<1>(Invoke([this, i](TransmissionType type) { - RetransmitDataPacket(i + 2, type); - }))); - } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this, i](TransmissionType type) { + RetransmitDataPacket(i + 2, type); + }))); manager_.OnRetransmissionTimeout(); - if (!manager_.session_decides_what_to_write()) { - RetransmitNextPacket(i + 2); - } } } -TEST_P(QuicSentPacketManagerTest, RetransmissionDelay) { +TEST_F(QuicSentPacketManagerTest, RetransmissionDelay) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); const int64_t kRttMs = 250; const int64_t kDeviationMs = 5; @@ -2115,7 +1711,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionDelay) { QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); } -TEST_P(QuicSentPacketManagerTest, GetLossDelay) { +TEST_F(QuicSentPacketManagerTest, GetLossDelay) { auto loss_algorithm = std::make_unique(); QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm.get()); @@ -2146,7 +1742,7 @@ TEST_P(QuicSentPacketManagerTest, GetLossDelay) { manager_.OnRetransmissionTimeout(); } -TEST_P(QuicSentPacketManagerTest, NegotiateTimeLossDetectionFromOptions) { +TEST_F(QuicSentPacketManagerTest, NegotiateTimeLossDetectionFromOptions) { EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) ->GetLossDetectionType()); @@ -2162,7 +1758,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateTimeLossDetectionFromOptions) { ->GetLossDetectionType()); } -TEST_P(QuicSentPacketManagerTest, NegotiateIetfLossDetectionFromOptions) { +TEST_F(QuicSentPacketManagerTest, NegotiateIetfLossDetectionFromOptions) { SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true); EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) ->GetLossDetectionType()); @@ -2183,7 +1779,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateIetfLossDetectionFromOptions) { QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, NegotiateIetfLossDetectionOneFourthRttFromOptions) { SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true); EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) @@ -2206,10 +1802,9 @@ TEST_P(QuicSentPacketManagerTest, QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, NegotiateIetfLossDetectionAdaptiveReorderingThreshold) { SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true); - SetQuicReloadableFlag(quic_detect_spurious_loss, true); EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) ->GetLossDetectionType()); EXPECT_FALSE( @@ -2231,10 +1826,9 @@ TEST_P(QuicSentPacketManagerTest, QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, NegotiateIetfLossDetectionAdaptiveReorderingThreshold2) { SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true); - SetQuicReloadableFlag(quic_detect_spurious_loss, true); EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) ->GetLossDetectionType()); EXPECT_FALSE( @@ -2257,7 +1851,36 @@ TEST_P(QuicSentPacketManagerTest, QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); } -TEST_P(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) { +TEST_F(QuicSentPacketManagerTest, + NegotiateIetfLossDetectionAdaptiveReorderingAndTimeThreshold) { + SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true); + EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) + ->GetLossDetectionType()); + EXPECT_FALSE( + QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); + EXPECT_FALSE( + QuicSentPacketManagerPeer::AdaptiveTimeThresholdEnabled(&manager_)); + + QuicConfig config; + QuicTagVector options; + options.push_back(kILD4); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + + EXPECT_EQ(kIetfLossDetection, + QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) + ->GetLossDetectionType()); + EXPECT_EQ(kDefaultLossDelayShift, + QuicSentPacketManagerPeer::GetReorderingShift(&manager_)); + EXPECT_TRUE( + QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); + EXPECT_TRUE( + QuicSentPacketManagerPeer::AdaptiveTimeThresholdEnabled(&manager_)); +} + +TEST_F(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) { QuicConfig config; QuicTagVector options; @@ -2293,7 +1916,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) { ->GetCongestionControlType()); } -TEST_P(QuicSentPacketManagerTest, NegotiateClientCongestionControlFromOptions) { +TEST_F(QuicSentPacketManagerTest, NegotiateClientCongestionControlFromOptions) { QuicConfig config; QuicTagVector options; @@ -2340,7 +1963,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateClientCongestionControlFromOptions) { ->GetCongestionControlType()); } -TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { +TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { QuicConfig config; QuicTagVector options; @@ -2362,11 +1985,8 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); - // Send two packets, and the TLP should be 2 us or 1ms. - QuicTime::Delta expected_tlp_delay = - GetQuicReloadableFlag(quic_sent_packet_manager_cleanup) - ? QuicTime::Delta::FromMilliseconds(1) - : QuicTime::Delta::FromMicroseconds(2); + // Send two packets, and the TLP should be 1ms. + QuicTime::Delta expected_tlp_delay = QuicTime::Delta::FromMilliseconds(1); SendDataPacket(1); SendDataPacket(2); EXPECT_EQ(expected_tlp_delay, @@ -2375,7 +1995,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } -TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) { +TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) { QuicConfig client_config; QuicTagVector options; @@ -2397,11 +2017,8 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) { QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); - // Send two packets, and the TLP should be 2 us or 1ms. - QuicTime::Delta expected_tlp_delay = - GetQuicReloadableFlag(quic_sent_packet_manager_cleanup) - ? QuicTime::Delta::FromMilliseconds(1) - : QuicTime::Delta::FromMicroseconds(2); + // Send two packets, and the TLP should be 1ms. + QuicTime::Delta expected_tlp_delay = QuicTime::Delta::FromMilliseconds(1); SendDataPacket(1); SendDataPacket(2); EXPECT_EQ(expected_tlp_delay, @@ -2410,70 +2027,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) { QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } -TEST_P(QuicSentPacketManagerTest, NegotiateIETFTLPFromOptionsAtServer) { - if (GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - return; - } - QuicConfig config; - QuicTagVector options; - - options.push_back(kMAD4); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - manager_.SetFromConfig(config); - // Provide an RTT measurement of 100ms. - RttStats* rtt_stats = const_cast(manager_.GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), - QuicTime::Delta::Zero(), QuicTime::Zero()); - // Expect 1.5x * SRTT + 0ms MAD - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); - // Expect 1.5x * SRTT + 50ms MAD - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(150), - QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats->smoothed_rtt()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); -} - -TEST_P(QuicSentPacketManagerTest, NegotiateIETFTLPFromOptionsAtClient) { - if (GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) { - return; - } - QuicConfig client_config; - QuicTagVector options; - - options.push_back(kMAD4); - QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); - client_config.SetConnectionOptionsToSend(options); - EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - manager_.SetFromConfig(client_config); - // Provide an RTT measurement of 100ms. - RttStats* rtt_stats = const_cast(manager_.GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), - QuicTime::Delta::Zero(), QuicTime::Zero()); - // Expect 1.5x * SRTT + 0ms MAD - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); - // Expect 1.5x * SRTT + 50ms MAD - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(150), - QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats->smoothed_rtt()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), - QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); -} - -TEST_P(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) { +TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) { QuicConfig config; QuicTagVector options; @@ -2486,26 +2040,20 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); rtt_stats->UpdateRtt(QuicTime::Delta::FromMicroseconds(1), QuicTime::Delta::Zero(), QuicTime::Zero()); - QuicTime::Delta expected_rto_delay = - GetQuicReloadableFlag(quic_sent_packet_manager_cleanup) - ? QuicTime::Delta::FromMilliseconds(1) - : QuicTime::Delta::FromMicroseconds(1); + QuicTime::Delta expected_rto_delay = QuicTime::Delta::FromMilliseconds(1); EXPECT_EQ(expected_rto_delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); EXPECT_EQ(expected_rto_delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); // The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(0ms). - QuicTime::Delta expected_tlp_delay = - GetQuicReloadableFlag(quic_sent_packet_manager_cleanup) - ? QuicTime::Delta::FromMicroseconds(502) - : QuicTime::Delta::FromMicroseconds(2); + QuicTime::Delta expected_tlp_delay = QuicTime::Delta::FromMicroseconds(502); EXPECT_EQ(expected_tlp_delay, QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); EXPECT_EQ(expected_tlp_delay, QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } -TEST_P(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) { +TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) { QuicConfig client_config; QuicTagVector options; @@ -2519,26 +2067,20 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); rtt_stats->UpdateRtt(QuicTime::Delta::FromMicroseconds(1), QuicTime::Delta::Zero(), QuicTime::Zero()); - QuicTime::Delta expected_rto_delay = - GetQuicReloadableFlag(quic_sent_packet_manager_cleanup) - ? QuicTime::Delta::FromMilliseconds(1) - : QuicTime::Delta::FromMicroseconds(1); + QuicTime::Delta expected_rto_delay = QuicTime::Delta::FromMilliseconds(1); EXPECT_EQ(expected_rto_delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); EXPECT_EQ(expected_rto_delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); // The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(0ms). - QuicTime::Delta expected_tlp_delay = - GetQuicReloadableFlag(quic_sent_packet_manager_cleanup) - ? QuicTime::Delta::FromMicroseconds(502) - : QuicTime::Delta::FromMicroseconds(2); + QuicTime::Delta expected_tlp_delay = QuicTime::Delta::FromMicroseconds(502); EXPECT_EQ(expected_tlp_delay, QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); EXPECT_EQ(expected_tlp_delay, QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } -TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) { +TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) { QuicConfig config; QuicTagVector options; @@ -2550,7 +2092,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) { EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); } -TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) { +TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) { QuicConfig client_config; QuicTagVector options; @@ -2563,7 +2105,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) { EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); } -TEST_P(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) { +TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) { QuicConfig config; QuicTagVector options; @@ -2575,7 +2117,7 @@ TEST_P(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) { EXPECT_EQ(1u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); } -TEST_P(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) { +TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) { QuicConfig client_config; QuicTagVector options; @@ -2588,7 +2130,7 @@ TEST_P(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) { EXPECT_EQ(1u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); } -TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) { +TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) { QuicConfig config; QuicTagVector options; @@ -2601,7 +2143,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) { QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_)); } -TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) { +TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) { QuicConfig client_config; QuicTagVector options; @@ -2615,7 +2157,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) { QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_)); } -TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) { +TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) { EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_)); QuicConfig config; QuicTagVector options; @@ -2628,7 +2170,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) { EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_)); } -TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) { +TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) { EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_)); QuicConfig client_config; QuicTagVector options; @@ -2642,7 +2184,7 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) { EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_)); } -TEST_P(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) { +TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) { QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(325); EXPECT_NE(initial_rtt, manager_.GetRttStats()->smoothed_rtt()); @@ -2656,22 +2198,26 @@ TEST_P(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) { EXPECT_EQ(initial_rtt, manager_.GetRttStats()->initial_rtt()); } -TEST_P(QuicSentPacketManagerTest, ResumeConnectionState) { +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); CachedNetworkParameters cached_network_params; cached_network_params.set_min_rtt_ms(kRtt.ToMilliseconds()); - EXPECT_CALL(*send_algorithm_, - AdjustNetworkParameters(QuicBandwidth::Zero(), kRtt, false)); + SendAlgorithmInterface::NetworkParams params; + params.bandwidth = QuicBandwidth::Zero(); + params.allow_cwnd_to_decrease = false; + params.rtt = kRtt; + + EXPECT_CALL(*send_algorithm_, AdjustNetworkParameters(params)); EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) .Times(testing::AnyNumber()); manager_.ResumeConnectionState(cached_network_params, false); EXPECT_EQ(kRtt, manager_.GetRttStats()->initial_rtt()); } -TEST_P(QuicSentPacketManagerTest, ConnectionMigrationUnspecifiedChange) { +TEST_F(QuicSentPacketManagerTest, ConnectionMigrationUnspecifiedChange) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); QuicTime::Delta default_init_rtt = rtt_stats->initial_rtt(); rtt_stats->set_initial_rtt(default_init_rtt * 2); @@ -2690,7 +2236,7 @@ TEST_P(QuicSentPacketManagerTest, ConnectionMigrationUnspecifiedChange) { EXPECT_EQ(0u, manager_.GetConsecutiveTlpCount()); } -TEST_P(QuicSentPacketManagerTest, ConnectionMigrationIPSubnetChange) { +TEST_F(QuicSentPacketManagerTest, ConnectionMigrationIPSubnetChange) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); QuicTime::Delta default_init_rtt = rtt_stats->initial_rtt(); rtt_stats->set_initial_rtt(default_init_rtt * 2); @@ -2708,7 +2254,7 @@ TEST_P(QuicSentPacketManagerTest, ConnectionMigrationIPSubnetChange) { EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount()); } -TEST_P(QuicSentPacketManagerTest, ConnectionMigrationPortChange) { +TEST_F(QuicSentPacketManagerTest, ConnectionMigrationPortChange) { RttStats* rtt_stats = const_cast(manager_.GetRttStats()); QuicTime::Delta default_init_rtt = rtt_stats->initial_rtt(); rtt_stats->set_initial_rtt(default_init_rtt * 2); @@ -2726,13 +2272,13 @@ TEST_P(QuicSentPacketManagerTest, ConnectionMigrationPortChange) { EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount()); } -TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) { +TEST_F(QuicSentPacketManagerTest, PathMtuIncreased) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), QuicPacketNumber(1), _, _)); SerializedPacket packet(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength + 100, false, false); - manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); // Ack the large packet and expect the path MTU to increase. ExpectAck(1); @@ -2747,7 +2293,7 @@ TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) { ENCRYPTION_INITIAL)); } -TEST_P(QuicSentPacketManagerTest, OnAckRangeSlowPath) { +TEST_F(QuicSentPacketManagerTest, OnAckRangeSlowPath) { // Send packets 1 - 20. for (size_t i = 1; i <= 20; ++i) { SendDataPacket(i); @@ -2782,7 +2328,7 @@ TEST_P(QuicSentPacketManagerTest, OnAckRangeSlowPath) { ENCRYPTION_INITIAL)); } -TEST_P(QuicSentPacketManagerTest, TolerateReneging) { +TEST_F(QuicSentPacketManagerTest, TolerateReneging) { // Send packets 1 - 20. for (size_t i = 1; i <= 20; ++i) { SendDataPacket(i); @@ -2815,7 +2361,7 @@ TEST_P(QuicSentPacketManagerTest, TolerateReneging) { EXPECT_EQ(QuicPacketNumber(16), manager_.GetLargestObserved()); } -TEST_P(QuicSentPacketManagerTest, MultiplePacketNumberSpaces) { +TEST_F(QuicSentPacketManagerTest, MultiplePacketNumberSpaces) { manager_.EnableMultiplePacketNumberSpacesSupport(); EXPECT_FALSE( manager_.GetLargestSentPacket(ENCRYPTION_INITIAL).IsInitialized()); @@ -2927,7 +2473,7 @@ TEST_P(QuicSentPacketManagerTest, MultiplePacketNumberSpaces) { manager_.GetLargestAckedPacket(ENCRYPTION_FORWARD_SECURE)); } -TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace) { +TEST_F(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace) { manager_.EnableMultiplePacketNumberSpacesSupport(); // Send packet 1. SendDataPacket(1, ENCRYPTION_INITIAL); @@ -2944,7 +2490,7 @@ TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace) { ENCRYPTION_INITIAL)); } -TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace2) { +TEST_F(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace2) { manager_.EnableMultiplePacketNumberSpacesSupport(); // Send packet 1. SendDataPacket(1, ENCRYPTION_INITIAL); @@ -2961,7 +2507,7 @@ TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace2) { ENCRYPTION_HANDSHAKE)); } -TEST_P(QuicSentPacketManagerTest, +TEST_F(QuicSentPacketManagerTest, ToleratePacketsGetAckedInWrongPacketNumberSpace) { manager_.EnableMultiplePacketNumberSpacesSupport(); // Send packet 1. @@ -2992,10 +2538,7 @@ TEST_P(QuicSentPacketManagerTest, } // Regression test for b/133771183. -TEST_P(QuicSentPacketManagerTest, PacketInLimbo) { - if (!manager_.session_decides_what_to_write()) { - return; - } +TEST_F(QuicSentPacketManagerTest, PacketInLimbo) { QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send SHLO. SendCryptoPacket(1); @@ -3047,10 +2590,7 @@ TEST_P(QuicSentPacketManagerTest, PacketInLimbo) { ENCRYPTION_INITIAL)); } -TEST_P(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) { - if (!manager_.session_decides_what_to_write()) { - return; - } +TEST_F(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) { // Send 10 packets. for (size_t i = 1; i <= 10; ++i) { SendDataPacket(i); @@ -3070,15 +2610,11 @@ TEST_P(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0); manager_.OnRetransmissionTimeout(); EXPECT_EQ(2u, stats_.rto_count); - if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) { - // Verify a credit is raised up. - EXPECT_EQ(1u, manager_.pending_timer_transmission_count()); - } else { - EXPECT_EQ(0u, manager_.pending_timer_transmission_count()); - } + // Verify a credit is raised up. + EXPECT_EQ(1u, manager_.pending_timer_transmission_count()); } -TEST_P(QuicSentPacketManagerTest, ComputingProbeTimeout) { +TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { EnablePto(k2PTO); EXPECT_CALL(*send_algorithm_, PacingRate(_)) .WillRepeatedly(Return(QuicBandwidth::Zero())); @@ -3144,7 +2680,7 @@ TEST_P(QuicSentPacketManagerTest, ComputingProbeTimeout) { EXPECT_EQ(sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); } -TEST_P(QuicSentPacketManagerTest, SendOneProbePacket) { +TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) { EnablePto(k1PTO); EXPECT_CALL(*send_algorithm_, PacingRate(_)) .WillRepeatedly(Return(QuicBandwidth::Zero())); @@ -3179,9 +2715,8 @@ TEST_P(QuicSentPacketManagerTest, SendOneProbePacket) { manager_.MaybeSendProbePackets(); } -TEST_P(QuicSentPacketManagerTest, DisableHandshakeModeClient) { +TEST_F(QuicSentPacketManagerTest, DisableHandshakeModeClient) { QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); - manager_.SetSessionDecideWhatToWrite(true); manager_.EnableIetfPtoAndLossDetection(); // Send CHLO. SendCryptoPacket(1); @@ -3203,8 +2738,7 @@ TEST_P(QuicSentPacketManagerTest, DisableHandshakeModeClient) { manager_.OnRetransmissionTimeout()); } -TEST_P(QuicSentPacketManagerTest, DisableHandshakeModeServer) { - manager_.SetSessionDecideWhatToWrite(true); +TEST_F(QuicSentPacketManagerTest, DisableHandshakeModeServer) { manager_.EnableIetfPtoAndLossDetection(); // Send SHLO. SendCryptoPacket(1); @@ -3223,6 +2757,363 @@ TEST_P(QuicSentPacketManagerTest, DisableHandshakeModeServer) { EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); } +TEST_F(QuicSentPacketManagerTest, ForwardSecurePacketAcked) { + EXPECT_LT(manager_.handshake_state(), + QuicSentPacketManager::HANDSHAKE_CONFIRMED); + SendDataPacket(1, ENCRYPTION_INITIAL); + // Ack packet 1. + ExpectAck(1); + 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_INITIAL)); + EXPECT_LT(manager_.handshake_state(), + QuicSentPacketManager::HANDSHAKE_CONFIRMED); + + SendDataPacket(2, ENCRYPTION_ZERO_RTT); + // Ack packet 2. + ExpectAck(2); + manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2), + ENCRYPTION_FORWARD_SECURE)); + EXPECT_LT(manager_.handshake_state(), + QuicSentPacketManager::HANDSHAKE_CONFIRMED); + + SendDataPacket(3, ENCRYPTION_FORWARD_SECURE); + // Ack packet 3. + ExpectAck(3); + manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3), + ENCRYPTION_FORWARD_SECURE)); + EXPECT_EQ(manager_.handshake_state(), + QuicSentPacketManager::HANDSHAKE_CONFIRMED); +} + +TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { + EnablePto(k1PTO); + // Use PTOS and PTOA. + QuicConfig config; + QuicTagVector options; + options.push_back(kPTOS); + options.push_back(kPTOA); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + EXPECT_TRUE(manager_.skip_packet_number_for_pto()); + EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); + + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + RttStats* rtt_stats = const_cast(manager_.GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), QuicTime::Zero()); + QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); + + SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + // Verify PTO is correctly set and ack delay is included. + QuicTime::Delta expected_pto_delay = + srtt + 4 * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendDataPacket(2, ENCRYPTION_FORWARD_SECURE); + // Verify PTO is correctly set based on sent time of packet 2 but ack delay is + // not included as an immediate ACK is expected. + expected_pto_delay = expected_pto_delay - QuicTime::Delta::FromMilliseconds( + kDefaultDelayedAckTimeMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + EXPECT_EQ(0u, stats_.pto_count); + + // Invoke PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); + EXPECT_EQ(1u, stats_.pto_count); + + // Verify 1 probe packets get sent and packet number gets skipped. + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(4, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeSendProbePackets(); + // Verify PTO period gets set to twice the current value. Also, ack delay is + // not included. + QuicTime sent_time = clock_.Now(); + EXPECT_EQ(sent_time + expected_pto_delay * 2, + manager_.GetRetransmissionTime()); + + // Received ACK for packets 1 and 2. + uint64_t acked[] = {1, 2}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE)); + expected_pto_delay = + rtt_stats->SmoothedOrInitialRtt() + + std::max(4 * rtt_stats->mean_deviation(), + QuicTime::Delta::FromMilliseconds(1)) + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + + // Verify PTO is correctly re-armed based on sent time of packet 4. Because of + // PTOS turns out to be spurious, ACK delay is included. + EXPECT_EQ(sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); + + // Received ACK for packets 4. + ExpectAck(4); + manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(5)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4), + ENCRYPTION_FORWARD_SECURE)); + EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); + // Send more packets, such that peer will do ack decimation. + std::vector acked2; + for (size_t i = 5; i <= 100; ++i) { + SendDataPacket(i, ENCRYPTION_FORWARD_SECURE); + acked2.push_back(i); + } + // Received ACK for all sent packets. + ExpectAcksAndLosses(true, &acked2[0], acked2.size(), nullptr, 0); + manager_.OnAckFrameStart(QuicPacketNumber(100), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(101)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(100), + ENCRYPTION_FORWARD_SECURE)); + + expected_pto_delay = + rtt_stats->SmoothedOrInitialRtt() + + std::max(4 * rtt_stats->mean_deviation(), + QuicTime::Delta::FromMilliseconds(1)) + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + for (size_t i = 101; i < 110; i++) { + SendDataPacket(i, ENCRYPTION_FORWARD_SECURE); + // Verify PTO timeout includes ACK delay as there are less than 10 packets + // outstanding. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + } + expected_pto_delay = expected_pto_delay - QuicTime::Delta::FromMilliseconds( + kDefaultDelayedAckTimeMs); + SendDataPacket(110, ENCRYPTION_FORWARD_SECURE); + // Verify ACK delay is excluded. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); +} + +TEST_F(QuicSentPacketManagerTest, StartExponentialBackoffSince2ndPto) { + EnablePto(k2PTO); + QuicConfig config; + QuicTagVector options; + options.push_back(kPEB2); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + RttStats* rtt_stats = const_cast(manager_.GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), QuicTime::Zero()); + QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); + + SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + // Verify PTO is correctly set. + QuicTime::Delta expected_pto_delay = + srtt + 4 * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendDataPacket(2, ENCRYPTION_FORWARD_SECURE); + // Verify PTO is correctly set based on sent time of packet 2. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + EXPECT_EQ(0u, stats_.pto_count); + + // Invoke PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); + EXPECT_EQ(1u, stats_.pto_count); + + // Verify two probe packets get sent. + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(3, type, ENCRYPTION_FORWARD_SECURE); + }))) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(4, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeSendProbePackets(); + // Verify no exponential backoff. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Invoke 2nd PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); + EXPECT_EQ(2u, stats_.pto_count); + + // Verify two probe packets get sent. + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(5, type, ENCRYPTION_FORWARD_SECURE); + }))) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(6, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeSendProbePackets(); + // Verify still no exponential backoff. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Invoke 3rd PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); + EXPECT_EQ(3u, stats_.pto_count); + + // Verify two probe packets get sent. + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(7, type, ENCRYPTION_FORWARD_SECURE); + }))) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(8, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeSendProbePackets(); + // Verify exponential backoff starts. + EXPECT_EQ(clock_.Now() + expected_pto_delay * 2, + manager_.GetRetransmissionTime()); + + // Invoke 4th PTO. + clock_.AdvanceTime(expected_pto_delay * 2); + manager_.OnRetransmissionTimeout(); + EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); + EXPECT_EQ(4u, stats_.pto_count); + + // Verify two probe packets get sent. + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(2) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(9, type, ENCRYPTION_FORWARD_SECURE); + }))) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(10, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeSendProbePackets(); + // Verify exponential backoff continues. + EXPECT_EQ(clock_.Now() + expected_pto_delay * 4, + manager_.GetRetransmissionTime()); +} + +TEST_F(QuicSentPacketManagerTest, PtoTimeoutRttVarMultiple) { + EnablePto(k1PTO); + // Use 2 * rttvar + QuicConfig config; + QuicTagVector options; + options.push_back(kPVS1); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + RttStats* rtt_stats = const_cast(manager_.GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), QuicTime::Zero()); + QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); + + SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + // Verify PTO is correctly set based on 2 times rtt var. + QuicTime::Delta expected_pto_delay = + srtt + 2 * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); +} + +// Regression test for b/143962153 +TEST_F(QuicSentPacketManagerTest, RtoNotInFlightPacket) { + QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); + // Send SHLO. + QuicStreamFrame crypto_frame(1, false, 0, QuicStringPiece()); + SendCryptoPacket(1); + // Send data packet. + SendDataPacket(2, ENCRYPTION_FORWARD_SECURE); + + // Successfully decrypt a forward secure packet. + if (GetQuicReloadableFlag(quic_neuter_handshake_packets_once2)) { + EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)).Times(1); + } else { + EXPECT_CALL(notifier_, OnFrameAcked(_, _, _)).Times(0); + } + manager_.SetHandshakeConfirmed(); + + // 1st TLP. + manager_.OnRetransmissionTimeout(); + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(3, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeRetransmitTailLossProbe(); + + // 2nd TLP. + manager_.OnRetransmissionTimeout(); + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(4, type, ENCRYPTION_FORWARD_SECURE); + }))); + manager_.MaybeRetransmitTailLossProbe(); + + // RTO retransmits SHLO although it is not in flight. + size_t num_rto_packets = 2; + if (GetQuicReloadableFlag(quic_neuter_handshake_packets_once2)) { + num_rto_packets = 1; + } + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .Times(num_rto_packets) + .WillOnce(WithArgs<0>(Invoke([&crypto_frame](const QuicFrames& frames) { + EXPECT_EQ(1u, frames.size()); + if (GetQuicReloadableFlag(quic_neuter_handshake_packets_once2)) { + EXPECT_NE(crypto_frame, frames[0].stream_frame); + } else { + EXPECT_EQ(crypto_frame, frames[0].stream_frame); + } + }))); + manager_.OnRetransmissionTimeout(); +} + } // 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 b6e4b83dd0b..ada8bf41d9d 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 @@ -9,6 +9,7 @@ #include #include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_flow_controller.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" @@ -87,7 +88,6 @@ QuicSession::QuicSession( perspective() == Perspective::IS_SERVER, nullptr), currently_writing_stream_id_(0), - is_handshake_confirmed_(false), goaway_sent_(false), goaway_received_(false), control_frame_manager_(this), @@ -114,6 +114,13 @@ void QuicSession::Initialize() { connection_->SetDataProducer(this); connection_->SetFromConfig(config_); + // On the server side, version negotiation has been done by the dispatcher, + // and the server session is created with the right version. + if (connection_->quic_version_negotiated_by_default_at_server() && + perspective() == Perspective::IS_SERVER) { + connection_->OnSuccessfulVersionNegotiation(); + } + if (QuicVersionUsesCryptoFrames(transport_version())) { return; } @@ -200,11 +207,8 @@ void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) { GetMutableCryptoStream()->OnCryptoFrame(frame); } -bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { - // We are not version 99. In theory, if not in version 99 then the framer - // could not call OnStopSending... This is just a check that is good when - // both a new protocol and a new implementation of that protocol are both - // being developed. +void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { + // STOP_SENDING is in IETF QUIC only. DCHECK(VersionHasIetfQuicFrames(transport_version())); QuicStreamId stream_id = frame.stream_id; @@ -216,21 +220,7 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { connection()->CloseConnection( QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; - } - - // Ignore STOP_SENDING for static streams. - // TODO(fkastenholz): IETF Quic does not have static streams and does not - // make exceptions for them with respect to processing things like - // STOP_SENDING. - if (QuicUtils::IsCryptoStreamId(transport_version(), stream_id)) { - QUIC_DVLOG(1) << ENDPOINT - << "Received STOP_SENDING for a static stream, id: " - << stream_id << " Closing connection"; - connection()->CloseConnection( - QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; + return; } if (visitor_) { @@ -243,7 +233,7 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { << ENDPOINT << "Received STOP_SENDING for closed or non-existent stream, id: " << stream_id << " Ignoring."; - return true; // Continue processing the packet. + return; } // If stream is non-existent, close the connection StreamMap::iterator it = stream_map_.find(stream_id); @@ -255,20 +245,15 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { IETF_QUIC_PROTOCOL_VIOLATION, "Received STOP_SENDING for a non-existent stream", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; + return; } - // Get the QuicStream for this stream. Ignore the STOP_SENDING - // if the QuicStream pointer is NULL - // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would - // happen IFF there was an entry in the map, but the pointer is null. sounds - // more like a deep programming error rather than a simple protocol problem). QuicStream* stream = it->second.get(); if (stream == nullptr) { QUIC_BUG << ENDPOINT << "Received STOP_SENDING for NULL QuicStream, stream_id: " << stream_id << ". Ignoring."; - return true; + return; } if (stream->is_static()) { @@ -278,20 +263,28 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { connection()->CloseConnection( QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; + return; } stream->OnStopSending(frame.application_error_code); stream->set_stream_error( static_cast(frame.application_error_code)); - SendRstStreamInner( - stream->id(), - static_cast(frame.application_error_code), - stream->stream_bytes_written(), - /*close_write_side_only=*/true); + if (connection()->connected()) { + MaybeSendRstStreamFrame( + stream->id(), + static_cast(frame.application_error_code), + stream->stream_bytes_written()); + connection_->OnStreamReset(stream->id(), + static_cast( + frame.application_error_code)); + } + stream->set_rst_sent(true); + stream->CloseWriteSide(); +} - return true; +void QuicSession::OnPacketDecrypted(EncryptionLevel level) { + GetMutableCryptoStream()->OnPacketDecrypted(level); } void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) { @@ -306,7 +299,10 @@ void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) { } pending->OnRstStreamFrame(frame); - SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0); + // Pending stream is currently read only. We can safely close the stream. + DCHECK_EQ(READ_UNIDIRECTIONAL, + QuicUtils::GetStreamType(pending->id(), perspective(), + /*peer_initiated = */ true)); ClosePendingStream(stream_id); } @@ -319,6 +315,16 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { return; } + if (VersionHasIetfQuicFrames(transport_version()) && + QuicUtils::GetStreamType(stream_id, perspective(), + IsIncomingStream(stream_id)) == + WRITE_UNIDIRECTIONAL) { + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Received RESET_STREAM for a write-only stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + if (visitor_) { visitor_->OnRstStreamReceived(frame); } @@ -458,9 +464,9 @@ void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { // individual stream. QUIC_DVLOG(1) << ENDPOINT << "Received connection level flow control window " - "update with byte offset: " - << frame.byte_offset; - flow_controller_.UpdateSendWindowOffset(frame.byte_offset); + "update with max data: " + << frame.max_data; + flow_controller_.UpdateSendWindowOffset(frame.max_data); return; } @@ -541,9 +547,7 @@ void QuicSession::OnCanWrite() { "write blocked."; return; } - if (session_decides_what_to_write()) { - SetTransmissionType(NOT_RETRANSMISSION); - } + SetTransmissionType(NOT_RETRANSMISSION); // We limit the number of writes to the number of pending streams. If more // streams become pending, WillingAndAbleToWrite will be true, which will // cause the connection to request resumption before yielding to other @@ -700,7 +704,24 @@ bool QuicSession::WriteControlFrame(const QuicFrame& frame) { void QuicSession::SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written) { - SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false); + if (!GetQuicReloadableFlag(quic_delete_send_rst_stream_inner)) { + SendRstStreamInner(id, error, bytes_written, false); + return; + } + QUIC_RELOADABLE_FLAG_COUNT(quic_delete_send_rst_stream_inner); + if (connection()->connected()) { + QuicConnection::ScopedPacketFlusher flusher(connection()); + MaybeSendRstStreamFrame(id, error, bytes_written); + MaybeSendStopSendingFrame(id, error); + + connection_->OnStreamReset(id, error); + } + + if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) { + OnStreamDoneWaitingForAcks(id); + return; + } + CloseStreamInner(id, true); } void QuicSession::SendRstStreamInner(QuicStreamId id, @@ -709,21 +730,23 @@ void QuicSession::SendRstStreamInner(QuicStreamId id, bool close_write_side_only) { if (connection()->connected()) { // Only send if still connected. - if (close_write_side_only) { - DCHECK(VersionHasIetfQuicFrames(transport_version())); - // Send a RST_STREAM frame. - control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); - } else { + if (VersionHasIetfQuicFrames(transport_version())) { // Send a RST_STREAM frame plus, if version 99, an IETF // QUIC STOP_SENDING frame. Both sre sent to emulate // the two-way close that Google QUIC's RST_STREAM does. - if (VersionHasIetfQuicFrames(transport_version())) { - QuicConnection::ScopedPacketFlusher flusher(connection()); + QuicConnection::ScopedPacketFlusher flusher(connection()); + if (QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) != + READ_UNIDIRECTIONAL) { control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); + } + if (!close_write_side_only && + QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) != + WRITE_UNIDIRECTIONAL) { control_frame_manager_.WriteOrBufferStopSending(error, id); - } else { - control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); } + } else { + DCHECK(!close_write_side_only); + control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); } connection_->OnStreamReset(id, error); } @@ -734,26 +757,27 @@ void QuicSession::SendRstStreamInner(QuicStreamId id, if (!close_write_side_only) { CloseStreamInner(id, true); - return; } - DCHECK(VersionHasIetfQuicFrames(transport_version())); +} - StreamMap::iterator it = stream_map_.find(id); - if (it != stream_map_.end()) { - if (it->second->is_static()) { - QUIC_DVLOG(1) << ENDPOINT - << "Try to send rst for a static stream, id: " << id - << " Closing connection"; - connection()->CloseConnection( - QUIC_INVALID_STREAM_ID, "Sending rst for a static stream", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; - } - QuicStream* stream = it->second.get(); - if (stream) { - stream->set_rst_sent(true); - stream->CloseWriteSide(); - } +void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written) { + DCHECK(connection()->connected()); + if (!VersionHasIetfQuicFrames(transport_version()) || + QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) != + READ_UNIDIRECTIONAL) { + control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); + } +} + +void QuicSession::MaybeSendStopSendingFrame(QuicStreamId id, + QuicRstStreamErrorCode error) { + DCHECK(connection()->connected()); + if (VersionHasIetfQuicFrames(transport_version()) && + QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) != + WRITE_UNIDIRECTIONAL) { + control_frame_manager_.WriteOrBufferStopSending(error, id); } } @@ -840,9 +864,7 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) { zombie_streams_[stream->id()] = std::move(it->second); } else { // Clean up the stream since it is no longer waiting for acks. - if (session_decides_what_to_write()) { - streams_waiting_for_acks_.erase(stream->id()); - } + streams_waiting_for_acks_.erase(stream->id()); closed_streams_.push_back(std::move(it->second)); // Do not retransmit data of a closed stream. streams_with_pending_retransmission_.erase(stream_id); @@ -855,7 +877,7 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) { // If we haven't received a FIN or RST for this stream, we need to keep track // of the how many bytes the stream's flow controller believes it has // received, for accurate connection level flow control accounting. - const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset(); + const bool had_fin_or_rst = stream->HasReceivedFinalOffset(); if (!had_fin_or_rst) { InsertLocallyClosedStreamsHighestOffset( stream_id, stream->flow_controller()->highest_received_byte_offset()); @@ -935,14 +957,16 @@ void QuicSession::OnFinalByteOffsetReceived( } bool QuicSession::IsEncryptionEstablished() const { - // Once the handshake is confirmed, it never becomes un-confirmed. - if (is_handshake_confirmed_) { - return true; + if (GetCryptoStream() == nullptr) { + return false; } return GetCryptoStream()->encryption_established(); } bool QuicSession::IsCryptoHandshakeConfirmed() const { + if (GetCryptoStream() == nullptr) { + return false; + } return GetCryptoStream()->handshake_confirmed(); } @@ -1249,6 +1273,7 @@ void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) { } void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { + DCHECK(!use_handshake_delegate()); switch (event) { case ENCRYPTION_ESTABLISHED: // Retransmit originally packets that were sent, since they can't be @@ -1264,7 +1289,6 @@ void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { // Discard originally encrypted packets, since they can't be decrypted by // the peer. NeuterUnencryptedData(); - is_handshake_confirmed_ = true; break; default: @@ -1272,6 +1296,93 @@ void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { } } +void QuicSession::OnNewKeysAvailable(EncryptionLevel level, + std::unique_ptr decrypter, + bool set_alternative_decrypter, + bool latch_once_used, + std::unique_ptr encrypter) { + DCHECK(use_handshake_delegate()); + // Install new keys. + connection()->SetEncrypter(level, std::move(encrypter)); + if (connection()->version().KnowsWhichDecrypterToUse()) { + connection()->InstallDecrypter(level, std::move(decrypter)); + return; + } + if (set_alternative_decrypter) { + connection()->SetAlternativeDecrypter(level, std::move(decrypter), + latch_once_used); + return; + } + connection()->SetDecrypter(level, std::move(decrypter)); +} + +void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { + DCHECK(use_handshake_delegate()); + QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " + << EncryptionLevelToString(level); + connection()->SetDefaultEncryptionLevel(level); + + switch (level) { + case ENCRYPTION_INITIAL: + break; + case ENCRYPTION_ZERO_RTT: + // Retransmit old 0-RTT data (if any) with the new 0-RTT keys, since they + // can't be decrypted by the peer. + connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION); + // Given any streams blocked by encryption a chance to write. + OnCanWrite(); + break; + case ENCRYPTION_HANDSHAKE: + break; + case ENCRYPTION_FORWARD_SECURE: + QUIC_BUG_IF(!config_.negotiated()) + << ENDPOINT << "Handshake confirmed without parameter negotiation."; + break; + default: + QUIC_BUG << "Unknown encryption level: " + << EncryptionLevelToString(level); + } +} + +void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) { + DCHECK(use_handshake_delegate()); + if (!connection()->version().KnowsWhichDecrypterToUse()) { + // TODO(fayang): actually discard keys. + return; + } + connection()->RemoveDecrypter(level); +} + +void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) { + DCHECK(use_handshake_delegate()); + QUIC_DVLOG(1) << ENDPOINT << "Discard keys of " + << EncryptionLevelToString(level); + // TODO(fayang): actually discard keys. + switch (level) { + case ENCRYPTION_INITIAL: + NeuterUnencryptedData(); + break; + case ENCRYPTION_HANDSHAKE: + DCHECK(false); + // TODO(fayang): implement this when handshake keys discarding settles + // down. + break; + case ENCRYPTION_ZERO_RTT: + break; + case ENCRYPTION_FORWARD_SECURE: + QUIC_BUG << "Tries to drop 1-RTT keys"; + break; + default: + QUIC_BUG << "Unknown encryption level: " + << EncryptionLevelToString(level); + } +} + +void QuicSession::NeuterHandshakeData() { + DCHECK(use_handshake_delegate()); + connection()->OnHandshakeComplete(); +} + void QuicSession::OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& /*message*/) {} @@ -1476,6 +1587,13 @@ void QuicSession::set_largest_peer_created_stream_id( largest_peer_created_stream_id); } +QuicStreamId QuicSession::GetLargestPeerCreatedStreamId( + bool unidirectional) const { + // This method is only used in IETF QUIC. + DCHECK(VersionHasIetfQuicFrames(transport_version())); + return v99_streamid_manager_.GetLargestPeerCreatedStreamId(unidirectional); +} + bool QuicSession::IsClosedStream(QuicStreamId id) { DCHECK_NE(QuicUtils::GetInvalidStreamId(transport_version()), id); if (IsOpenStream(id)) { @@ -1621,9 +1739,7 @@ bool QuicSession::IsIncomingStream(QuicStreamId id) const { } void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) { - if (session_decides_what_to_write()) { - streams_waiting_for_acks_.erase(id); - } + streams_waiting_for_acks_.erase(id); auto it = zombie_streams_.find(id); if (it == zombie_streams_.end()) { @@ -1640,10 +1756,6 @@ void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) { } void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) { - if (!session_decides_what_to_write()) { - return; - } - // Exclude crypto stream's status since it is counted in HasUnackedCryptoData. if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) { return; @@ -1903,14 +2015,12 @@ bool QuicSession::RetransmitLostData() { } void QuicSession::NeuterUnencryptedData() { - if (connection_->session_decides_what_to_write()) { - QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); - crypto_stream->NeuterUnencryptedStreamData(); - if (!crypto_stream->HasPendingRetransmission() && - !QuicVersionUsesCryptoFrames(transport_version())) { - streams_with_pending_retransmission_.erase( - QuicUtils::GetCryptoStreamId(transport_version())); - } + QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); + crypto_stream->NeuterUnencryptedStreamData(); + if (!crypto_stream->HasPendingRetransmission() && + !QuicVersionUsesCryptoFrames(transport_version())) { + streams_with_pending_retransmission_.erase( + QuicUtils::GetCryptoStreamId(transport_version())); } connection_->NeuterUnencryptedPackets(); } @@ -1920,11 +2030,15 @@ void QuicSession::SetTransmissionType(TransmissionType type) { } MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) { + return SendMessage(message, /*flush=*/false); +} + +MessageResult QuicSession::SendMessage(QuicMemSliceSpan message, bool flush) { if (!IsEncryptionEstablished()) { return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0}; } MessageStatus result = - connection_->SendMessage(last_message_id_ + 1, message); + connection_->SendMessage(last_message_id_ + 1, message, flush); if (result == MESSAGE_STATUS_SUCCESS) { return {result, ++last_message_id_}; } @@ -1945,10 +2059,6 @@ void QuicSession::CleanUpClosedStreams() { closed_streams_.clear(); } -bool QuicSession::session_decides_what_to_write() const { - return connection_->session_decides_what_to_write(); -} - QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const { return connection_->GetCurrentLargestMessagePayload(); } 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 9a2f3aaeffc..c6861f93ca5 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 @@ -14,6 +14,7 @@ #include #include +#include "net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h" #include "net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h" #include "net/third_party/quiche/src/quic/core/quic_connection.h" #include "net/third_party/quiche/src/quic/core/quic_control_frame_manager.h" @@ -23,6 +24,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_stream.h" #include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h" #include "net/third_party/quiche/src/quic/core/session_notifier_interface.h" #include "net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h" @@ -45,12 +47,13 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, public SessionNotifierInterface, public QuicStreamFrameDataProducer, - public QuicStreamIdManager::DelegateInterface { + public QuicStreamIdManager::DelegateInterface, + public HandshakerDelegateInterface { public: // An interface from the session to the entity owning the session. // This lets the session notify its owner (the Dispatcher) when the connection // is closed, blocked, or added/removed from the time-wait list. - class Visitor { + class QUIC_EXPORT_PRIVATE Visitor { public: virtual ~Visitor() {} @@ -72,6 +75,7 @@ class QUIC_EXPORT_PRIVATE QuicSession }; // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream. + // TODO(fayang): Replace this enum and with HandshakeState. enum CryptoHandshakeEvent { // ENCRYPTION_ESTABLISHED indicates that a client hello has been sent and // subsequent packets will be encrypted. (Client only.) @@ -125,7 +129,8 @@ class QUIC_EXPORT_PRIVATE QuicSession void OnForwardProgressConfirmed() override; bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; - bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override; + void OnStopSendingFrame(const QuicStopSendingFrame& frame) override; + void OnPacketDecrypted(EncryptionLevel level) override; // QuicStreamFrameDataProducer WriteStreamDataResult WriteStreamData(QuicStreamId id, @@ -197,6 +202,10 @@ class QUIC_EXPORT_PRIVATE QuicSession // callback. MessageResult SendMessage(QuicMemSliceSpan message); + // Same as above SendMessage, except caller can specify if the given |message| + // should be flushed even if the underlying connection is deemed unwritable. + MessageResult SendMessage(QuicMemSliceSpan message, bool flush); + // Called when message with |message_id| gets acked. virtual void OnMessageAcked(QuicMessageId message_id, QuicTime receive_timestamp); @@ -208,7 +217,9 @@ class QUIC_EXPORT_PRIVATE QuicSession // the peer. Returns true if |frame| is consumed, false otherwise. virtual bool WriteControlFrame(const QuicFrame& frame); - // Called by streams when they want to close the stream in both directions. + // Close the stream in both directions. + // TODO(renjietang): rename this method as it sends both RST_STREAM and + // STOP_SENDING in IETF QUIC. virtual void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written); @@ -248,6 +259,18 @@ class QUIC_EXPORT_PRIVATE QuicSession // Servers will simply call it once with HANDSHAKE_CONFIRMED. virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event); + // From HandshakerDelegateInterface + void OnNewKeysAvailable(EncryptionLevel level, + std::unique_ptr decrypter, + bool set_alternative_decrypter, + bool latch_once_used, + std::unique_ptr encrypter) override; + void SetDefaultEncryptionLevel(EncryptionLevel level) override; + void DiscardOldDecryptionKey(EncryptionLevel level) override; + void DiscardOldEncryptionKey(EncryptionLevel level) override; + void NeuterUnencryptedData() override; + void NeuterHandshakeData() override; + // Called by the QuicCryptoStream when a handshake message is sent. virtual void OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& message); @@ -330,9 +353,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // Called when stream |id| is newly waiting for acks. void OnStreamWaitingForAcks(QuicStreamId id); - // Called to cancel retransmission of unencypted crypto stream data. - void NeuterUnencryptedData(); - // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. bool HasDataToWrite() const; @@ -404,8 +424,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // Clean up closed_streams_. void CleanUpClosedStreams(); - bool session_decides_what_to_write() const; - const ParsedQuicVersionVector& supported_versions() const { return supported_versions_; } @@ -447,6 +465,10 @@ class QUIC_EXPORT_PRIVATE QuicSession return use_http2_priority_write_scheduler_; } + bool use_handshake_delegate() const { + return connection_->use_handshake_delegate(); + } + bool is_configured() const { return is_configured_; } QuicStreamCount num_expected_unidirectional_static_streams() const { @@ -539,6 +561,10 @@ class QUIC_EXPORT_PRIVATE QuicSession StreamMap& stream_map() { return stream_map_; } const StreamMap& stream_map() const { return stream_map_; } + const PendingStreamMap& pending_streams() const { + return pending_stream_map_; + } + ClosedStreams* closed_streams() { return &closed_streams_; } const ZombieStreamMap& zombie_streams() const { return zombie_streams_; } @@ -596,7 +622,9 @@ class QUIC_EXPORT_PRIVATE QuicSession return false; } - bool IsHandshakeConfirmed() const { return is_handshake_confirmed_; } + // Return the largest peer created stream id depending on directionality + // indicated by |unidirectional|. + QuicStreamId GetLargestPeerCreatedStreamId(bool unidirectional) const; private: friend class test::QuicSessionPeer; @@ -659,6 +687,14 @@ class QUIC_EXPORT_PRIVATE QuicSession // stream. void PendingStreamOnRstStream(const QuicRstStreamFrame& frame); + // Does actual work of sending RESET_STREAM, if the stream type allows. + void MaybeSendRstStreamFrame(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written); + + // Sends a STOP_SENDING frame if the stream type allows. + void MaybeSendStopSendingFrame(QuicStreamId id, QuicRstStreamErrorCode error); + // Keep track of highest received byte offset of locally closed streams, while // waiting for a definitive final highest offset from the peer. std::map @@ -732,9 +768,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // call stack of OnCanWrite. QuicStreamId currently_writing_stream_id_; - // Cached value of whether the crypto handshake has been confirmed. - bool is_handshake_confirmed_; - // Whether a GoAway has been sent. bool goaway_sent_; 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 9eb4fed3de9..afb5641d8f9 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 @@ -85,11 +85,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); } - EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_THAT(error, IsQuicNoError()); session()->OnConfigNegotiated(); - session()->connection()->SetDefaultEncryptionLevel( - ENCRYPTION_FORWARD_SECURE); - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + if (session()->use_handshake_delegate()) { + session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + } else { + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + } } // QuicCryptoStream implementation @@ -104,6 +109,7 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { CryptoMessageParser* crypto_message_parser() override { return QuicCryptoHandshaker::crypto_message_parser(); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} MOCK_METHOD0(OnCanWrite, void()); bool HasPendingCryptoRetransmission() const override { return false; } @@ -135,7 +141,6 @@ class TestStream : public QuicStream { using QuicStream::CloseReadSide; using QuicStream::CloseWriteSide; using QuicStream::WriteMemSlices; - using QuicStream::WritevData; void OnDataAvailable() override {} @@ -144,7 +149,6 @@ class TestStream : public QuicStream { bool(QuicStreamOffset, QuicByteCount, bool)); MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); - MOCK_METHOD1(OnStopSending, void(uint16_t code)); }; class TestSession : public QuicSession { @@ -391,24 +395,33 @@ class QuicSessionTestBase : public QuicTestWithParam { } void CloseStream(QuicStreamId id) { - if (VersionHasIetfQuicFrames(session_.transport_version()) && - QuicUtils::GetStreamType(id, session_.perspective(), - session_.IsIncomingStream(id)) == - READ_UNIDIRECTIONAL) { - // Verify reset is not sent for READ_UNIDIRECTIONAL streams. - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); - EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(0); - } else { - // Verify reset IS sent for BIDIRECTIONAL streams. - if (VersionHasIetfQuicFrames(session_.transport_version())) { - // Once for the RST_STREAM, Once for the STOP_SENDING + if (VersionHasIetfQuicFrames(transport_version())) { + if (QuicUtils::GetStreamType(id, session_.perspective(), + session_.IsIncomingStream(id)) == + READ_UNIDIRECTIONAL) { + // Verify reset is not sent for READ_UNIDIRECTIONAL streams. + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); + EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(0); + } else if (QuicUtils::GetStreamType(id, session_.perspective(), + session_.IsIncomingStream(id)) == + WRITE_UNIDIRECTIONAL) { + // Verify RESET_STREAM but not STOP_SENDING is sent for write-only + // stream. EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly(Invoke(&ClearControlFrame)); + .Times(1) + .WillOnce(Invoke(&ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(id, _)); } else { + // Verify RESET_STREAM and STOP_SENDING are sent for BIDIRECTIONAL + // streams. EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&ClearControlFrame)); + .Times(2) + .WillRepeatedly(Invoke(&ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(id, _)); } + } else { + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(id, _)); } session_.CloseStream(id); @@ -1309,7 +1322,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { TEST_P(QuicSessionTestServer, SendGoAway) { if (VersionHasIetfQuicFrames(transport_version())) { - // GoAway frames are not in version 99 + // In IETF QUIC, GOAWAY lives up in the HTTP layer. return; } connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); @@ -1334,8 +1347,7 @@ TEST_P(QuicSessionTestServer, SendGoAway) { TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) { if (VersionHasIetfQuicFrames(transport_version())) { - // TODO(b/118808809): Enable this test for version 99 when GOAWAY is - // supported. + // In IETF QUIC, GOAWAY lives up in the HTTP layer. return; } EXPECT_CALL(*connection_, SendControlFrame(_)) @@ -1347,8 +1359,7 @@ TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) { TEST_P(QuicSessionTestServer, InvalidGoAway) { if (VersionHasIetfQuicFrames(transport_version())) { - // TODO(b/118808809): Enable this test for version 99 when GOAWAY is - // supported. + // In IETF QUIC, GOAWAY lives up in the HTTP layer. return; } QuicGoAwayFrame go_away(kInvalidControlFrameId, QUIC_PEER_GOING_AWAY, @@ -1558,7 +1569,7 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { config.ToHandshakeMessage(&crypto_message, transport_version()); crypto_stream->SendHandshakeMessage(crypto_message); char buf[1000]; - QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); + QuicDataWriter writer(1000, buf, quiche::NETWORK_BYTE_ORDER); crypto_stream->WriteStreamData(offset, crypto_message.size(), &writer); } EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked()); @@ -1605,7 +1616,8 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) { // stream and therefore fulfill all of the expects. QuicStopSendingFrame frame(kInvalidControlFrameId, stream->id(), QUIC_STREAM_CANCELLED); - EXPECT_TRUE(session_.OnStopSendingFrame(frame)); + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + session_.OnStopSendingFrame(frame); } EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); } @@ -1886,9 +1898,6 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) { EXPECT_EQ(0, session_.num_incoming_streams_created()); EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); - EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_RST_ACKNOWLEDGEMENT)) - .Times(1); QuicRstStreamFrame rst1(kInvalidControlFrameId, stream_id, QUIC_ERROR_PROCESSING_STREAM, 12); session_.OnRstStream(rst1); @@ -2119,7 +2128,8 @@ TEST_P(QuicSessionTestServer, TestZombieStreams) { // stream and therefore fulfill all of the expects. QuicStopSendingFrame frame(kInvalidControlFrameId, stream2->id(), QUIC_STREAM_CANCELLED); - EXPECT_TRUE(session_.OnStopSendingFrame(frame)); + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + session_.OnStopSendingFrame(frame); } EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); ASSERT_EQ(1u, session_.closed_streams()->size()); @@ -2148,7 +2158,6 @@ TEST_P(QuicSessionTestServer, TestZombieStreams) { } TEST_P(QuicSessionTestServer, OnStreamFrameLost) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); InSequence s; // Drive congestion control manually. @@ -2225,7 +2234,6 @@ TEST_P(QuicSessionTestServer, OnStreamFrameLost) { } TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); InSequence s; TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); @@ -2265,7 +2273,6 @@ TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { } TEST_P(QuicSessionTestServer, RetransmitFrames) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); MockSendAlgorithm* send_algorithm = new StrictMock; QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); InSequence s; @@ -2301,7 +2308,6 @@ TEST_P(QuicSessionTestServer, RetransmitFrames) { TEST_P(QuicSessionTestServer, RetransmitLostDataCausesConnectionClose) { // This test mimics the scenario when a dynamic stream retransmits lost data // and causes connection close. - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); TestStream* stream = session_.CreateOutgoingBidirectionalStream(); QuicStreamFrame frame(stream->id(), false, 0, 9); @@ -2343,21 +2349,21 @@ TEST_P(QuicSessionTestServer, SendMessage) { EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); QuicStringPiece message; - EXPECT_CALL(*connection_, SendMessage(1, _)) + EXPECT_CALL(*connection_, SendMessage(1, _, false)) .WillOnce(Return(MESSAGE_STATUS_SUCCESS)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1), session_.SendMessage( MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), message, &storage))); // Verify message_id increases. - EXPECT_CALL(*connection_, SendMessage(2, _)) + EXPECT_CALL(*connection_, SendMessage(2, _, false)) .WillOnce(Return(MESSAGE_STATUS_TOO_LARGE)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_TOO_LARGE, 0), session_.SendMessage( MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), message, &storage))); // Verify unsent message does not consume a message_id. - EXPECT_CALL(*connection_, SendMessage(2, _)) + EXPECT_CALL(*connection_, SendMessage(2, _, false)) .WillOnce(Return(MESSAGE_STATUS_SUCCESS)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 2), session_.SendMessage( @@ -2380,8 +2386,6 @@ TEST_P(QuicSessionTestServer, SendMessage) { // Regression test of b/115323618. TEST_P(QuicSessionTestServer, LocallyResetZombieStreams) { - QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); - session_.set_writev_consumes_all_data(true); TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); std::string body(100, '.'); @@ -2632,7 +2636,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputInvalidStreamId) { *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream", _)); - EXPECT_FALSE(session_.OnStopSendingFrame(frame)); + session_.OnStopSendingFrame(frame); } // Second test, streams in the static stream map are not subject to @@ -2652,7 +2656,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputStaticStreams) { EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", _)); - EXPECT_FALSE(session_.OnStopSendingFrame(frame)); + session_.OnStopSendingFrame(frame); } // Third test, if stream id specifies a closed stream: @@ -2672,7 +2676,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputClosedStream) { stream->CloseReadSide(); QuicStopSendingFrame frame(1, stream_id, 123); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); - EXPECT_TRUE(session_.OnStopSendingFrame(frame)); + session_.OnStopSendingFrame(frame); } // Fourth test, if stream id specifies a nonexistent stream, return false and @@ -2690,7 +2694,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputNonExistentStream) { CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, "Received STOP_SENDING for a non-existent stream", _)) .Times(1); - EXPECT_FALSE(session_.OnStopSendingFrame(frame)); + session_.OnStopSendingFrame(frame); } // For a valid stream, ensure that all works @@ -2708,15 +2712,14 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputValidStream) { QuicStreamId stream_id = stream->id(); QuicStopSendingFrame frame(1, stream_id, 123); - EXPECT_CALL(*stream, OnStopSending(123)); // Expect a reset to come back out. EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL( *connection_, OnStreamReset(stream_id, static_cast(123))); - EXPECT_TRUE(session_.OnStopSendingFrame(frame)); - // When the STOP_SENDING is received, the node generates a RST_STREAM, - // which closes the stream in the write direction. Ensure this. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + session_.OnStopSendingFrame(frame); + EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream)); EXPECT_TRUE(stream->write_side_closed()); } @@ -2754,17 +2757,43 @@ TEST_P(QuicSessionTestServer, StreamFrameReceivedAfterFin) { session_.OnStreamFrame(frame); QuicStreamFrame frame1(stream->id(), false, 1, ","); - if (GetQuicReloadableFlag(quic_rst_if_stream_frame_beyond_close_offset)) { + if (!GetQuicReloadableFlag(quic_close_connection_on_wrong_offset)) { EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(stream->id(), QUIC_DATA_AFTER_CLOSE_OFFSET)); - session_.OnStreamFrame(frame1); - EXPECT_TRUE(connection_->connected()); } else { -#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - EXPECT_DEBUG_DEATH(session_.OnStreamFrame(frame1), "Check failed"); -#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) + EXPECT_CALL(*connection_, + CloseConnection(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET, _, _)); + } + session_.OnStreamFrame(frame1); +} + +TEST_P(QuicSessionTestServer, ResetForIETFStreamTypes) { + if (!VersionHasIetfQuicFrames(transport_version())) { + return; } + + QuicStreamId read_only = GetNthClientInitiatedUnidirectionalId(0); + + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(1) + .WillOnce(Invoke(&ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(read_only, _)); + session_.SendRstStream(read_only, QUIC_STREAM_CANCELLED, 0); + + QuicStreamId write_only = GetNthServerInitiatedUnidirectionalId(0); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(1) + .WillOnce(Invoke(&ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(write_only, _)); + session_.SendRstStream(write_only, QUIC_STREAM_CANCELLED, 0); + + QuicStreamId bidirectional = GetNthClientInitiatedBidirectionalId(0); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(&ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(bidirectional, _)); + session_.SendRstStream(bidirectional, QUIC_STREAM_CANCELLED, 0); } // A client test class that can be used when the automatic configuration is not 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 d708b13cfcf..20373272d4f 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 @@ -9,6 +9,7 @@ #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_flow_controller.h" #include "net/third_party/quiche/src/quic/core/quic_session.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" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" @@ -21,7 +22,7 @@ using spdy::SpdyPriority; namespace quic { #define ENDPOINT \ - (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") + (session_->perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ") namespace { @@ -135,9 +136,13 @@ void PendingStream::AddBytesConsumed(QuicByteCount bytes) { connection_flow_controller_->AddBytesConsumed(bytes); } -void PendingStream::Reset(QuicRstStreamErrorCode error) { - // TODO: RESET_STREAM must not be sent for READ_UNIDIRECTIONAL stream. - session_->SendRstStream(id_, error, 0); +void PendingStream::Reset(QuicRstStreamErrorCode /*error*/) { + // Currently PendingStream is only read-unidirectional. It shouldn't send + // Reset. + DCHECK_EQ(READ_UNIDIRECTIONAL, + QuicUtils::GetStreamType(id_, session_->perspective(), + /*peer_initiated = */ true)); + QUIC_NOTREACHED(); } void PendingStream::CloseConnectionWithDetails(QuicErrorCode error, @@ -171,9 +176,13 @@ void PendingStream::OnStreamFrame(const QuicStreamFrame& frame) { return; } - if (GetQuicReloadableFlag(quic_rst_if_stream_frame_beyond_close_offset) && - frame.offset + frame.data_length > sequencer_.close_offset()) { - Reset(QUIC_DATA_AFTER_CLOSE_OFFSET); + if (frame.offset + frame.data_length > sequencer_.close_offset()) { + CloseConnectionWithDetails( + QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET, + QuicStrCat( + "Stream ", id_, + " received data with offset: ", frame.offset + frame.data_length, + ", which is beyond close offset: ", sequencer()->close_offset())); return; } @@ -212,6 +221,20 @@ void PendingStream::OnRstStreamFrame(const QuicRstStreamFrame& frame) { "Reset frame stream offset overflow."); return; } + + const QuicStreamOffset kMaxOffset = + std::numeric_limits::max(); + if (sequencer()->close_offset() != kMaxOffset && + frame.byte_offset != sequencer()->close_offset()) { + CloseConnectionWithDetails( + QUIC_STREAM_MULTIPLE_OFFSET, + QuicStrCat("Stream ", id_, + " received new final offset: ", frame.byte_offset, + ", which is different from close offset: ", + sequencer()->close_offset())); + return; + } + MaybeIncreaseHighestReceivedOffset(frame.byte_offset); if (flow_controller_.FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { @@ -328,7 +351,6 @@ QuicStream::QuicStream(QuicStreamId id, fin_received_(fin_received), rst_sent_(false), rst_received_(false), - perspective_(session_->perspective()), flow_controller_(std::move(flow_controller)), connection_flow_controller_(connection_flow_controller), stream_contributes_to_connection_flow_control_(true), @@ -342,7 +364,7 @@ QuicStream::QuicStream(QuicStreamId id, type_(VersionHasIetfQuicFrames(session->transport_version()) && type != CRYPTO ? QuicUtils::GetStreamType(id_, - perspective_, + session->perspective(), session->IsIncomingStream(id_)) : type) { if (type_ == WRITE_UNIDIRECTIONAL) { @@ -352,7 +374,6 @@ QuicStream::QuicStream(QuicStreamId id, set_fin_sent(true); CloseWriteSide(); } - SetFromConfig(); if (type_ != CRYPTO) { session_->RegisterStreamPriority(id, is_static_, precedence_); } @@ -371,8 +392,6 @@ QuicStream::~QuicStream() { } } -void QuicStream::SetFromConfig() {} - void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { DCHECK_EQ(frame.stream_id, id_); @@ -402,12 +421,19 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { return; } - if (GetQuicReloadableFlag(quic_rst_if_stream_frame_beyond_close_offset)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_rst_if_stream_frame_beyond_close_offset); - if (frame.offset + frame.data_length > sequencer_.close_offset()) { + if (frame.offset + frame.data_length > sequencer_.close_offset()) { + if (!GetQuicReloadableFlag(quic_close_connection_on_wrong_offset)) { Reset(QUIC_DATA_AFTER_CLOSE_OFFSET); return; } + QUIC_RELOADABLE_FLAG_COUNT_N(quic_close_connection_on_wrong_offset, 1, 2); + CloseConnectionWithDetails( + QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET, + QuicStrCat( + "Stream ", id_, + " received data with offset: ", frame.offset + frame.data_length, + ", which is beyond close offset: ", sequencer_.close_offset())); + return; } if (frame.fin) { @@ -463,6 +489,23 @@ void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) { "Reset frame stream offset overflow."); return; } + + if (GetQuicReloadableFlag(quic_close_connection_on_wrong_offset)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_close_connection_on_wrong_offset, 2, 2); + const QuicStreamOffset kMaxOffset = + std::numeric_limits::max(); + if (sequencer()->close_offset() != kMaxOffset && + frame.byte_offset != sequencer()->close_offset()) { + CloseConnectionWithDetails( + QUIC_STREAM_MULTIPLE_OFFSET, + QuicStrCat("Stream ", id_, + " received new final offset: ", frame.byte_offset, + ", which is different from close offset: ", + sequencer_.close_offset())); + return; + } + } + MaybeIncreaseHighestReceivedOffset(frame.byte_offset); if (flow_controller_->FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { @@ -624,64 +667,6 @@ void QuicStream::MaybeSendBlocked() { } } -QuicConsumedData QuicStream::WritevData(const struct iovec* iov, - int iov_count, - bool fin) { - if (write_side_closed_) { - QUIC_DLOG(ERROR) << ENDPOINT << "Stream " << id() - << "attempting to write when the write side is closed"; - if (type_ == READ_UNIDIRECTIONAL) { - CloseConnectionWithDetails( - QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM, - "Try to send data on read unidirectional stream"); - } - return QuicConsumedData(0, false); - } - - // How much data was provided. - size_t write_length = 0; - if (iov != nullptr) { - for (int i = 0; i < iov_count; ++i) { - write_length += iov[i].iov_len; - } - } - - QuicConsumedData consumed_data(0, false); - if (fin_buffered_) { - QUIC_BUG << "Fin already buffered"; - return consumed_data; - } - - if (kMaxStreamLength - send_buffer_.stream_offset() < write_length) { - QUIC_BUG << "Write too many data via stream " << id_; - CloseConnectionWithDetails( - QUIC_STREAM_LENGTH_OVERFLOW, - QuicStrCat("Write too many data via stream ", id_)); - return consumed_data; - } - - bool had_buffered_data = HasBufferedData(); - if (CanWriteNewData()) { - // Save all data if buffered data size is below low water mark. - consumed_data.bytes_consumed = write_length; - if (consumed_data.bytes_consumed > 0) { - QuicStreamOffset offset = send_buffer_.stream_offset(); - send_buffer_.SaveStreamData(iov, iov_count, 0, write_length); - OnDataBuffered(offset, write_length, nullptr); - } - } - consumed_data.fin_consumed = - consumed_data.bytes_consumed == write_length && fin; - fin_buffered_ = consumed_data.fin_consumed; - - if (!had_buffered_data && (HasBufferedData() || fin_buffered_)) { - // Write data if there is no buffered data before. - WriteBufferedData(); - } - - return consumed_data; -} - QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) { QuicConsumedData consumed_data(0, false); if (span.empty() && !fin) { @@ -831,7 +816,7 @@ void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { return; } - if (flow_controller_->UpdateSendWindowOffset(frame.byte_offset)) { + if (flow_controller_->UpdateSendWindowOffset(frame.max_data)) { // Let session unblock this stream. session_->MarkConnectionLevelWriteBlocked(id_); } @@ -1055,9 +1040,7 @@ void QuicStream::WriteBufferedData() { QUIC_DVLOG(1) << "stream " << id() << " shortens write length to " << write_length << " due to flow control"; } - if (session_->session_decides_what_to_write()) { - session_->SetTransmissionType(NOT_RETRANSMISSION); - } + session_->SetTransmissionType(NOT_RETRANSMISSION); StreamSendingState state = fin ? FIN : NO_FIN; if (fin && add_random_padding_after_fin_) { @@ -1180,10 +1163,6 @@ bool QuicStream::MaybeSetTtl(QuicTime::Delta ttl) { QUIC_DLOG(WARNING) << "Deadline has already been set."; return false; } - if (!session()->session_decides_what_to_write()) { - QUIC_DLOG(WARNING) << "This session does not support stream TTL yet."; - return false; - } QuicTime now = session()->connection()->clock()->ApproximateNow(); deadline_ = now + ttl; return true; @@ -1194,7 +1173,6 @@ bool QuicStream::HasDeadlinePassed() const { // No deadline has been set. return false; } - DCHECK(session()->session_decides_what_to_write()); QuicTime now = session()->connection()->clock()->ApproximateNow(); if (now < deadline_) { return false; @@ -1218,6 +1196,4 @@ void QuicStream::SendStopSending(uint16_t code) { session_->SendStopSending(code, id_); } -void QuicStream::OnStopSending(uint16_t /*code*/) {} - } // namespace quic 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 c8e5012767a..c936bc71264 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 @@ -136,9 +136,6 @@ class QUIC_EXPORT_PRIVATE QuicStream virtual ~QuicStream(); - // Not in use currently. - void SetFromConfig(); - // QuicStreamSequencer::StreamInterface implementation. QuicStreamId id() const override { return id_; } // Called by the stream subclass after it has consumed the final incoming @@ -247,9 +244,7 @@ class QUIC_EXPORT_PRIVATE QuicStream // sent. If this is not true on deletion of the stream object, the session // must keep track of the stream's byte offset until a definitive final value // arrives. - bool HasFinalReceivedByteOffset() const { - return fin_received_ || rst_received_; - } + bool HasReceivedFinalOffset() const { return fin_received_ || rst_received_; } // Returns true if the stream has queued data waiting to write. bool HasBufferedData() const; @@ -341,11 +336,8 @@ class QUIC_EXPORT_PRIVATE QuicStream // this method or not. void SendStopSending(uint16_t code); - // Invoked when QUIC receives a STOP_SENDING frame for this stream, informing - // the application that the peer has sent a STOP_SENDING. The default - // implementation is a noop. Is to be overridden by the application-specific - // QuicStream class. - virtual void OnStopSending(uint16_t code); + // Handle received StopSending frame. + virtual void OnStopSending(uint16_t /*code*/) {} // Close the write side of the socket. Further writes will fail. // Can be called by the subclass or internally. @@ -356,16 +348,6 @@ class QUIC_EXPORT_PRIVATE QuicStream bool is_static() const { return is_static_; } protected: - // Sends as many bytes in the first |count| buffers of |iov| to the connection - // as the connection will consume. If FIN is consumed, the write side is - // immediately closed. - // Returns the number of bytes consumed by the connection. - // Please note: Returned consumed data is the amount of data saved in send - // buffer. The data is not necessarily consumed by the connection. So write - // side is closed when FIN is sent. - // TODO(fayang): Let WritevData return boolean. - QuicConsumedData WritevData(const struct iovec* iov, int iov_count, bool fin); - // Close the read side of the socket. 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 @@ -437,9 +419,6 @@ class QUIC_EXPORT_PRIVATE QuicStream QuicOptional flow_controller, QuicFlowController* connection_flow_controller); - // Subclasses and consumers should use reading_stopped. - bool read_side_closed() const { return read_side_closed_; } - // Calls MaybeSendBlocked on the stream's flow controller and the connection // level flow controller. If the stream is flow control blocked by the // connection-level flow controller but not by the stream-level flow @@ -501,10 +480,6 @@ class QUIC_EXPORT_PRIVATE QuicStream // True if this stream has received a RST_STREAM frame. bool rst_received_; - // Tracks if the session this stream is running under was created by a - // server or a client. - Perspective perspective_; - QuicOptional flow_controller_; // The connection level flow controller. Not owned. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h index 1ac2947fca7..e39e14fcf85 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h @@ -29,7 +29,7 @@ const int kMaxStreamsWindowDivisor = 2; // This class manages the stream ids for Version 99/IETF QUIC. class QUIC_EXPORT_PRIVATE QuicStreamIdManager { public: - class DelegateInterface { + class QUIC_EXPORT_PRIVATE DelegateInterface { public: virtual ~DelegateInterface() = default; @@ -153,6 +153,10 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { largest_peer_created_stream_id_ = largest_peer_created_stream_id; } + QuicStreamId largest_peer_created_stream_id() const { + return largest_peer_created_stream_id_; + } + // These are the limits for outgoing and incoming streams, // respectively. For incoming there are two limits, what has // been advertised to the peer and what is actually available. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc index 7b7fb1a9e72..2ff55be857c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc @@ -13,7 +13,6 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h" using testing::_; -using testing::Invoke; using testing::StrictMock; namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc index ead192dd6fe..158afd80f63 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc @@ -9,6 +9,7 @@ #include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.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" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.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" @@ -95,6 +96,8 @@ void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) { bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset, QuicByteCount data_length, QuicDataWriter* writer) { + // TODO(renjietang): Remove this variable once quic_coalesce_stream_frames_2 + // is deprecated. bool write_index_hit = false; QuicDeque::iterator slice_it = write_index_ == -1 @@ -134,15 +137,33 @@ bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset, offset += copy_length; data_length -= copy_length; - if (write_index_hit && copy_length == available_bytes_in_slice) { + if (GetQuicRestartFlag(quic_coalesce_stream_frames_2)) { + QUIC_RESTART_FLAG_COUNT_N(quic_coalesce_stream_frames_2, 2, 3); + if (write_index_ != -1) { + QuicDeque::const_iterator index_slice = + buffered_slices_.begin() + write_index_; + if (index_slice->offset == slice_it->offset && + copy_length == available_bytes_in_slice) { + // The slice pointed by write_index has been fully written, advance + // write index. + ++write_index_; + } + } + } else if (write_index_hit && copy_length == available_bytes_in_slice) { // Finished writing all data in current slice, advance write index for // next write. ++write_index_; } } - if (write_index_hit && - static_cast(write_index_) == buffered_slices_.size()) { + if (GetQuicRestartFlag(quic_coalesce_stream_frames_2)) { + QUIC_RESTART_FLAG_COUNT_N(quic_coalesce_stream_frames_2, 3, 3); + if (write_index_ != -1 && + static_cast(write_index_) == buffered_slices_.size()) { + write_index_ = -1; + } + } else if (write_index_hit && + static_cast(write_index_) == buffered_slices_.size()) { // Already write to the end off buffer. QUIC_DVLOG(2) << "Finish writing out all buffered data."; write_index_ = -1; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h index 74e9d0d5ee2..51a10e9f325 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h @@ -26,7 +26,7 @@ class QuicDataWriter; // contiguous memory space. Please note, BufferedSlice is constructed when // stream data is saved in send buffer and is removed when stream data is fully // acked. It is move-only. -struct BufferedSlice { +struct QUIC_EXPORT_PRIVATE BufferedSlice { BufferedSlice(QuicMemSlice mem_slice, QuicStreamOffset offset); BufferedSlice(BufferedSlice&& other); BufferedSlice& operator=(BufferedSlice&& other); @@ -41,8 +41,9 @@ struct BufferedSlice { QuicStreamOffset offset; }; -struct StreamPendingRetransmission { - StreamPendingRetransmission(QuicStreamOffset offset, QuicByteCount length) +struct QUIC_EXPORT_PRIVATE StreamPendingRetransmission { + constexpr StreamPendingRetransmission(QuicStreamOffset offset, + QuicByteCount length) : offset(offset), length(length) {} // Starting offset of this pending retransmission. @@ -50,8 +51,7 @@ struct StreamPendingRetransmission { // Length of this pending retransmission. QuicByteCount length; - QUIC_EXPORT_PRIVATE bool operator==( - const StreamPendingRetransmission& other) const; + bool operator==(const StreamPendingRetransmission& other) const; }; // QuicStreamSendBuffer contains a list of QuicStreamDataSlices. New data slices @@ -62,7 +62,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer { public: explicit QuicStreamSendBuffer(QuicBufferAllocator* allocator); QuicStreamSendBuffer(const QuicStreamSendBuffer& other) = delete; - QuicStreamSendBuffer(QuicStreamSendBuffer&& other) = default; + QuicStreamSendBuffer(QuicStreamSendBuffer&& other) = delete; ~QuicStreamSendBuffer(); // Save |data_length| of data starts at |iov_offset| in |iov| to send buffer. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc index 3a5efb50e7f..90fcd6eb104 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc @@ -64,7 +64,7 @@ class QuicStreamSendBufferTest : public QuicTest { void WriteAllData() { // Write all data. char buf[4000]; - QuicDataWriter writer(4000, buf, HOST_BYTE_ORDER); + QuicDataWriter writer(4000, buf, quiche::HOST_BYTE_ORDER); send_buffer_.WriteStreamData(0, 3840u, &writer); send_buffer_.OnStreamDataConsumed(3840u); @@ -78,7 +78,7 @@ class QuicStreamSendBufferTest : public QuicTest { TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { char buf[4000]; - QuicDataWriter writer(4000, buf, HOST_BYTE_ORDER); + QuicDataWriter writer(4000, buf, quiche::HOST_BYTE_ORDER); std::string copy1(1024, 'a'); std::string copy2 = std::string(512, 'a') + std::string(256, 'b') + std::string(256, 'c'); @@ -95,7 +95,7 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { EXPECT_EQ(copy4, QuicStringPiece(buf + 3072, 768)); // Test data piece across boundries. - QuicDataWriter writer2(4000, buf, HOST_BYTE_ORDER); + QuicDataWriter writer2(4000, buf, quiche::HOST_BYTE_ORDER); std::string copy5 = std::string(536, 'a') + std::string(256, 'b') + std::string(232, 'c'); ASSERT_TRUE(send_buffer_.WriteStreamData(1000, 1024, &writer2)); @@ -105,7 +105,7 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { EXPECT_EQ(copy6, QuicStringPiece(buf + 1024, 1024)); // Invalid data copy. - QuicDataWriter writer3(4000, buf, HOST_BYTE_ORDER); + QuicDataWriter writer3(4000, buf, quiche::HOST_BYTE_ORDER); EXPECT_FALSE(send_buffer_.WriteStreamData(3000, 1024, &writer3)); EXPECT_QUIC_BUG(send_buffer_.WriteStreamData(0, 4000, &writer3), "Writer fails to write."); @@ -115,6 +115,41 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { EXPECT_EQ(3840u, send_buffer_.stream_bytes_outstanding()); } +// Regression test for b/143491027. +TEST_F(QuicStreamSendBufferTest, + WriteStreamDataContainsBothRetransmissionAndNewData) { + std::string copy1(1024, 'a'); + std::string copy2 = + std::string(512, 'a') + std::string(256, 'b') + std::string(256, 'c'); + std::string copy3 = std::string(1024, 'c') + std::string(100, 'd'); + char buf[6000]; + QuicDataWriter writer(6000, buf, quiche::HOST_BYTE_ORDER); + // Write more than one slice. + EXPECT_EQ(0, QuicStreamSendBufferPeer::write_index(&send_buffer_)); + ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer)); + EXPECT_EQ(copy1, QuicStringPiece(buf, 1024)); + EXPECT_EQ(1, QuicStreamSendBufferPeer::write_index(&send_buffer_)); + + // Retransmit the first frame and also send new data. + ASSERT_TRUE(send_buffer_.WriteStreamData(0, 2048, &writer)); + EXPECT_EQ(copy1 + copy2, QuicStringPiece(buf + 1024, 2048)); + + // Write new data. + if (!GetQuicRestartFlag(quic_coalesce_stream_frames_2)) { + EXPECT_EQ(1, QuicStreamSendBufferPeer::write_index(&send_buffer_)); + EXPECT_QUIC_DEBUG_DEATH(send_buffer_.WriteStreamData(2048, 50, &writer), + "Tried to write data out of sequence."); + } else { + EXPECT_EQ(2, QuicStreamSendBufferPeer::write_index(&send_buffer_)); + ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 50, &writer)); + EXPECT_EQ(std::string(50, 'c'), QuicStringPiece(buf + 1024 + 2048, 50)); + EXPECT_EQ(2, QuicStreamSendBufferPeer::write_index(&send_buffer_)); + ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 1124, &writer)); + EXPECT_EQ(copy3, QuicStringPiece(buf + 1024 + 2048 + 50, 1124)); + EXPECT_EQ(3, QuicStreamSendBufferPeer::write_index(&send_buffer_)); + } +} + TEST_F(QuicStreamSendBufferTest, RemoveStreamFrame) { WriteAllData(); @@ -255,7 +290,7 @@ TEST_F(QuicStreamSendBufferTest, PendingRetransmission) { TEST_F(QuicStreamSendBufferTest, CurrentWriteIndex) { char buf[4000]; - QuicDataWriter writer(4000, buf, HOST_BYTE_ORDER); + QuicDataWriter writer(4000, buf, quiche::HOST_BYTE_ORDER); // With data buffered, index points to the 1st slice of data. EXPECT_EQ(0u, QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)->offset); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc index 8f84fb9475b..d7976689331 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc @@ -9,6 +9,7 @@ #include #include +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_stream.h" #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h" @@ -26,6 +27,7 @@ namespace quic { QuicStreamSequencer::QuicStreamSequencer(StreamInterface* quic_stream) : stream_(quic_stream), buffered_frames_(kStreamReceiveWindowLimit), + highest_offset_(0), close_offset_(std::numeric_limits::max()), blocked_(false), num_frames_received_(0), @@ -33,7 +35,13 @@ QuicStreamSequencer::QuicStreamSequencer(StreamInterface* quic_stream) ignore_read_data_(false), level_triggered_(false), stop_reading_when_level_triggered_( - GetQuicReloadableFlag(quic_stop_reading_when_level_triggered)) {} + GetQuicReloadableFlag(quic_stop_reading_when_level_triggered)), + close_connection_and_discard_data_on_wrong_offset_(GetQuicReloadableFlag( + quic_close_connection_and_discard_data_on_wrong_offset)) { + if (stop_reading_when_level_triggered_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_stop_reading_when_level_triggered); + } +} QuicStreamSequencer::~QuicStreamSequencer() {} @@ -48,8 +56,9 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { if (data_len == 0) { return; } - if (GetQuicReloadableFlag(quic_no_stream_data_after_reset)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_no_stream_data_after_reset); + if (close_connection_and_discard_data_on_wrong_offset_) { + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_close_connection_and_discard_data_on_wrong_offset, 1, 3); if (!should_process_data) { return; } @@ -66,6 +75,7 @@ void QuicStreamSequencer::OnCryptoFrame(const QuicCryptoFrame& frame) { void QuicStreamSequencer::OnFrameData(QuicStreamOffset byte_offset, size_t data_len, const char* data_buffer) { + highest_offset_ = std::max(highest_offset_, byte_offset + data_len); const size_t previous_readable_bytes = buffered_frames_.ReadableBytes(); size_t bytes_written; std::string error_details; @@ -123,7 +133,31 @@ bool QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) { // If there is a scheduled close, the new offset should match it. if (close_offset_ != kMaxOffset && offset != close_offset_) { - stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS); + if (!close_connection_and_discard_data_on_wrong_offset_) { + stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS); + return false; + } + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_close_connection_and_discard_data_on_wrong_offset, 2, 3); + stream_->CloseConnectionWithDetails( + QUIC_STREAM_SEQUENCER_INVALID_STATE, + QuicStrCat("Stream ", stream_->id(), + " received new final offset: ", offset, + ", which is different from close offset: ", close_offset_)); + return false; + } + + // The final offset should be no less than the highest offset that is + // received. + if (close_connection_and_discard_data_on_wrong_offset_ && + offset < highest_offset_) { + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_close_connection_and_discard_data_on_wrong_offset, 3, 3); + stream_->CloseConnectionWithDetails( + QUIC_STREAM_SEQUENCER_INVALID_STATE, + QuicStrCat( + "Stream ", stream_->id(), " received fin with offset: ", offset, + ", which reduces current highest offset: ", highest_offset_)); return false; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h index a735a1ebbf5..878acb04307 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" namespace quic { @@ -24,7 +25,7 @@ class QuicStreamSequencerPeer; class QUIC_EXPORT_PRIVATE QuicStreamSequencer { public: // Interface that thie Sequencer uses to communicate with the Stream. - class StreamInterface { + class QUIC_EXPORT_PRIVATE StreamInterface { public: virtual ~StreamInterface() = default; @@ -182,6 +183,9 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer { // Stores received data in offset order. QuicStreamSequencerBuffer buffered_frames_; + // The highest offset that is received so far. + QuicStreamOffset highest_offset_; + // The offset, if any, we got a stream termination for. When this many bytes // have been processed, the sequencer will be closed. QuicStreamOffset close_offset_; @@ -207,6 +211,11 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer { // the sequencer will discard incoming data (but not FIN bits) after // StopReading is called, even in level_triggered_ mode. const bool stop_reading_when_level_triggered_; + + // Latched value of quic_close_connection_and_discard_data_on_wrong_offset. + // When true, the sequencer will inform the stream to close connection when + // wrong offset is received. And the stream frame's data will be discarded. + const bool close_connection_and_discard_data_on_wrong_offset_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h index 93b723f1781..406cd92edc3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h @@ -85,7 +85,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { static const size_t kBlockSizeBytes = 8 * 1024; // 8KB // The basic storage block used by this buffer. - struct BufferBlock { + struct QUIC_EXPORT_PRIVATE BufferBlock { char buffer[kBlockSizeBytes]; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc index 028c12b6077..b17dcc498fa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc @@ -110,15 +110,15 @@ TEST_F(QuicStreamSequencerBufferTest, ClearOnEmpty) { TEST_F(QuicStreamSequencerBufferTest, OnStreamData0length) { QuicErrorCode error = buffer_->OnStreamData(800, "", &written_, &error_details_); - EXPECT_EQ(error, QUIC_EMPTY_STREAM_FRAME_NO_FIN); + EXPECT_THAT(error, IsError(QUIC_EMPTY_STREAM_FRAME_NO_FIN)); EXPECT_TRUE(helper_->CheckBufferInvariants()); } TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) { EXPECT_FALSE(helper_->IsBufferAllocated()); std::string source(1024, 'a'); - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(800, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(800, source, &written_, &error_details_), + IsQuicNoError()); BufferBlock* block_ptr = helper_->GetBlock(0); for (size_t i = 0; i < source.size(); ++i) { ASSERT_EQ('a', block_ptr->buffer[helper_->GetInBlockOffset(800) + i]); @@ -135,8 +135,8 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) { TEST_F(QuicStreamSequencerBufferTest, Move) { EXPECT_FALSE(helper_->IsBufferAllocated()); std::string source(1024, 'a'); - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(800, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(800, source, &written_, &error_details_), + IsQuicNoError()); BufferBlock* block_ptr = helper_->GetBlock(0); for (size_t i = 0; i < source.size(); ++i) { ASSERT_EQ('a', block_ptr->buffer[helper_->GetInBlockOffset(800) + i]); @@ -160,8 +160,8 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInvalidSource) { // Pass in an invalid source, expects to return error. QuicStringPiece source; source = QuicStringPiece(nullptr, 1024); - EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE, - buffer_->OnStreamData(800, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(800, source, &written_, &error_details_), + IsError(QUIC_STREAM_SEQUENCER_INVALID_STATE)); EXPECT_EQ(0u, error_details_.find(QuicStrCat( "QuicStreamSequencerBuffer error: OnStreamData() " "dest == nullptr: ", @@ -171,13 +171,13 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInvalidSource) { TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) { std::string source(1024, 'a'); // Write something into [800, 1824) - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(800, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(800, source, &written_, &error_details_), + IsQuicNoError()); // Try to write to [0, 1024) and [1024, 2048). - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(0, source, &written_, &error_details_)); - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(1024, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(0, source, &written_, &error_details_), + IsQuicNoError()); + EXPECT_THAT(buffer_->OnStreamData(1024, source, &written_, &error_details_), + IsQuicNoError()); } TEST_F(QuicStreamSequencerBufferTest, @@ -188,31 +188,31 @@ TEST_F(QuicStreamSequencerBufferTest, source = std::string(800, 'b'); std::string one_byte = "c"; // Write [1, 801). - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(1, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(1, source, &written_, &error_details_), + IsQuicNoError()); // Write [0, 800). - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(0, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(0, source, &written_, &error_details_), + IsQuicNoError()); // Write [1823, 1824). - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(1823, one_byte, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(1823, one_byte, &written_, &error_details_), + IsQuicNoError()); EXPECT_EQ(0u, written_); // write one byte to [1824, 1825) - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(1824, one_byte, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(1824, one_byte, &written_, &error_details_), + IsQuicNoError()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithoutOverlap) { std::string source(1024, 'a'); // Write something into [800, 1824). - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(800, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(800, source, &written_, &error_details_), + IsQuicNoError()); source = std::string(100, 'b'); // Write something into [kBlockSizeBytes * 2 - 20, kBlockSizeBytes * 2 + 80). - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(kBlockSizeBytes * 2 - 20, source, &written_, - &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(kBlockSizeBytes * 2 - 20, source, &written_, + &error_details_), + IsQuicNoError()); EXPECT_EQ(3, helper_->IntervalSize()); EXPECT_EQ(1024u + 100u, buffer_->BytesBuffered()); EXPECT_TRUE(helper_->CheckBufferInvariants()); @@ -229,20 +229,20 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInLongStreamWithOverlap) { std::string source(kBytesToWrite, 'a'); // Frame [2^32 + 500, 2^32 + 600). QuicStreamOffset offset = pow(2, 32) + 500; - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(offset, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(offset, source, &written_, &error_details_), + IsQuicNoError()); EXPECT_EQ(2, helper_->IntervalSize()); // Frame [2^32 + 700, 2^32 + 800). offset = pow(2, 32) + 700; - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(offset, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(offset, source, &written_, &error_details_), + IsQuicNoError()); EXPECT_EQ(3, helper_->IntervalSize()); // Another frame [2^32 + 300, 2^32 + 400). offset = pow(2, 32) + 300; - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(offset, source, &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(offset, source, &written_, &error_details_), + IsQuicNoError()); EXPECT_EQ(4, helper_->IntervalSize()); } @@ -250,9 +250,9 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEnd) { // Write 50 bytes to the end. const size_t kBytesToWrite = 50; std::string source(kBytesToWrite, 'a'); - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source, - &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source, + &written_, &error_details_), + IsQuicNoError()); EXPECT_EQ(50u, buffer_->BytesBuffered()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } @@ -261,42 +261,42 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEndCorner) { // Write 1 byte to the end. const size_t kBytesToWrite = 1; std::string source(kBytesToWrite, 'a'); - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source, - &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source, + &written_, &error_details_), + IsQuicNoError()); EXPECT_EQ(1u, buffer_->BytesBuffered()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } TEST_F(QuicStreamSequencerBufferTest, OnStreamDataBeyondCapacity) { std::string source(60, 'a'); - EXPECT_EQ(QUIC_INTERNAL_ERROR, - buffer_->OnStreamData(max_capacity_bytes_ - 50, source, &written_, - &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(max_capacity_bytes_ - 50, source, &written_, + &error_details_), + IsError(QUIC_INTERNAL_ERROR)); EXPECT_TRUE(helper_->CheckBufferInvariants()); source = "b"; - EXPECT_EQ(QUIC_INTERNAL_ERROR, - buffer_->OnStreamData(max_capacity_bytes_, source, &written_, - &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(max_capacity_bytes_, source, &written_, + &error_details_), + IsError(QUIC_INTERNAL_ERROR)); EXPECT_TRUE(helper_->CheckBufferInvariants()); - EXPECT_EQ(QUIC_INTERNAL_ERROR, - buffer_->OnStreamData(max_capacity_bytes_ * 1000, source, &written_, - &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(max_capacity_bytes_ * 1000, source, + &written_, &error_details_), + IsError(QUIC_INTERNAL_ERROR)); EXPECT_TRUE(helper_->CheckBufferInvariants()); // Disallow current_gap != gaps_.end() - EXPECT_EQ(QUIC_INTERNAL_ERROR, - buffer_->OnStreamData(static_cast(-1), source, - &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(static_cast(-1), source, + &written_, &error_details_), + IsError(QUIC_INTERNAL_ERROR)); EXPECT_TRUE(helper_->CheckBufferInvariants()); // Disallow offset + size overflow source = "bbb"; - EXPECT_EQ(QUIC_INTERNAL_ERROR, - buffer_->OnStreamData(static_cast(-2), source, - &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(static_cast(-2), source, + &written_, &error_details_), + IsError(QUIC_INTERNAL_ERROR)); EXPECT_TRUE(helper_->CheckBufferInvariants()); EXPECT_EQ(0u, buffer_->BytesBuffered()); } @@ -314,7 +314,8 @@ TEST_F(QuicStreamSequencerBufferTest, Readv100Bytes) { char dest[120]; iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(iovecs, 3, &read, &error_details_), + IsQuicNoError()); QUIC_LOG(ERROR) << error_details_; EXPECT_EQ(100u, read); EXPECT_EQ(100u, buffer_->BytesConsumed()); @@ -335,7 +336,8 @@ TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossBlocks) { std::fill(dest, dest + 512, 0); iovec iovecs[2]{iovec{dest, 256}, iovec{dest + 256, 256}}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 2, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(iovecs, 2, &read, &error_details_), + IsQuicNoError()); } // The last read only reads the rest 50 bytes in 2nd block. EXPECT_EQ(std::string(50, 'a'), std::string(dest, 50)); @@ -353,7 +355,7 @@ TEST_F(QuicStreamSequencerBufferTest, ClearAfterRead) { char dest[512]{0}; const iovec iov{dest, 512}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(&iov, 1, &read, &error_details_), IsQuicNoError()); // Clear() should make buffer empty while preserving BytesConsumed() buffer_->Clear(); EXPECT_TRUE(buffer_->Empty()); @@ -369,14 +371,15 @@ TEST_F(QuicStreamSequencerBufferTest, char dest[512]{0}; const iovec iov{dest, 512}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(&iov, 1, &read, &error_details_), IsQuicNoError()); EXPECT_EQ(source.size(), written_); // Write more than half block size of bytes in the last block with 'b', which // will wrap to the beginning and reaches the full capacity. source = std::string(0.5 * kBlockSizeBytes + 512, 'b'); - EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(2 * kBlockSizeBytes, source, - &written_, &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(2 * kBlockSizeBytes, source, &written_, + &error_details_), + IsQuicNoError()); EXPECT_EQ(source.size(), written_); EXPECT_TRUE(helper_->CheckBufferInvariants()); } @@ -390,14 +393,14 @@ TEST_F(QuicStreamSequencerBufferTest, char dest[512]{0}; const iovec iov{dest, 512}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(&iov, 1, &read, &error_details_), IsQuicNoError()); // Try to write from [max_capacity_bytes_ - 0.5 * kBlockSizeBytes, // max_capacity_bytes_ + 512 + 1). But last bytes exceeds current capacity. source = std::string(0.5 * kBlockSizeBytes + 512 + 1, 'b'); - EXPECT_EQ(QUIC_INTERNAL_ERROR, - buffer_->OnStreamData(2 * kBlockSizeBytes, source, &written_, - &error_details_)); + EXPECT_THAT(buffer_->OnStreamData(2 * kBlockSizeBytes, source, &written_, + &error_details_), + IsError(QUIC_INTERNAL_ERROR)); EXPECT_TRUE(helper_->CheckBufferInvariants()); } @@ -409,7 +412,7 @@ TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossLastBlock) { char dest[512]{0}; const iovec iov{dest, 512}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(&iov, 1, &read, &error_details_), IsQuicNoError()); source = std::string(256, 'b'); buffer_->OnStreamData(max_capacity_bytes_, source, &written_, &error_details_); @@ -419,7 +422,8 @@ TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossLastBlock) { std::unique_ptr dest1{new char[max_capacity_bytes_]}; dest1[0] = 0; const iovec iov1{dest1.get(), max_capacity_bytes_}; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov1, 1, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(&iov1, 1, &read, &error_details_), + IsQuicNoError()); EXPECT_EQ(max_capacity_bytes_ - 512 + 256, read); EXPECT_EQ(max_capacity_bytes_ + 256, buffer_->BytesConsumed()); EXPECT_TRUE(buffer_->Empty()); @@ -430,7 +434,7 @@ TEST_F(QuicStreamSequencerBufferTest, ReadvEmpty) { char dest[512]{0}; iovec iov{dest, 512}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(&iov, 1, &read, &error_details_), IsQuicNoError()); EXPECT_EQ(0u, read); EXPECT_TRUE(helper_->CheckBufferInvariants()); } @@ -452,7 +456,8 @@ TEST_F(QuicStreamSequencerBufferTest, ReleaseWholeBuffer) { char dest[120]; iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}}; size_t read; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_)); + EXPECT_THAT(buffer_->Readv(iovecs, 3, &read, &error_details_), + IsQuicNoError()); EXPECT_EQ(100u, read); EXPECT_EQ(100u, buffer_->BytesConsumed()); EXPECT_TRUE(helper_->CheckBufferInvariants()); @@ -847,7 +852,7 @@ TEST_F(QuicStreamSequencerBufferTest, TooManyGaps) { QuicStreamOffset last_straw = 2 * kMaxNumGapsAllowed - 1; if (begin == last_straw) { - EXPECT_EQ(QUIC_TOO_MANY_STREAM_DATA_INTERVALS, rs); + EXPECT_THAT(rs, IsError(QUIC_TOO_MANY_STREAM_DATA_INTERVALS)); EXPECT_EQ("Too many data intervals received for this stream.", error_details_); break; @@ -982,9 +987,9 @@ TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndReadv) { num_to_read += dest_iov[i].iov_len; } size_t actually_read; - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->Readv(dest_iov, kNumReads, &actually_read, - &error_details_)); + EXPECT_THAT(buffer_->Readv(dest_iov, kNumReads, &actually_read, + &error_details_), + IsQuicNoError()); ASSERT_LE(actually_read, num_to_read); QUIC_DVLOG(1) << " read from offset: " << total_bytes_read_ << " size: " << num_to_read diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc index 8ad845b80a7..cb6fb936cf6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.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" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -374,12 +375,16 @@ TEST_F(QuicStreamSequencerTest, MultipleOffsets) { OnFinFrame(3, ""); EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get())); - EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); + if (!GetQuicReloadableFlag( + quic_close_connection_and_discard_data_on_wrong_offset)) { + EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); + } else { + EXPECT_CALL(stream_, CloseConnectionWithDetails( + QUIC_STREAM_SEQUENCER_INVALID_STATE, + "Stream 1 received new final offset: 1, which is " + "different from close offset: 3")); + } OnFinFrame(1, ""); - EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get())); - - OnFinFrame(3, ""); - EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get())); } class QuicSequencerRandomTest : public QuicStreamSequencerTest { @@ -756,14 +761,35 @@ TEST_F(QuicStreamSequencerTest, StopReadingWithLevelTriggered) { // Regression test for https://crbug.com/992486. TEST_F(QuicStreamSequencerTest, CorruptFinFrames) { - SetQuicReloadableFlag(quic_no_stream_data_after_reset, true); - EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); + if (!GetQuicReloadableFlag( + quic_close_connection_and_discard_data_on_wrong_offset)) { + return; + } + EXPECT_CALL(stream_, CloseConnectionWithDetails( + QUIC_STREAM_SEQUENCER_INVALID_STATE, + "Stream 1 received new final offset: 1, which is " + "different from close offset: 2")); OnFinFrame(2u, ""); OnFinFrame(0u, "a"); EXPECT_FALSE(sequencer_->HasBytesToRead()); } +// Regression test for crbug.com/1015693 +TEST_F(QuicStreamSequencerTest, ReceiveFinLessThanHighestOffset) { + if (!GetQuicReloadableFlag( + quic_close_connection_and_discard_data_on_wrong_offset)) { + return; + } + EXPECT_CALL(stream_, OnDataAvailable()).Times(1); + EXPECT_CALL(stream_, CloseConnectionWithDetails( + QUIC_STREAM_SEQUENCER_INVALID_STATE, + "Stream 1 received fin with offset: 0, which " + "reduces current highest offset: 3")); + OnFrame(0u, "abc"); + OnFinFrame(0u, ""); +} + } // namespace } // namespace test } // namespace quic 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 411d6d00858..673c7a7405c 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 @@ -8,8 +8,10 @@ #include #include +#include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h" #include "net/third_party/quiche/src/quic/core/quic_connection.h" #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_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" @@ -50,12 +52,14 @@ const size_t kDataLen = 9; class TestStream : public QuicStream { public: TestStream(QuicStreamId id, QuicSession* session, StreamType type) - : QuicStream(id, session, /*is_static=*/false, type) {} + : QuicStream(id, session, /*is_static=*/false, type) { + sequencer()->set_level_triggered(true); + } TestStream(PendingStream* pending, StreamType type, bool is_static) : QuicStream(pending, type, is_static) {} - void OnDataAvailable() override {} + MOCK_METHOD0(OnDataAvailable, void()); MOCK_METHOD0(OnCanWriteNewData, void()); @@ -66,7 +70,6 @@ class TestStream : public QuicStream { using QuicStream::OnClose; using QuicStream::WriteMemSlices; using QuicStream::WriteOrBufferData; - using QuicStream::WritevData; private: std::string data_; @@ -99,7 +102,8 @@ class QuicStreamTest : public QuicTestWithParam { session_->config(), 10); session_->OnConfigNegotiated(); - stream_ = new TestStream(kTestStreamId, session_.get(), BIDIRECTIONAL); + stream_ = new StrictMock(kTestStreamId, session_.get(), + BIDIRECTIONAL); EXPECT_NE(nullptr, stream_); // session_ now owns stream_. session_->ActivateStream(QuicWrapUnique(stream_)); @@ -144,7 +148,7 @@ class QuicStreamTest : public QuicTestWithParam { MockAlarmFactory alarm_factory_; MockQuicConnection* connection_; std::unique_ptr session_; - TestStream* stream_; + StrictMock* stream_; QuicWriteBlockedList* write_blocked_list_; QuicTime::Delta zero_; ParsedQuicVersionVector supported_versions_; @@ -177,8 +181,7 @@ TEST_P(QuicStreamTest, PendingStreamTooMuchData) { // Receive a stream frame that violates flow control: the byte offset is // higher than the receive window offset. QuicStreamFrame frame(kTestStreamId + 2, false, - kInitialSessionFlowControlWindowForTest + 1, - QuicStringPiece(".")); + kInitialSessionFlowControlWindowForTest + 1, "."); // Stream should not accept the frame, and the connection should be closed. EXPECT_CALL(*connection_, @@ -221,10 +224,10 @@ TEST_P(QuicStreamTest, FromPendingStream) { PendingStream pending(kTestStreamId + 2, session_.get()); - QuicStreamFrame frame(kTestStreamId + 2, false, 2, QuicStringPiece(".")); + QuicStreamFrame frame(kTestStreamId + 2, false, 2, "."); pending.OnStreamFrame(frame); pending.OnStreamFrame(frame); - QuicStreamFrame frame2(kTestStreamId + 2, true, 3, QuicStringPiece(".")); + QuicStreamFrame frame2(kTestStreamId + 2, true, 3, "."); pending.OnStreamFrame(frame2); TestStream stream(&pending, StreamType::READ_UNIDIRECTIONAL, false); @@ -243,14 +246,14 @@ TEST_P(QuicStreamTest, FromPendingStreamThenData) { PendingStream pending(kTestStreamId + 2, session_.get()); - QuicStreamFrame frame(kTestStreamId + 2, false, 2, QuicStringPiece(".")); + QuicStreamFrame frame(kTestStreamId + 2, false, 2, "."); pending.OnStreamFrame(frame); auto stream = new TestStream(&pending, StreamType::READ_UNIDIRECTIONAL, false); session_->ActivateStream(QuicWrapUnique(stream)); - QuicStreamFrame frame2(kTestStreamId + 2, true, 3, QuicStringPiece(".")); + QuicStreamFrame frame2(kTestStreamId + 2, true, 3, "."); stream->OnStreamFrame(frame2); EXPECT_EQ(2, stream->num_frames_received()); @@ -301,11 +304,7 @@ TEST_P(QuicStreamTest, BlockIfOnlySomeDataConsumed) { NO_FIN); })); stream_->WriteOrBufferData(QuicStringPiece(kData1, 2), false, nullptr); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); EXPECT_EQ(1u, stream_->BufferedDataBytes()); } @@ -323,11 +322,7 @@ TEST_P(QuicStreamTest, BlockIfFinNotConsumedWithData) { NO_FIN); })); stream_->WriteOrBufferData(QuicStringPiece(kData1, 2), true, nullptr); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); } @@ -374,11 +369,7 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { })); stream_->WriteOrBufferData(kData1, false, nullptr); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(1u, stream_->BufferedDataBytes()); EXPECT_TRUE(HasWriteBlockedStreams()); @@ -392,12 +383,9 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { return MockQuicSession::ConsumeData(stream_, stream_->id(), kDataLen - 1, kDataLen - 1, NO_FIN); })); + EXPECT_CALL(*stream_, OnCanWriteNewData()); stream_->OnCanWrite(); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); // And finally the end of the bytes_consumed. EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) @@ -405,12 +393,9 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { return MockQuicSession::ConsumeData(stream_, stream_->id(), 2u, 2 * kDataLen - 2, NO_FIN); })); + EXPECT_CALL(*stream_, OnCanWriteNewData()); stream_->OnCanWrite(); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); } TEST_P(QuicStreamTest, WriteOrBufferDataReachStreamLimit) { @@ -421,11 +406,7 @@ TEST_P(QuicStreamTest, WriteOrBufferDataReachStreamLimit) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Invoke(&(MockQuicSession::ConsumeData))); stream_->WriteOrBufferData(data, false, nullptr); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)); EXPECT_QUIC_BUG(stream_->WriteOrBufferData("a", false, nullptr), "Write too many data via stream"); @@ -436,12 +417,12 @@ TEST_P(QuicStreamTest, ConnectionCloseAfterStreamClose) { QuicStreamPeer::CloseReadSide(stream_); stream_->CloseWriteSide(); - EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); + EXPECT_THAT(stream_->connection_error(), IsQuicNoError()); stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, ConnectionCloseSource::FROM_SELF); - EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); + EXPECT_THAT(stream_->connection_error(), IsQuicNoError()); } TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) { @@ -460,11 +441,7 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) { NO_FIN); })); stream_->WriteOrBufferData(QuicStringPiece(kData1, 1), false, nullptr); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_FALSE(fin_sent()); EXPECT_FALSE(rst_sent()); @@ -540,9 +517,8 @@ TEST_P(QuicStreamTest, StreamFlowControlMultipleWindowUpdates) { QuicWindowUpdateFrame window_update_1(kInvalidControlFrameId, stream_->id(), kMinimumFlowControlSendWindow + 5); stream_->OnWindowUpdateFrame(window_update_1); - EXPECT_EQ( - window_update_1.byte_offset, - QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller())); + EXPECT_EQ(window_update_1.max_data, QuicFlowControllerPeer::SendWindowOffset( + stream_->flow_controller())); // Now send a few more WINDOW_UPDATES and make sure that only the largest is // remembered. @@ -555,9 +531,8 @@ TEST_P(QuicStreamTest, StreamFlowControlMultipleWindowUpdates) { stream_->OnWindowUpdateFrame(window_update_2); stream_->OnWindowUpdateFrame(window_update_3); stream_->OnWindowUpdateFrame(window_update_4); - EXPECT_EQ( - window_update_3.byte_offset, - QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller())); + EXPECT_EQ(window_update_3.max_data, QuicFlowControllerPeer::SendWindowOffset( + stream_->flow_controller())); } TEST_P(QuicStreamTest, FrameStats) { @@ -565,13 +540,16 @@ TEST_P(QuicStreamTest, FrameStats) { EXPECT_EQ(0, stream_->num_frames_received()); EXPECT_EQ(0, stream_->num_duplicate_frames_received()); - QuicStreamFrame frame(stream_->id(), false, 0, QuicStringPiece(".")); + QuicStreamFrame frame(stream_->id(), false, 0, "."); + EXPECT_CALL(*stream_, OnDataAvailable()).Times(2); stream_->OnStreamFrame(frame); EXPECT_EQ(1, stream_->num_frames_received()); EXPECT_EQ(0, stream_->num_duplicate_frames_received()); stream_->OnStreamFrame(frame); EXPECT_EQ(2, stream_->num_frames_received()); EXPECT_EQ(1, stream_->num_duplicate_frames_received()); + QuicStreamFrame frame2(stream_->id(), false, 1, "abc"); + stream_->OnStreamFrame(frame2); } // Verify that when we receive a packet which violates flow control (i.e. sends @@ -583,8 +561,7 @@ TEST_P(QuicStreamTest, StreamSequencerNeverSeesPacketsViolatingFlowControl) { // Receive a stream frame that violates flow control: the byte offset is // higher than the receive window offset. QuicStreamFrame frame(stream_->id(), false, - kInitialSessionFlowControlWindowForTest + 1, - QuicStringPiece(".")); + kInitialSessionFlowControlWindowForTest + 1, "."); EXPECT_GT(frame.offset, QuicFlowControllerPeer::ReceiveWindowOffset( stream_->flow_controller())); @@ -597,6 +574,7 @@ TEST_P(QuicStreamTest, StreamSequencerNeverSeesPacketsViolatingFlowControl) { // Verify that after the consumer calls StopReading(), the stream still sends // flow control updates. TEST_P(QuicStreamTest, StopReadingSendsFlowControl) { + SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true); Initialize(); stream_->StopReading(); @@ -624,40 +602,38 @@ TEST_P(QuicStreamTest, StopReadingSendsFlowControl) { TEST_P(QuicStreamTest, FinalByteOffsetFromFin) { Initialize(); - EXPECT_FALSE(stream_->HasFinalReceivedByteOffset()); + EXPECT_FALSE(stream_->HasReceivedFinalOffset()); - QuicStreamFrame stream_frame_no_fin(stream_->id(), false, 1234, - QuicStringPiece(".")); + QuicStreamFrame stream_frame_no_fin(stream_->id(), false, 1234, "."); stream_->OnStreamFrame(stream_frame_no_fin); - EXPECT_FALSE(stream_->HasFinalReceivedByteOffset()); + EXPECT_FALSE(stream_->HasReceivedFinalOffset()); - QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, - QuicStringPiece(".")); + QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, "."); stream_->OnStreamFrame(stream_frame_with_fin); - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); } TEST_P(QuicStreamTest, FinalByteOffsetFromRst) { Initialize(); - EXPECT_FALSE(stream_->HasFinalReceivedByteOffset()); + EXPECT_FALSE(stream_->HasReceivedFinalOffset()); QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 1234); stream_->OnStreamReset(rst_frame); - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); } TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) { Initialize(); - EXPECT_FALSE(stream_->HasFinalReceivedByteOffset()); + EXPECT_FALSE(stream_->HasReceivedFinalOffset()); QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 0xFFFFFFFFFFFF); // Stream should not accept the frame, and the connection should be closed. EXPECT_CALL(*connection_, CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); stream_->OnStreamReset(rst_frame); - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); stream_->OnClose(); } @@ -670,7 +646,7 @@ TEST_P(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) { // ignores such a stream frame. Initialize(); - EXPECT_FALSE(stream_->HasFinalReceivedByteOffset()); + EXPECT_FALSE(stream_->HasReceivedFinalOffset()); const QuicStreamOffset kByteOffsetExceedingFlowControlWindow = kInitialSessionFlowControlWindowForTest + 1; const QuicStreamOffset current_stream_flow_control_offset = @@ -688,7 +664,7 @@ TEST_P(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); stream_->OnStreamFrame(zero_length_stream_frame_with_fin); - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); // The flow control receive offset values should not have changed. EXPECT_EQ( @@ -721,11 +697,9 @@ TEST_P(QuicStreamTest, OnStreamFrameUpperLimit) { EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)) .Times(0); - QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength - 1, - QuicStringPiece(".")); + QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength - 1, "."); stream_->OnStreamFrame(stream_frame); - QuicStreamFrame stream_frame2(stream_->id(), true, kMaxStreamLength, - QuicStringPiece("")); + QuicStreamFrame stream_frame2(stream_->id(), true, kMaxStreamLength, ""); stream_->OnStreamFrame(stream_frame2); } @@ -733,8 +707,7 @@ TEST_P(QuicStreamTest, StreamTooLong) { Initialize(); EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)) .Times(1); - QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength, - QuicStringPiece(".")); + QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength, "."); EXPECT_QUIC_PEER_BUG(stream_->OnStreamFrame(stream_frame), QuicStrCat("Receive stream frame on stream ", stream_->id(), " reaches max stream length")); @@ -745,11 +718,10 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) { Initialize(); // Incoming data with FIN. - QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, - QuicStringPiece(".")); + QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, "."); stream_->OnStreamFrame(stream_frame_with_fin); // The FIN has been received but not consumed. - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_FALSE(stream_->reading_stopped()); @@ -785,11 +757,10 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) { EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); // Incoming data with FIN. - QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, - QuicStringPiece(".")); + QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, "."); stream_->OnStreamFrame(stream_frame_with_fin); // The FIN has been received but not consumed. - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_FALSE(stream_->reading_stopped()); @@ -808,7 +779,8 @@ TEST_P(QuicStreamTest, EarlyResponseFinHandling) { .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Receive data for the request. - QuicStreamFrame frame1(stream_->id(), false, 0, QuicStringPiece("Start")); + EXPECT_CALL(*stream_, OnDataAvailable()).Times(1); + QuicStreamFrame frame1(stream_->id(), false, 0, "Start"); stream_->OnStreamFrame(frame1); // When QuicSimpleServerStream sends the response, it calls // QuicStream::CloseReadSide() first. @@ -817,10 +789,10 @@ TEST_P(QuicStreamTest, EarlyResponseFinHandling) { stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_)); // Receive remaining data and FIN for the request. - QuicStreamFrame frame2(stream_->id(), true, 0, QuicStringPiece("End")); + QuicStreamFrame frame2(stream_->id(), true, 0, "End"); stream_->OnStreamFrame(frame2); EXPECT_TRUE(stream_->fin_received()); - EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); + EXPECT_TRUE(stream_->HasReceivedFinalOffset()); } TEST_P(QuicStreamTest, StreamWaitsForAcks) { @@ -834,11 +806,7 @@ TEST_P(QuicStreamTest, StreamWaitsForAcks) { // Send kData1. stream_->WriteOrBufferData(kData1, false, nullptr); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); QuicByteCount newly_acked_length = 0; @@ -853,11 +821,7 @@ TEST_P(QuicStreamTest, StreamWaitsForAcks) { // Send kData2. stream_->WriteOrBufferData(kData2, false, nullptr); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // Send FIN. stream_->WriteOrBufferData("", true, nullptr); @@ -873,11 +837,7 @@ TEST_P(QuicStreamTest, StreamWaitsForAcks) { EXPECT_EQ(9u, newly_acked_length); // Stream is waiting for acks as FIN is not acked. EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); // FIN is acked. @@ -900,46 +860,26 @@ TEST_P(QuicStreamTest, StreamDataGetAckedOutOfOrder) { stream_->WriteOrBufferData("", true, nullptr); EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); QuicByteCount newly_acked_length = 0; EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(), &newly_acked_length)); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 9, false, QuicTime::Delta::Zero(), &newly_acked_length)); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(), &newly_acked_length)); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); // FIN is not acked yet. EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(), &newly_acked_length)); EXPECT_EQ(0u, newly_acked_length); @@ -957,31 +897,23 @@ TEST_P(QuicStreamTest, CancelStream) { stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // Cancel stream. stream_->Reset(QUIC_STREAM_NO_ERROR); // stream still waits for acks as the error code is QUIC_STREAM_NO_ERROR, and // data is going to be retransmitted. EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_CALL(*connection_, OnStreamReset(stream_->id(), QUIC_STREAM_CANCELLED)); - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*session_, SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, 9)) .WillOnce(InvokeWithoutArgs([this]() { - return QuicSessionPeer::SendRstStreamInner( - session_.get(), stream_->id(), QUIC_STREAM_CANCELLED, - stream_->stream_bytes_written(), - /*close_write_side_only=*/false); + session_->ReallySendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, + stream_->stream_bytes_written()); })); stream_->Reset(QUIC_STREAM_CANCELLED); @@ -1007,11 +939,7 @@ TEST_P(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) { stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // RST_STREAM received. @@ -1037,11 +965,7 @@ TEST_P(QuicStreamTest, RstFrameReceivedStreamFinishSending) { stream_->WriteOrBufferData(kData1, true, nullptr); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); // RST_STREAM received. EXPECT_CALL(*session_, SendRstStream(_, _, _)).Times(0); @@ -1050,11 +974,7 @@ TEST_P(QuicStreamTest, RstFrameReceivedStreamFinishSending) { stream_->OnStreamReset(rst_frame); // Stream still waits for acks as it finishes sending and has unacked data. EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); } @@ -1068,11 +988,7 @@ TEST_P(QuicStreamTest, ConnectionClosed) { stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); EXPECT_CALL(*session_, SendRstStream(stream_->id(), QUIC_RST_ACKNOWLEDGEMENT, 9)); stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, @@ -1328,11 +1244,7 @@ TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) { stream_->WriteOrBufferData(kData1, true, nullptr); EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); // Ack [0, 9), [5, 22) and [18, 26) // Verify [0, 9) 9 bytes are acked. QuicByteCount newly_acked_length = 0; @@ -1351,11 +1263,7 @@ TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) { EXPECT_EQ(4u, newly_acked_length); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); // Ack [0, 27). Verify [26, 27) 1 byte is acked. EXPECT_TRUE(stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero(), @@ -1363,11 +1271,7 @@ TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) { EXPECT_EQ(1u, newly_acked_length); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Session decides what to write and puts stream into set of unacked streams - // only after v39. - if (GetParam().transport_version > QUIC_VERSION_39) { - EXPECT_TRUE(session_->HasUnackedStreamData()); - } + EXPECT_TRUE(session_->HasUnackedStreamData()); // Ack Fin. EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(), @@ -1410,6 +1314,7 @@ TEST_P(QuicStreamTest, OnStreamFrameLost) { EXPECT_TRUE(stream_->HasPendingRetransmission()); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); + EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); EXPECT_FALSE(stream_->HasPendingRetransmission()); EXPECT_TRUE(stream_->HasBufferedData()); @@ -1581,10 +1486,6 @@ TEST_P(QuicStreamTest, RetransmitStreamData) { } TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresRetransmitLostData) { - // Version 39 and below doesn't support stream ttl. - if (GetParam().transport_version <= QUIC_VERSION_39) { - return; - } Initialize(); EXPECT_CALL(*session_, WritevData(_, stream_->id(), 200, 0, FIN)) @@ -1609,10 +1510,6 @@ TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresRetransmitLostData) { } TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresEarlyRetransmitData) { - // Version 39 and below doesn't support stream ttl. - if (GetParam().transport_version <= QUIC_VERSION_39) { - return; - } Initialize(); EXPECT_CALL(*session_, WritevData(_, stream_->id(), 200, 0, FIN)) @@ -1675,50 +1572,6 @@ TEST_P(QuicStreamTest, OnStreamResetReadOrReadWrite) { } } -// Test that receiving a STOP_SENDING just closes the write side of the stream. -// If not V99, the test is a noop (no STOP_SENDING in Google QUIC). -TEST_P(QuicStreamTest, OnStopSendingReadOrReadWrite) { - Initialize(); - if (!VersionHasIetfQuicFrames(connection_->transport_version())) { - return; - } - - EXPECT_FALSE(stream_->write_side_closed()); - EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); - - // Simulate receipt of a STOP_SENDING. - stream_->OnStopSending(123); - - // Should close just the read side. - EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); - // TODO(b/142425843): Currently no action is taken upon receiving stop - // sending. Need to figure out what to do and turn on this expectation. - // EXPECT_TRUE(stream_->write_side_closed()); -} - -// SendOnlyRstStream must only send a RESET_STREAM (no bundled STOP_SENDING). -TEST_P(QuicStreamTest, SendOnlyRstStream) { - Initialize(); - if (!VersionHasIetfQuicFrames(connection_->transport_version())) { - return; - } - - EXPECT_CALL(*connection_, - OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD)); - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(1) - .WillOnce(Invoke(this, &QuicStreamTest::ClearResetStreamFrame)); - - QuicSessionPeer::SendRstStreamInner(session_.get(), stream_->id(), - QUIC_BAD_APPLICATION_PAYLOAD, - stream_->stream_bytes_written(), - /*close_write_side_only=*/true); - - // ResetStreamOnly should just close the write side. - EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); - EXPECT_TRUE(stream_->write_side_closed()); -} - TEST_P(QuicStreamTest, WindowUpdateForReadOnlyStream) { Initialize(); @@ -1735,6 +1588,20 @@ TEST_P(QuicStreamTest, WindowUpdateForReadOnlyStream) { stream.OnWindowUpdateFrame(window_update_frame); } +TEST_P(QuicStreamTest, RstStreamFrameChangesCloseOffset) { + SetQuicReloadableFlag(quic_close_connection_on_wrong_offset, true); + Initialize(); + + QuicStreamFrame stream_frame(stream_->id(), true, 0, "abc"); + EXPECT_CALL(*stream_, OnDataAvailable()); + stream_->OnStreamFrame(stream_frame); + QuicRstStreamFrame rst(kInvalidControlFrameId, stream_->id(), + QUIC_STREAM_CANCELLED, 0u); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_MULTIPLE_OFFSET, _, _)); + stream_->OnStreamReset(rst); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.h b/chromium/net/third_party/quiche/src/quic/core/quic_time.h index 9a5ae7dd5b2..d4429e34ceb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.h @@ -210,6 +210,9 @@ inline bool operator<=(QuicTime::Delta lhs, QuicTime::Delta rhs) { inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) { return !(lhs < rhs); } +inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs) { + return QuicTime::Delta(lhs.time_offset_ << rhs); +} inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs) { return QuicTime::Delta(lhs.time_offset_ >> rhs); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator.h new file mode 100644 index 00000000000..6535d74c45b --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator.h @@ -0,0 +1,69 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QUIC_TIME_ACCUMULATOR_H_ +#define QUICHE_QUIC_CORE_QUIC_TIME_ACCUMULATOR_H_ + +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +// QuicTimeAccumulator accumulates elapsed times between Start(s) and Stop(s). +class QUIC_EXPORT_PRIVATE QuicTimeAccumulator { + // TODO(wub): Switch to a data member called kNotRunningSentinel after c++17. + static constexpr QuicTime NotRunningSentinel() { + return QuicTime::Infinite(); + } + + public: + // True if Started and not Stopped. + bool IsRunning() const { return last_start_time_ != NotRunningSentinel(); } + + void Start(QuicTime now) { + DCHECK(!IsRunning()); + last_start_time_ = now; + DCHECK(IsRunning()); + } + + void Stop(QuicTime now) { + DCHECK(IsRunning()); + if (now > last_start_time_) { + total_elapsed_ = total_elapsed_ + (now - last_start_time_); + } + last_start_time_ = NotRunningSentinel(); + DCHECK(!IsRunning()); + } + + // Get total elapsed time between COMPLETED Start/Stop pairs. + QuicTime::Delta GetTotalElapsedTime() const { return total_elapsed_; } + + // Get total elapsed time between COMPLETED Start/Stop pairs, plus, if it is + // running, the elapsed time between |last_start_time_| and |now|. + QuicTime::Delta GetTotalElapsedTime(QuicTime now) const { + if (!IsRunning()) { + return total_elapsed_; + } + if (now <= last_start_time_) { + return total_elapsed_; + } + return total_elapsed_ + (now - last_start_time_); + } + + private: + // + // |last_start_time_| + // | + // V + // Start => Stop => Start => Stop => Start + // | | | | + // |___________| + |___________| = |total_elapsed_| + QuicTime::Delta total_elapsed_ = QuicTime::Delta::Zero(); + QuicTime last_start_time_ = NotRunningSentinel(); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_TIME_ACCUMULATOR_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator_test.cc new file mode 100644 index 00000000000..e7bc43a0459 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_accumulator_test.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_time_accumulator.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" + +namespace quic { +namespace test { + +TEST(QuicTimeAccumulator, DefaultConstruct) { + MockClock clock; + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + + QuicTimeAccumulator acc; + EXPECT_FALSE(acc.IsRunning()); + + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + EXPECT_EQ(QuicTime::Delta::Zero(), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::Zero(), acc.GetTotalElapsedTime(clock.Now())); +} + +TEST(QuicTimeAccumulator, StartStop) { + MockClock clock; + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + + QuicTimeAccumulator acc; + acc.Start(clock.Now()); + EXPECT_TRUE(acc.IsRunning()); + + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + acc.Stop(clock.Now()); + EXPECT_FALSE(acc.IsRunning()); + + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), + acc.GetTotalElapsedTime(clock.Now())); + + acc.Start(clock.Now()); + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(15), + acc.GetTotalElapsedTime(clock.Now())); + + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), + acc.GetTotalElapsedTime(clock.Now())); + + acc.Stop(clock.Now()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), + acc.GetTotalElapsedTime(clock.Now())); +} + +TEST(QuicTimeAccumulator, ClockStepBackwards) { + MockClock clock; + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + + QuicTimeAccumulator acc; + acc.Start(clock.Now()); + + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(-10)); + acc.Stop(clock.Now()); + EXPECT_EQ(QuicTime::Delta::Zero(), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::Zero(), acc.GetTotalElapsedTime(clock.Now())); + + acc.Start(clock.Now()); + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(50)); + acc.Stop(clock.Now()); + + acc.Start(clock.Now()); + clock.AdvanceTime(QuicTime::Delta::FromMilliseconds(-80)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50), acc.GetTotalElapsedTime()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50), + acc.GetTotalElapsedTime(clock.Now())); +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h index e2a45946b97..5c7553565b4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h @@ -35,7 +35,8 @@ class QuicTimeWaitListManagerPeer; // wait state. After the connection_id expires its time wait period, a new // connection/session will be created if a packet is received for this // connection_id. -class QuicTimeWaitListManager : public QuicBlockedWriterInterface { +class QUIC_NO_EXPORT QuicTimeWaitListManager + : public QuicBlockedWriterInterface { public: // Specifies what the time wait list manager should do when processing packets // of a time wait connection. @@ -49,7 +50,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { DO_NOTHING, }; - class Visitor : public QuicSession::Visitor { + class QUIC_NO_EXPORT Visitor : public QuicSession::Visitor { public: // Called after the given connection is added to the time-wait list. virtual void OnConnectionAddedToTimeWaitList( @@ -159,7 +160,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { QuicConnectionId connection_id) const; // Internal structure to store pending termination packets. - class QueuedPacket { + class QUIC_NO_EXPORT QueuedPacket { public: QueuedPacket(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, @@ -229,7 +230,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { // A map from a recently closed connection_id to the number of packets // received after the termination of the connection bound to the // connection_id. - struct ConnectionIdData { + struct QUIC_NO_EXPORT ConnectionIdData { ConnectionIdData(int num_packets, bool ietf_quic, QuicTime time_added, 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 42ee003966d..50974853345 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 @@ -6,7 +6,7 @@ #include -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -44,7 +44,6 @@ QuicTraceVisitor::QuicTraceVisitor(const QuicConnection* connection) } void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet, - QuicPacketNumber /*original_packet_number*/, TransmissionType /*transmission_type*/, QuicTime sent_time) { quic_trace::Event* event = trace_.add_events(); @@ -172,7 +171,7 @@ void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame, quic_trace::FlowControlInfo* info = frame_record->mutable_flow_control_info(); - info->set_max_data(frame.window_update_frame->byte_offset); + info->set_max_data(frame.window_update_frame->max_data); if (!is_connection) { info->set_stream_id(frame.window_update_frame->stream_id); } @@ -266,7 +265,8 @@ void QuicTraceVisitor::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame, void QuicTraceVisitor::OnSuccessfulVersionNegotiation( const ParsedQuicVersion& version) { - uint32_t tag = QuicEndian::HostToNet32(CreateQuicVersionLabel(version)); + uint32_t tag = + quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)); std::string binary_tag(reinterpret_cast(&tag), sizeof(tag)); trace_.set_protocol_version(binary_tag); } 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 0494d874331..86d7198ebe7 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 @@ -14,12 +14,11 @@ namespace quic { // Records a QUIC trace protocol buffer for a QuicConnection. It's the // responsibility of the user of this visitor to process or store the resulting // trace, which can be accessed via trace(). -class QuicTraceVisitor : public QuicConnectionDebugVisitor { +class QUIC_NO_EXPORT QuicTraceVisitor : public QuicConnectionDebugVisitor { public: explicit QuicTraceVisitor(const QuicConnection* connection); void OnPacketSent(const SerializedPacket& serialized_packet, - QuicPacketNumber original_packet_number, TransmissionType transmission_type, QuicTime sent_time) override; 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 fb5cf670063..163ba384f32 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 @@ -8,7 +8,6 @@ namespace quic { QuicTransmissionInfo::QuicTransmissionInfo() : encryption_level(ENCRYPTION_INITIAL), - packet_number_length(PACKET_1BYTE_PACKET_NUMBER), bytes_sent(0), sent_time(QuicTime::Zero()), transmission_type(NOT_RETRANSMISSION), @@ -19,14 +18,12 @@ QuicTransmissionInfo::QuicTransmissionInfo() QuicTransmissionInfo::QuicTransmissionInfo( EncryptionLevel level, - QuicPacketNumberLength packet_number_length, TransmissionType transmission_type, QuicTime sent_time, QuicPacketLength bytes_sent, bool has_crypto_handshake, int num_padding_bytes) : encryption_level(level), - packet_number_length(packet_number_length), bytes_sent(bytes_sent), sent_time(sent_time), transmission_type(transmission_type), 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 7c4881a290a..a4fa762d359 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 @@ -22,7 +22,6 @@ struct QUIC_EXPORT_PRIVATE QuicTransmissionInfo { // Constructs a Transmission with a new all_transmissions set // containing |packet_number|. QuicTransmissionInfo(EncryptionLevel level, - QuicPacketNumberLength packet_number_length, TransmissionType transmission_type, QuicTime sent_time, QuicPacketLength bytes_sent, @@ -35,8 +34,6 @@ struct QUIC_EXPORT_PRIVATE QuicTransmissionInfo { QuicFrames retransmittable_frames; EncryptionLevel encryption_level; - // TODO(fayang): remove this when deprecating QUIC_VERSION_39. - QuicPacketNumberLength packet_number_length; QuicPacketLength bytes_sent; QuicTime sent_time; // Reason why this packet was transmitted. 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 db48c5c2391..ca12e76725b 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 @@ -6,13 +6,11 @@ #include +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" namespace quic { -QuicConsumedData::QuicConsumedData(size_t bytes_consumed, bool fin_consumed) - : bytes_consumed(bytes_consumed), fin_consumed(fin_consumed) {} - std::ostream& operator<<(std::ostream& os, const QuicConsumedData& s) { os << "bytes_consumed: " << s.bytes_consumed << " fin_consumed: " << s.fin_consumed; @@ -53,6 +51,8 @@ std::string HistogramEnumString(WriteStatus enum_value) { return "ERROR"; case WRITE_STATUS_MSG_TOO_BIG: return "MSG_TOO_BIG"; + case WRITE_STATUS_FAILED_TO_COALESCE_PACKET: + return "WRITE_STATUS_FAILED_TO_COALESCE_PACKET"; case WRITE_STATUS_NUM_VALUES: return "NUM_VALUES"; } @@ -60,11 +60,6 @@ std::string HistogramEnumString(WriteStatus enum_value) { return ""; } -WriteResult::WriteResult() : status(WRITE_STATUS_ERROR), bytes_written(0) {} - -WriteResult::WriteResult(WriteStatus status, int bytes_written_or_error_code) - : status(status), bytes_written(bytes_written_or_error_code) {} - std::ostream& operator<<(std::ostream& os, const WriteResult& s) { os << "{ status: " << s.status; if (s.status == WRITE_STATUS_OK) { @@ -413,6 +408,23 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( {static_cast(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES)}}; case QUIC_TRANSPORT_INVALID_CLIENT_INDICATION: return {false, {0u}}; + case QUIC_QPACK_DECOMPRESSION_FAILED: + return { + false, + {static_cast(IETF_QUIC_HTTP_QPACK_DECOMPRESSION_FAILED)}}; + case QUIC_QPACK_ENCODER_STREAM_ERROR: + return { + false, + {static_cast(IETF_QUIC_HTTP_QPACK_ENCODER_STREAM_ERROR)}}; + case QUIC_QPACK_DECODER_STREAM_ERROR: + return { + false, + {static_cast(IETF_QUIC_HTTP_QPACK_DECODER_STREAM_ERROR)}}; + case QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET: + return {true, + {static_cast(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET)}}; + case QUIC_STREAM_MULTIPLE_OFFSET: + return {true, {static_cast(QUIC_STREAM_MULTIPLE_OFFSET)}}; case QUIC_LAST_ERROR: return {false, {static_cast(QUIC_LAST_ERROR)}}; } @@ -450,6 +462,8 @@ std::string QuicIetfFrameTypeString(QuicIetfFrameType t) { RETURN_STRING_LITERAL(IETF_APPLICATION_CLOSE); RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE_NO_LENGTH); RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE); + RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE_NO_LENGTH_V99); + RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE_V99); default: return QuicStrCat("Private value (", t, ")"); } @@ -468,6 +482,7 @@ std::string TransmissionTypeToString(TransmissionType transmission_type) { RETURN_STRING_LITERAL(LOSS_RETRANSMISSION); RETURN_STRING_LITERAL(RTO_RETRANSMISSION); RETURN_STRING_LITERAL(TLP_RETRANSMISSION); + RETURN_STRING_LITERAL(PTO_RETRANSMISSION); RETURN_STRING_LITERAL(PROBING_RETRANSMISSION); default: // Some varz rely on this behavior for statistic collection. @@ -502,6 +517,33 @@ std::string QuicLongHeaderTypeToString(QuicLongHeaderType type) { } } +std::string MessageStatusToString(MessageStatus message_status) { + switch (message_status) { + RETURN_STRING_LITERAL(MESSAGE_STATUS_SUCCESS); + RETURN_STRING_LITERAL(MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED); + RETURN_STRING_LITERAL(MESSAGE_STATUS_UNSUPPORTED); + RETURN_STRING_LITERAL(MESSAGE_STATUS_BLOCKED); + RETURN_STRING_LITERAL(MESSAGE_STATUS_TOO_LARGE); + RETURN_STRING_LITERAL(MESSAGE_STATUS_INTERNAL_ERROR); + default: + return QuicStrCat("Unknown(", static_cast(message_status), ")"); + break; + } +} + +std::string MessageResultToString(MessageResult message_result) { + if (message_result.status != MESSAGE_STATUS_SUCCESS) { + return QuicStrCat("{", MessageStatusToString(message_result.status), "}"); + } + return QuicStrCat("{MESSAGE_STATUS_SUCCESS,id=", message_result.message_id, + "}"); +} + +std::ostream& operator<<(std::ostream& os, const MessageResult& mr) { + os << MessageResultToString(mr); + return os; +} + std::string PacketNumberSpaceToString(PacketNumberSpace packet_number_space) { switch (packet_number_space) { RETURN_STRING_LITERAL(INITIAL_DATA); @@ -513,6 +555,17 @@ std::string PacketNumberSpaceToString(PacketNumberSpace packet_number_space) { } } +std::string SerializedPacketFateToString(SerializedPacketFate fate) { + switch (fate) { + RETURN_STRING_LITERAL(COALESCE); + RETURN_STRING_LITERAL(BUFFER); + RETURN_STRING_LITERAL(SEND_TO_WRITER); + RETURN_STRING_LITERAL(FAILED_TO_WRITE_COALESCED_PACKET); + default: + return QuicStrCat("Unknown(", static_cast(fate), ")"); + } +} + std::string EncryptionLevelToString(EncryptionLevel level) { switch (level) { RETURN_STRING_LITERAL(ENCRYPTION_INITIAL); 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 afd42be3f46..23cbe7a4eb4 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 @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_packet_number.h" #include "net/third_party/quiche/src/quic/core/quic_time.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" namespace quic { @@ -23,6 +24,7 @@ typedef uint16_t QuicPacketLength; typedef uint32_t QuicControlFrameId; typedef uint32_t QuicHeaderId; typedef uint32_t QuicMessageId; +typedef uint64_t QuicDatagramFlowId; // TODO(fkastenholz): Should update this to 64 bits for V99. typedef uint32_t QuicStreamId; @@ -55,7 +57,8 @@ typedef uint64_t QuicConnectionIdSequenceNumber; // A struct for functions which consume data payloads and fins. struct QUIC_EXPORT_PRIVATE QuicConsumedData { - QuicConsumedData(size_t bytes_consumed, bool fin_consumed); + constexpr QuicConsumedData(size_t bytes_consumed, bool fin_consumed) + : bytes_consumed(bytes_consumed), fin_consumed(fin_consumed) {} // By default, gtest prints the raw bytes of an object. The bool data // member causes this object to have padding bytes, which causes the @@ -94,6 +97,7 @@ enum WriteStatus { // - Errors MUST be added after WRITE_STATUS_ERROR. WRITE_STATUS_ERROR, WRITE_STATUS_MSG_TOO_BIG, + WRITE_STATUS_FAILED_TO_COALESCE_PACKET, WRITE_STATUS_NUM_VALUES, }; @@ -115,8 +119,10 @@ inline bool IsWriteError(WriteStatus status) { // A struct used to return the result of write calls including either the number // of bytes written or the error code, depending upon the status. struct QUIC_EXPORT_PRIVATE WriteResult { - WriteResult(WriteStatus status, int bytes_written_or_error_code); - WriteResult(); + constexpr WriteResult(WriteStatus status, int bytes_written_or_error_code) + : status(status), bytes_written(bytes_written_or_error_code) {} + + constexpr WriteResult() : WriteResult(WRITE_STATUS_ERROR, 0) {} bool operator==(const WriteResult& other) const { if (status != other.status) { @@ -153,6 +159,7 @@ enum TransmissionType : int8_t { LOSS_RETRANSMISSION, // Retransmits due to loss detection. RTO_RETRANSMISSION, // Retransmits due to retransmit time out. TLP_RETRANSMISSION, // Tail loss probes. + PTO_RETRANSMISSION, // Retransmission due to probe timeout. PROBING_RETRANSMISSION, // Retransmission in order to probe bandwidth. LAST_TRANSMISSION_TYPE = PROBING_RETRANSMISSION, }; @@ -265,10 +272,13 @@ enum QuicIetfFrameType : uint8_t { IETF_CONNECTION_CLOSE = 0x1c, IETF_APPLICATION_CLOSE = 0x1d, - // MESSAGE frame type is not yet determined, use 0x2x temporarily to give - // stream frame some wiggle room. + // The MESSAGE frame type has not yet been fully standardized. + // QUIC versions starting with 46 and before 99 use 0x20-0x21. + // IETF QUIC (v99) uses 0x30-0x31, see draft-pauly-quic-datagram. IETF_EXTENSION_MESSAGE_NO_LENGTH = 0x20, IETF_EXTENSION_MESSAGE = 0x21, + IETF_EXTENSION_MESSAGE_NO_LENGTH_V99 = 0x30, + IETF_EXTENSION_MESSAGE_V99 = 0x31, }; QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const QuicIetfFrameType& c); @@ -308,7 +318,8 @@ enum QuicPacketNumberLength : uint8_t { PACKET_3BYTE_PACKET_NUMBER = 3, // Used in versions 45+. PACKET_4BYTE_PACKET_NUMBER = 4, IETF_MAX_PACKET_NUMBER_LENGTH = 4, - // TODO(rch): Remove this when we remove QUIC_VERSION_39. + // TODO(rch): Remove these when we remove QUIC_VERSION_43 since these values + // are not representable with v46 and above. PACKET_6BYTE_PACKET_NUMBER = 6, PACKET_8BYTE_PACKET_NUMBER = 8 }; @@ -440,7 +451,7 @@ enum StreamSendingState { }; enum SentPacketState : uint8_t { - // The packet has been sent and waiting to be acked. + // The packet is in flight and waiting to be acked. OUTSTANDING, FIRST_PACKET_STATE = OUTSTANDING, // The packet was never sent. @@ -449,6 +460,8 @@ enum SentPacketState : uint8_t { ACKED, // This packet is not expected to be acked. UNACKABLE, + // This packet has been delivered or unneeded. + NEUTERED, // States below are corresponding to retransmission types in TransmissionType. @@ -461,6 +474,8 @@ enum SentPacketState : uint8_t { TLP_RETRANSMITTED, // This packet has been retransmitted when RTO fires. RTO_RETRANSMITTED, + // This packet has been retransmitted when PTO fires. + PTO_RETRANSMITTED, // This packet has been retransmitted for probing purpose. PROBE_RETRANSMITTED, LAST_PACKET_STATE = PROBE_RETRANSMITTED, @@ -476,10 +491,10 @@ QUIC_EXPORT_PRIVATE std::string PacketHeaderFormatToString( PacketHeaderFormat format); // Information about a newly acknowledged packet. -struct AckedPacket { - AckedPacket(QuicPacketNumber packet_number, - QuicPacketLength bytes_acked, - QuicTime receive_timestamp) +struct QUIC_EXPORT_PRIVATE AckedPacket { + constexpr AckedPacket(QuicPacketNumber packet_number, + QuicPacketLength bytes_acked, + QuicTime receive_timestamp) : packet_number(packet_number), bytes_acked(bytes_acked), receive_timestamp(receive_timestamp) {} @@ -498,10 +513,10 @@ struct AckedPacket { }; // A vector of acked packets. -typedef std::vector AckedPacketVector; +typedef QuicInlinedVector AckedPacketVector; // Information about a newly lost packet. -struct LostPacket { +struct QUIC_EXPORT_PRIVATE LostPacket { LostPacket(QuicPacketNumber packet_number, QuicPacketLength bytes_lost) : packet_number(packet_number), bytes_lost(bytes_lost) {} @@ -515,7 +530,7 @@ struct LostPacket { }; // A vector of lost packets. -typedef std::vector LostPacketVector; +typedef QuicInlinedVector LostPacketVector; enum QuicIetfTransportErrorCodes : uint64_t { NO_IETF_QUIC_ERROR = 0x0, @@ -542,7 +557,7 @@ QUIC_EXPORT_PRIVATE std::ostream& operator<<( // first element of the pair is false, it means that an IETF Application Close // should be done instead. -struct QuicErrorCodeToIetfMapping { +struct QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping { bool is_transport_close_; union { uint64_t application_error_code_; @@ -599,6 +614,9 @@ enum MessageStatus { // reaches an invalid state. }; +QUIC_EXPORT_PRIVATE std::string MessageStatusToString( + MessageStatus message_status); + // Used to return the result of SendMessage calls struct QUIC_EXPORT_PRIVATE MessageResult { MessageResult(MessageStatus status, QuicMessageId message_id); @@ -607,11 +625,17 @@ struct QUIC_EXPORT_PRIVATE MessageResult { return status == other.status && message_id == other.message_id; } + QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os, + const MessageResult& mr); + MessageStatus status; // Only valid when status is MESSAGE_STATUS_SUCCESS. QuicMessageId message_id; }; +QUIC_EXPORT_PRIVATE std::string MessageResultToString( + MessageResult message_result); + enum WriteStreamDataResult { WRITE_SUCCESS, STREAM_MISSING, // Trying to write data of a nonexistent stream (e.g. @@ -660,6 +684,18 @@ enum AckResult { PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE, }; +// Indicates the fate of a serialized packet in WritePacket(). +enum SerializedPacketFate : uint8_t { + COALESCE, // Try to coalesce packet. + BUFFER, // Buffer packet in buffered_packets_. + SEND_TO_WRITER, // Send packet to writer. + FAILED_TO_WRITE_COALESCED_PACKET, // Packet cannot be coalesced, error occurs + // when sending existing coalesced packet. +}; + +QUIC_EXPORT_PRIVATE std::string SerializedPacketFateToString( + SerializedPacketFate fate); + // There are three different forms of CONNECTION_CLOSE. typedef enum QuicConnectionCloseType { GOOGLE_QUIC_CONNECTION_CLOSE = 0, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc index 8b4df895224..c7e4316a218 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc @@ -13,9 +13,9 @@ namespace quic { namespace test { namespace { -class QuicUtilsTest : public QuicTest {}; +class QuicTypesTest : public QuicTest {}; -TEST_F(QuicUtilsTest, QuicIetfTransportErrorCodeString) { +TEST_F(QuicTypesTest, QuicIetfTransportErrorCodeString) { // QuicIetfTransportErrorCode out of bound. for (quic::QuicErrorCode error = quic::QUIC_ENCRYPTION_FAILURE; error < quic::QUIC_LAST_ERROR; @@ -27,10 +27,6 @@ TEST_F(QuicUtilsTest, QuicIetfTransportErrorCodeString) { QuicIetfTransportErrorCodeString(mapping.transport_error_code_), QuicStrCat("Unknown Transport Error Code Value: ", static_cast(mapping.transport_error_code_))); - } else { - // Some QuicErrorCodes are no longer valid. - EXPECT_EQ(QuicIetfTransportErrorCodeString(mapping.transport_error_code_), - "NO_IETF_QUIC_ERROR"); } } } 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 cc9c13f7a4c..d8beb435967 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 @@ -28,17 +28,11 @@ QuicUnackedPacketMap::QuicUnackedPacketMap(Perspective perspective) : perspective_(perspective), least_unacked_(FirstSendingPacketNumber()), bytes_in_flight_(0), - pending_crypto_packet_count_(0), + packets_in_flight_(0), last_inflight_packet_sent_time_(QuicTime::Zero()), last_crypto_packet_sent_time_(QuicTime::Zero()), session_notifier_(nullptr), - session_decides_what_to_write_(false), - supports_multiple_packet_number_spaces_(false), - simple_inflight_time_(GetQuicReloadableFlag(quic_simple_inflight_time)) { - if (simple_inflight_time_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_simple_inflight_time); - } -} + supports_multiple_packet_number_spaces_(false) {} QuicUnackedPacketMap::~QuicUnackedPacketMap() { for (QuicTransmissionInfo& transmission_info : unacked_packets_) { @@ -47,7 +41,6 @@ QuicUnackedPacketMap::~QuicUnackedPacketMap() { } void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, - QuicPacketNumber old_packet_number, TransmissionType transmission_type, QuicTime sent_time, bool set_in_flight) { @@ -65,15 +58,11 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, const bool has_crypto_handshake = packet->has_crypto_handshake == IS_HANDSHAKE; - QuicTransmissionInfo info( - packet->encryption_level, packet->packet_number_length, transmission_type, - sent_time, bytes_sent, has_crypto_handshake, packet->num_padding_bytes); + QuicTransmissionInfo info(packet->encryption_level, transmission_type, + sent_time, bytes_sent, has_crypto_handshake, + packet->num_padding_bytes); info.largest_acked = packet->largest_acked; largest_sent_largest_acked_.UpdateMax(packet->largest_acked); - if (old_packet_number.IsInitialized()) { - TransferRetransmissionInfo(old_packet_number, packet_number, - transmission_type, &info); - } largest_sent_packet_ = packet_number; if (supports_multiple_packet_number_spaces_) { @@ -82,6 +71,7 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, } if (set_in_flight) { bytes_in_flight_ += bytes_sent; + ++packets_in_flight_; info.in_flight = true; largest_sent_retransmittable_packets_[GetPacketNumberSpace( info.encryption_level)] = packet_number; @@ -92,15 +82,12 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, unacked_packets_.push_back(info); // Swap the retransmittable frames to avoid allocations. // TODO(ianswett): Could use emplace_back when Chromium can. - if (!old_packet_number.IsInitialized()) { - if (has_crypto_handshake) { - ++pending_crypto_packet_count_; - last_crypto_packet_sent_time_ = sent_time; - } - - packet->retransmittable_frames.swap( - unacked_packets_.back().retransmittable_frames); + if (has_crypto_handshake) { + last_crypto_packet_sent_time_ = sent_time; } + + packet->retransmittable_frames.swap( + unacked_packets_.back().retransmittable_frames); } void QuicUnackedPacketMap::RemoveObsoletePackets() { @@ -108,62 +95,12 @@ void QuicUnackedPacketMap::RemoveObsoletePackets() { if (!IsPacketUseless(least_unacked_, unacked_packets_.front())) { break; } - if (session_decides_what_to_write_) { - DeleteFrames(&unacked_packets_.front().retransmittable_frames); - } + DeleteFrames(&unacked_packets_.front().retransmittable_frames); unacked_packets_.pop_front(); ++least_unacked_; } } -void QuicUnackedPacketMap::TransferRetransmissionInfo( - QuicPacketNumber old_packet_number, - QuicPacketNumber new_packet_number, - TransmissionType transmission_type, - QuicTransmissionInfo* info) { - if (old_packet_number < least_unacked_) { - // This can happen when a retransmission packet is queued because of write - // blocked socket, and the original packet gets acked before the - // retransmission gets sent. - return; - } - if (old_packet_number > largest_sent_packet_) { - QUIC_BUG << "Old QuicTransmissionInfo never existed for :" - << old_packet_number << " largest_sent:" << largest_sent_packet_; - return; - } - DCHECK_GE(new_packet_number, least_unacked_ + unacked_packets_.size()); - DCHECK_NE(NOT_RETRANSMISSION, transmission_type); - - QuicTransmissionInfo* transmission_info = - &unacked_packets_.at(old_packet_number - least_unacked_); - QuicFrames* frames = &transmission_info->retransmittable_frames; - if (session_notifier_ != nullptr) { - for (const QuicFrame& frame : *frames) { - if (frame.type == STREAM_FRAME) { - session_notifier_->OnStreamFrameRetransmitted(frame.stream_frame); - } - } - } - - // Swap the frames and preserve num_padding_bytes and has_crypto_handshake. - frames->swap(info->retransmittable_frames); - info->has_crypto_handshake = transmission_info->has_crypto_handshake; - transmission_info->has_crypto_handshake = false; - info->num_padding_bytes = transmission_info->num_padding_bytes; - - // Don't link old transmissions to new ones when version or - // encryption changes. - if (transmission_type == ALL_INITIAL_RETRANSMISSION || - transmission_type == ALL_UNACKED_RETRANSMISSION) { - transmission_info->state = UNACKABLE; - } else { - transmission_info->retransmission = new_packet_number; - } - // Proactively remove obsolete packets so the least unacked can be raised. - RemoveObsoletePackets(); -} - bool QuicUnackedPacketMap::HasRetransmittableFrames( QuicPacketNumber packet_number) const { DCHECK_GE(packet_number, least_unacked_); @@ -174,10 +111,6 @@ bool QuicUnackedPacketMap::HasRetransmittableFrames( bool QuicUnackedPacketMap::HasRetransmittableFrames( const QuicTransmissionInfo& info) const { - if (!session_decides_what_to_write_) { - return !info.retransmittable_frames.empty(); - } - if (!QuicUtils::IsAckable(info.state)) { return false; } @@ -192,24 +125,8 @@ bool QuicUnackedPacketMap::HasRetransmittableFrames( void QuicUnackedPacketMap::RemoveRetransmittability( QuicTransmissionInfo* info) { - if (session_decides_what_to_write_) { - DeleteFrames(&info->retransmittable_frames); - info->retransmission.Clear(); - return; - } - while (info->retransmission.IsInitialized()) { - const QuicPacketNumber retransmission = info->retransmission; - info->retransmission.Clear(); - info = &unacked_packets_[retransmission - least_unacked_]; - } - - if (info->has_crypto_handshake) { - DCHECK(HasRetransmittableFrames(*info)); - DCHECK_LT(0u, pending_crypto_packet_count_); - --pending_crypto_packet_count_; - info->has_crypto_handshake = false; - } DeleteFrames(&info->retransmittable_frames); + info->retransmission.Clear(); } void QuicUnackedPacketMap::RemoveRetransmittability( @@ -250,16 +167,6 @@ bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl( bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData( const QuicTransmissionInfo& info) const { - if (!session_decides_what_to_write_) { - // Packet may have retransmittable frames, or the data may have been - // retransmitted with a new packet number. - // Allow for an extra 1 RTT before stopping to track old packets. - return (info.retransmission.IsInitialized() && - (!largest_acked_.IsInitialized() || - info.retransmission > largest_acked_)) || - HasRetransmittableFrames(info); - } - // Wait for 1 RTT before giving up on the lost packet. return info.retransmission.IsInitialized() && (!largest_acked_.IsInitialized() || @@ -286,7 +193,9 @@ bool QuicUnackedPacketMap::IsUnacked(QuicPacketNumber packet_number) const { void QuicUnackedPacketMap::RemoveFromInFlight(QuicTransmissionInfo* info) { if (info->in_flight) { QUIC_BUG_IF(bytes_in_flight_ < info->bytes_sent); + QUIC_BUG_IF(packets_in_flight_ == 0); bytes_in_flight_ -= info->bytes_sent; + --packets_in_flight_; info->in_flight = false; } } @@ -299,23 +208,6 @@ void QuicUnackedPacketMap::RemoveFromInFlight(QuicPacketNumber packet_number) { RemoveFromInFlight(info); } -void QuicUnackedPacketMap::CancelRetransmissionsForStream( - QuicStreamId stream_id) { - DCHECK(!session_decides_what_to_write_); - QuicPacketNumber packet_number = least_unacked_; - for (auto it = unacked_packets_.begin(); it != unacked_packets_.end(); - ++it, ++packet_number) { - QuicFrames* frames = &it->retransmittable_frames; - if (frames->empty()) { - continue; - } - RemoveFramesForStream(frames, stream_id); - if (frames->empty()) { - RemoveRetransmittability(packet_number); - } - } -} - bool QuicUnackedPacketMap::HasInFlightPackets() const { return bytes_in_flight_ > 0; } @@ -331,20 +223,7 @@ QuicTransmissionInfo* QuicUnackedPacketMap::GetMutableTransmissionInfo( } QuicTime QuicUnackedPacketMap::GetLastInFlightPacketSentTime() const { - if (simple_inflight_time_) { - return last_inflight_packet_sent_time_; - } - auto it = unacked_packets_.rbegin(); - while (it != unacked_packets_.rend()) { - if (it->in_flight) { - QUIC_BUG_IF(it->sent_time == QuicTime::Zero()) - << "Sent time can never be zero for a packet in flight."; - return it->sent_time; - } - ++it; - } - QUIC_BUG << "GetLastPacketSentTime requires in flight packets."; - return QuicTime::Zero(); + return last_inflight_packet_sent_time_; } QuicTime QuicUnackedPacketMap::GetLastCryptoPacketSentTime() const { @@ -381,9 +260,6 @@ bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const { } bool QuicUnackedPacketMap::HasPendingCryptoPackets() const { - if (!session_decides_what_to_write_) { - return pending_crypto_packet_count_ > 0; - } return session_notifier_->HasUnackedCryptoData(); } @@ -423,7 +299,6 @@ bool QuicUnackedPacketMap::NotifyFramesAcked(const QuicTransmissionInfo& info, void QuicUnackedPacketMap::NotifyFramesLost(const QuicTransmissionInfo& info, TransmissionType /*type*/) { - DCHECK(session_decides_what_to_write_); for (const QuicFrame& frame : info.retransmittable_frames) { session_notifier_->OnFrameLost(frame); } @@ -431,7 +306,6 @@ void QuicUnackedPacketMap::NotifyFramesLost(const QuicTransmissionInfo& info, void QuicUnackedPacketMap::RetransmitFrames(const QuicTransmissionInfo& info, TransmissionType type) { - DCHECK(session_decides_what_to_write_); session_notifier_->RetransmitFrames(info.retransmittable_frames, type); } @@ -537,15 +411,6 @@ QuicUnackedPacketMap::GetLargestSentRetransmittableOfPacketNumberSpace( return largest_sent_retransmittable_packets_[packet_number_space]; } -void QuicUnackedPacketMap::SetSessionDecideWhatToWrite( - bool session_decides_what_to_write) { - if (largest_sent_packet_.IsInitialized()) { - QUIC_BUG << "Cannot change session_decide_what_to_write with packets sent."; - return; - } - session_decides_what_to_write_ = session_decides_what_to_write; -} - void QuicUnackedPacketMap::EnableMultiplePacketNumberSpacesSupport() { if (supports_multiple_packet_number_spaces_) { QUIC_BUG << "Multiple packet number spaces has already been enabled"; 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 864e485fbf0..fd6510a6c77 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 @@ -34,12 +34,9 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // 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. - // |old_packet_number| is the packet number of the previous transmission, - // or 0 if there was none. // Any AckNotifierWrappers in |serialized_packet| are swapped from the // serialized packet into the QuicTransmissionInfo. void AddSentPacket(SerializedPacket* serialized_packet, - QuicPacketNumber old_packet_number, TransmissionType transmission_type, QuicTime sent_time, bool set_in_flight); @@ -68,9 +65,6 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Marks |packet_number| as no longer in flight. void RemoveFromInFlight(QuicPacketNumber packet_number); - // No longer retransmit data for |stream_id|. - void CancelRetransmissionsForStream(QuicStreamId stream_id); - // Returns true if |packet_number| has retransmittable frames. This will // return false if all frames of this packet are either non-retransmittable or // have been acked. @@ -100,6 +94,7 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Returns the sum of bytes from all packets in flight. QuicByteCount bytes_in_flight() const { return bytes_in_flight_; } + QuicPacketCount packets_in_flight() const { return packets_in_flight_; } // Returns the smallest packet number of a serialized packet which has not // been acked by the peer. If there are no unacked packets, returns 0. @@ -140,16 +135,14 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { size_t GetNumUnackedPacketsDebugOnly() const; // Returns true if there are multiple packets in flight. + // TODO(fayang): Remove this method and use packets_in_flight_ instead. bool HasMultipleInFlightPackets() const; // Returns true if there are any pending crypto packets. - // TODO(fayang): Remove this method and call session_notifier_'s - // HasUnackedCryptoData() when session_decides_what_to_write_ is default true. bool HasPendingCryptoPackets() const; // Returns true if there is any unacked non-crypto stream data. bool HasUnackedStreamData() const { - DCHECK(session_decides_what_to_write()); return session_notifier_->HasUnackedStreamData(); } @@ -210,37 +203,19 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { QuicPacketNumber GetLargestSentPacketOfPacketNumberSpace( EncryptionLevel encryption_level) const; - // Called to start/stop letting session decide what to write. - void SetSessionDecideWhatToWrite(bool session_decides_what_to_write); - void SetSessionNotifier(SessionNotifierInterface* session_notifier); void EnableMultiplePacketNumberSpacesSupport(); - bool session_decides_what_to_write() const { - return session_decides_what_to_write_; - } - Perspective perspective() const { return perspective_; } bool supports_multiple_packet_number_spaces() const { return supports_multiple_packet_number_spaces_; } - bool simple_inflight_time() const { return simple_inflight_time_; } - private: friend class test::QuicUnackedPacketMapPeer; - // Called when a packet is retransmitted with a new packet number. - // |old_packet_number| will remain unacked, but will have no - // retransmittable data associated with it. Retransmittable frames will be - // transferred to |info| and all_transmissions will be populated. - void TransferRetransmissionInfo(QuicPacketNumber old_packet_number, - QuicPacketNumber new_packet_number, - TransmissionType transmission_type, - QuicTransmissionInfo* info); - // Returns true if packet may be useful for an RTT measurement. bool IsPacketUsefulForMeasuringRtt(QuicPacketNumber packet_number, const QuicTransmissionInfo& info) const; @@ -287,8 +262,7 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { QuicPacketNumber least_unacked_; QuicByteCount bytes_in_flight_; - // Number of retransmittable crypto handshake packets. - size_t pending_crypto_packet_count_; + QuicPacketCount packets_in_flight_; // Time that the last inflight packet was sent. QuicTime last_inflight_packet_sent_time_; @@ -303,9 +277,6 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Receives notifications of frames being retransmitted or acknowledged. SessionNotifierInterface* session_notifier_; - // If true, let session decides what to write. - bool session_decides_what_to_write_; - // If true, supports multiple packet number spaces. bool supports_multiple_packet_number_spaces_; 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 ad096396468..92e61e3bb02 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 @@ -24,43 +24,12 @@ namespace { // Default packet length. const uint32_t kDefaultLength = 1000; -struct TestParams { - TestParams(Perspective perspective, bool session_decides_what_to_write) - : perspective(perspective), - session_decides_what_to_write(session_decides_what_to_write) {} - - Perspective perspective; - bool session_decides_what_to_write; -}; - -// Used by ::testing::PrintToStringParamName(). -std::string PrintToString(const TestParams& p) { - return QuicStrCat( - (p.perspective == Perspective::IS_CLIENT ? "Client" : "Server"), - "_Session", - (p.session_decides_what_to_write ? "Decides" : "DoesNotDecide"), - "WhatToWrite"); -} - -std::vector GetTestParams() { - std::vector params; - for (Perspective perspective : - {Perspective::IS_CLIENT, Perspective::IS_SERVER}) { - for (bool session_decides_what_to_write : {true, false}) { - params.push_back(TestParams(perspective, session_decides_what_to_write)); - } - } - return params; -} - -class QuicUnackedPacketMapTest : public QuicTestWithParam { +class QuicUnackedPacketMapTest : public QuicTestWithParam { protected: QuicUnackedPacketMapTest() - : unacked_packets_(GetParam().perspective), + : unacked_packets_(GetParam()), now_(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1000)) { unacked_packets_.SetSessionNotifier(¬ifier_); - unacked_packets_.SetSessionDecideWhatToWrite( - GetParam().session_decides_what_to_write); EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); EXPECT_CALL(notifier_, OnStreamFrameRetransmitted(_)) .Times(testing::AnyNumber()); @@ -167,14 +136,6 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam { TransmissionType transmission_type) { DCHECK(unacked_packets_.HasRetransmittableFrames( QuicPacketNumber(old_packet_number))); - if (!unacked_packets_.session_decides_what_to_write()) { - SerializedPacket packet( - CreateNonRetransmittablePacket(new_packet_number)); - unacked_packets_.AddSentPacket(&packet, - QuicPacketNumber(old_packet_number), - transmission_type, now_, true); - return; - } QuicTransmissionInfo* info = unacked_packets_.GetMutableTransmissionInfo( QuicPacketNumber(old_packet_number)); QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( @@ -192,8 +153,7 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam { info->retransmission = QuicPacketNumber(new_packet_number); SerializedPacket packet( CreateRetransmittablePacketForStream(new_packet_number, stream_id)); - unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(), - transmission_type, now_, true); + unacked_packets_.AddSentPacket(&packet, transmission_type, now_, true); } QuicUnackedPacketMap unacked_packets_; QuicTime now_; @@ -202,14 +162,14 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam { INSTANTIATE_TEST_SUITE_P(Tests, QuicUnackedPacketMapTest, - ::testing::ValuesIn(GetTestParams()), + ::testing::ValuesIn({Perspective::IS_CLIENT, + Perspective::IS_SERVER}), ::testing::PrintToStringParamName()); TEST_P(QuicUnackedPacketMapTest, RttOnly) { // Acks are only tracked for RTT measurement purposes. SerializedPacket packet(CreateNonRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, false); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, false); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -225,8 +185,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, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -252,8 +211,7 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) { TEST_P(QuicUnackedPacketMapTest, StopRetransmission) { const QuicStreamId stream_id = 2; SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id)); - unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -262,11 +220,7 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmission) { VerifyRetransmittablePackets(retransmittable, QUIC_ARRAYSIZE(retransmittable)); - if (unacked_packets_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } else { - unacked_packets_.CancelRetransmissionsForStream(stream_id); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); @@ -275,8 +229,7 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmission) { TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) { const QuicStreamId stream_id = 2; SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id)); - unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -285,10 +238,6 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) { VerifyRetransmittablePackets(retransmittable, QUIC_ARRAYSIZE(retransmittable)); - // Stop retransmissions on another stream and verify the packet is unchanged. - if (!unacked_packets_.session_decides_what_to_write()) { - unacked_packets_.CancelRetransmissionsForStream(stream_id + 2); - } VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(retransmittable, @@ -298,26 +247,16 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) { TEST_P(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) { const QuicStreamId stream_id = 2; SerializedPacket packet1(CreateRetransmittablePacketForStream(1, stream_id)); - unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); - std::vector retransmittable; - if (unacked_packets_.session_decides_what_to_write()) { - retransmittable = {1, 2}; - } else { - retransmittable = {2}; - } + std::vector retransmittable = {1, 2}; VerifyRetransmittablePackets(&retransmittable[0], retransmittable.size()); - if (unacked_packets_.session_decides_what_to_write()) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - } else { - unacked_packets_.CancelRetransmissionsForStream(stream_id); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); @@ -327,19 +266,13 @@ 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, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); - std::vector retransmittable; - if (unacked_packets_.session_decides_what_to_write()) { - retransmittable = {1, 2}; - } else { - retransmittable = {2}; - } + std::vector retransmittable = {1, 2}; VerifyRetransmittablePackets(&retransmittable[0], retransmittable.size()); EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); @@ -368,11 +301,9 @@ 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, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); SerializedPacket packet2(CreateRetransmittablePacket(2)); - unacked_packets_.AddSentPacket(&packet2, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -388,19 +319,13 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1)); RetransmitAndSendPacket(1, 3, LOSS_RETRANSMISSION); SerializedPacket packet4(CreateRetransmittablePacket(4)); - unacked_packets_.AddSentPacket(&packet4, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true); uint64_t unacked2[] = {1, 3, 4}; VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); uint64_t pending2[] = {3, 4}; VerifyInFlightPackets(pending2, QUIC_ARRAYSIZE(pending2)); - std::vector retransmittable2; - if (unacked_packets_.session_decides_what_to_write()) { - retransmittable2 = {1, 3, 4}; - } else { - retransmittable2 = {3, 4}; - } + std::vector retransmittable2 = {1, 3, 4}; VerifyRetransmittablePackets(&retransmittable2[0], retransmittable2.size()); // Early retransmit 3 (formerly 1) as 5, and remove 1 from unacked. @@ -409,18 +334,10 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.RemoveRetransmittability(QuicPacketNumber(4)); RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION); SerializedPacket packet6(CreateRetransmittablePacket(6)); - unacked_packets_.AddSentPacket(&packet6, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); - - std::vector unacked3; - std::vector retransmittable3; - if (unacked_packets_.session_decides_what_to_write()) { - unacked3 = {3, 5, 6}; - retransmittable3 = {3, 5, 6}; - } else { - unacked3 = {3, 5, 6}; - retransmittable3 = {5, 6}; - } + unacked_packets_.AddSentPacket(&packet6, NOT_RETRANSMISSION, now_, true); + + std::vector unacked3 = {3, 5, 6}; + std::vector retransmittable3 = {3, 5, 6}; VerifyUnackedPackets(&unacked3[0], unacked3.size()); VerifyRetransmittablePackets(&retransmittable3[0], retransmittable3.size()); uint64_t pending3[] = {3, 5, 6}; @@ -432,15 +349,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.RemoveRetransmittability(QuicPacketNumber(6)); RetransmitAndSendPacket(5, 7, LOSS_RETRANSMISSION); - std::vector unacked4; - std::vector retransmittable4; - if (unacked_packets_.session_decides_what_to_write()) { - unacked4 = {3, 5, 7}; - retransmittable4 = {3, 5, 7}; - } else { - unacked4 = {3, 5, 7}; - retransmittable4 = {7}; - } + std::vector unacked4 = {3, 5, 7}; + std::vector retransmittable4 = {3, 5, 7}; VerifyUnackedPackets(&unacked4[0], unacked4.size()); VerifyRetransmittablePackets(&retransmittable4[0], retransmittable4.size()); uint64_t pending4[] = {3, 5, 7}; @@ -456,11 +366,9 @@ 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, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); SerializedPacket packet2(CreateRetransmittablePacket(2)); - unacked_packets_.AddSentPacket(&packet2, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); @@ -480,30 +388,19 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) { VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); uint64_t pending2[] = {3}; VerifyInFlightPackets(pending2, QUIC_ARRAYSIZE(pending2)); - std::vector retransmittable2; - if (unacked_packets_.session_decides_what_to_write()) { - retransmittable2 = {1, 3}; - } else { - retransmittable2 = {3}; - } + std::vector retransmittable2 = {1, 3}; VerifyRetransmittablePackets(&retransmittable2[0], retransmittable2.size()); // 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, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet5, NOT_RETRANSMISSION, now_, true); uint64_t unacked3[] = {1, 3, 4, 5}; VerifyUnackedPackets(unacked3, QUIC_ARRAYSIZE(unacked3)); uint64_t pending3[] = {3, 4, 5}; VerifyInFlightPackets(pending3, QUIC_ARRAYSIZE(pending3)); - std::vector retransmittable3; - if (unacked_packets_.session_decides_what_to_write()) { - retransmittable3 = {1, 3, 4, 5}; - } else { - retransmittable3 = {4, 5}; - } + std::vector retransmittable3 = {1, 3, 4, 5}; VerifyRetransmittablePackets(&retransmittable3[0], retransmittable3.size()); // Early retransmit 4 as 6 and ensure in flight packet 3 is removed. @@ -514,21 +411,11 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) { unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4)); RetransmitAndSendPacket(4, 6, LOSS_RETRANSMISSION); - std::vector unacked4; - if (unacked_packets_.session_decides_what_to_write()) { - unacked4 = {4, 6}; - } else { - unacked4 = {4, 6}; - } + std::vector unacked4 = {4, 6}; VerifyUnackedPackets(&unacked4[0], unacked4.size()); uint64_t pending4[] = {6}; VerifyInFlightPackets(pending4, QUIC_ARRAYSIZE(pending4)); - std::vector retransmittable4; - if (unacked_packets_.session_decides_what_to_write()) { - retransmittable4 = {4, 6}; - } else { - retransmittable4 = {6}; - } + std::vector retransmittable4 = {4, 6}; VerifyRetransmittablePackets(&retransmittable4[0], retransmittable4.size()); } @@ -536,11 +423,9 @@ 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, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); SerializedPacket packet3(CreateRetransmittablePacket(3)); - unacked_packets_.AddSentPacket(&packet3, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true); RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION); EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.GetLeastUnacked()); @@ -685,8 +570,7 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 1. SerializedPacket packet1(CreateRetransmittablePacket(1)); packet1.encryption_level = ENCRYPTION_INITIAL; - unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentPacketOfPacketNumberSpace( @@ -698,8 +582,7 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 2. SerializedPacket packet2(CreateRetransmittablePacket(2)); packet2.encryption_level = ENCRYPTION_HANDSHAKE; - unacked_packets_.AddSentPacket(&packet2, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true); EXPECT_EQ(QuicPacketNumber(2u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentPacketOfPacketNumberSpace( @@ -713,8 +596,7 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 3. SerializedPacket packet3(CreateRetransmittablePacket(3)); packet3.encryption_level = ENCRYPTION_ZERO_RTT; - unacked_packets_.AddSentPacket(&packet3, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true); EXPECT_EQ(QuicPacketNumber(3u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentPacketOfPacketNumberSpace( @@ -734,8 +616,7 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 4. SerializedPacket packet4(CreateRetransmittablePacket(4)); packet4.encryption_level = ENCRYPTION_FORWARD_SECURE; - unacked_packets_.AddSentPacket(&packet4, QuicPacketNumber(), - NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true); EXPECT_EQ(QuicPacketNumber(4u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentPacketOfPacketNumberSpace( 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 33f7de16c18..a69efcdf822 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 @@ -15,11 +15,11 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.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_prefetch.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace { @@ -161,10 +161,12 @@ const char* QuicUtils::SentPacketStateToString(SentPacketState state) { RETURN_STRING_LITERAL(NEVER_SENT); RETURN_STRING_LITERAL(ACKED); RETURN_STRING_LITERAL(UNACKABLE); + RETURN_STRING_LITERAL(NEUTERED); RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMITTED); RETURN_STRING_LITERAL(LOST); RETURN_STRING_LITERAL(TLP_RETRANSMITTED); RETURN_STRING_LITERAL(RTO_RETRANSMITTED); + RETURN_STRING_LITERAL(PTO_RETRANSMITTED); RETURN_STRING_LITERAL(PROBE_RETRANSMITTED); } return "INVALID_SENT_PACKET_STATE"; @@ -329,6 +331,8 @@ SentPacketState QuicUtils::RetransmissionTypeToPacketState( return TLP_RETRANSMITTED; case RTO_RETRANSMISSION: return RTO_RETRANSMITTED; + case PTO_RETRANSMISSION: + return PTO_RETRANSMITTED; case PROBING_RETRANSMISSION: return PROBE_RETRANSMITTED; default: @@ -514,7 +518,7 @@ bool QuicUtils::VariableLengthConnectionIdAllowedForVersion( // We allow variable length connection IDs for unsupported versions to // ensure that IETF version negotiation works when other implementations // trigger version negotiation with custom connection ID lengths. - return version >= QUIC_VERSION_47 || version == QUIC_VERSION_UNSUPPORTED; + return version > QUIC_VERSION_46 || version == QUIC_VERSION_UNSUPPORTED; } // static diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc index 62cfbd0cc99..362c766b7de 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc @@ -131,6 +131,8 @@ TEST_F(QuicUtilsTest, RetransmissionTypeToPacketState) { EXPECT_EQ(TLP_RETRANSMITTED, state); } else if (i == RTO_RETRANSMISSION) { EXPECT_EQ(RTO_RETRANSMITTED, state); + } else if (i == PTO_RETRANSMISSION) { + EXPECT_EQ(PTO_RETRANSMITTED, state); } else if (i == PROBING_RETRANSMISSION) { EXPECT_EQ(PROBE_RETRANSMITTED, state); } else { @@ -244,17 +246,17 @@ TEST_F(QuicUtilsTest, RandomConnectionIdVariableLength) { TEST_F(QuicUtilsTest, VariableLengthConnectionId) { EXPECT_FALSE( - QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_39)); + QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_43)); EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion( - QuicUtils::CreateZeroConnectionId(QUIC_VERSION_39), QUIC_VERSION_39)); + QuicUtils::CreateZeroConnectionId(QUIC_VERSION_43), QUIC_VERSION_43)); EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion( QuicUtils::CreateZeroConnectionId(QUIC_VERSION_99), QUIC_VERSION_99)); - EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_39), + EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_43), EmptyQuicConnectionId()); EXPECT_EQ(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_99), EmptyQuicConnectionId()); EXPECT_FALSE(QuicUtils::IsConnectionIdValidForVersion(EmptyQuicConnectionId(), - QUIC_VERSION_39)); + QUIC_VERSION_43)); } TEST_F(QuicUtilsTest, StatelessResetToken) { 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 5f14ad4e80a..476bbc7fad3 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 @@ -17,13 +17,9 @@ QuicVersionManager::QuicVersionManager( ParsedQuicVersionVector supported_versions) : enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)), enable_version_50_(GetQuicReloadableFlag(quic_enable_version_50)), - enable_version_49_(GetQuicReloadableFlag(quic_enable_version_49)), - enable_version_48_(GetQuicReloadableFlag(quic_enable_version_48_2)), - enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)), - disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)), enable_tls_(GetQuicReloadableFlag(quic_supports_tls_handshake)), allowed_supported_versions_(std::move(supported_versions)) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); RefilterSupportedVersions(); } @@ -42,21 +38,13 @@ const ParsedQuicVersionVector& QuicVersionManager::GetSupportedVersions() { } void QuicVersionManager::MaybeRefilterSupportedVersions() { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) || enable_version_50_ != GetQuicReloadableFlag(quic_enable_version_50) || - enable_version_49_ != GetQuicReloadableFlag(quic_enable_version_49) || - enable_version_48_ != GetQuicReloadableFlag(quic_enable_version_48_2) || - enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) || - disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39) || enable_tls_ != GetQuicReloadableFlag(quic_supports_tls_handshake)) { enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99); enable_version_50_ = GetQuicReloadableFlag(quic_enable_version_50); - enable_version_49_ = GetQuicReloadableFlag(quic_enable_version_49); - enable_version_48_ = GetQuicReloadableFlag(quic_enable_version_48_2); - enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47); - disable_version_39_ = GetQuicReloadableFlag(quic_disable_version_39); enable_tls_ = GetQuicReloadableFlag(quic_supports_tls_handshake); RefilterSupportedVersions(); } 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 3b2ec854230..0851464b857 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 @@ -45,14 +45,6 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { bool enable_version_99_; // quic_enable_version_50 flag bool enable_version_50_; - // quic_enable_version_49 flag - bool enable_version_49_; - // quic_enable_version_48_2 flag - bool enable_version_48_; - // quic_enable_version_47 flag - bool enable_version_47_; - // quic_disable_version_39 flag - bool disable_version_39_; // quic_supports_tls_handshake flag bool enable_tls_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc index 87494772887..48623a878f3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc @@ -16,64 +16,36 @@ namespace { class QuicVersionManagerTest : public QuicTest {}; TEST_F(QuicVersionManagerTest, QuicVersionManager) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); SetQuicReloadableFlag(quic_enable_version_99, false); SetQuicReloadableFlag(quic_enable_version_50, false); - SetQuicReloadableFlag(quic_enable_version_49, false); - SetQuicReloadableFlag(quic_enable_version_48_2, false); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_disable_version_39, true); QuicVersionManager manager(AllSupportedVersions()); EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), manager.GetSupportedTransportVersions()); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_43}), - manager.GetSupportedTransportVersions()); - - SetQuicReloadableFlag(quic_disable_version_39, false); - EXPECT_EQ(QuicTransportVersionVector( - {QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}), - manager.GetSupportedTransportVersions()); - - SetQuicReloadableFlag(quic_enable_version_47, true); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_47, QUIC_VERSION_46, - QUIC_VERSION_43, QUIC_VERSION_39}), - manager.GetSupportedTransportVersions()); - - SetQuicReloadableFlag(quic_enable_version_48_2, true); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_48, QUIC_VERSION_47, - QUIC_VERSION_46, QUIC_VERSION_43, - QUIC_VERSION_39}), - manager.GetSupportedTransportVersions()); - - SetQuicReloadableFlag(quic_enable_version_49, true); EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_49, QUIC_VERSION_48, - QUIC_VERSION_47, QUIC_VERSION_46, - QUIC_VERSION_43, QUIC_VERSION_39}), + QUIC_VERSION_46, QUIC_VERSION_43}), manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_50, true); - EXPECT_EQ( - QuicTransportVersionVector( - {QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47, - QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}), - manager.GetSupportedTransportVersions()); + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_50, QUIC_VERSION_49, + QUIC_VERSION_48, QUIC_VERSION_46, + QUIC_VERSION_43}), + manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_99, true); - EXPECT_EQ( - QuicTransportVersionVector( - {QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, - QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}), - manager.GetSupportedTransportVersions()); + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_50, + QUIC_VERSION_49, QUIC_VERSION_48, + QUIC_VERSION_46, QUIC_VERSION_43}), + manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_99, true); - EXPECT_EQ( - QuicTransportVersionVector( - {QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, - QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}), - manager.GetSupportedTransportVersions()); + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_50, + QUIC_VERSION_49, QUIC_VERSION_48, + QUIC_VERSION_46, QUIC_VERSION_43}), + manager.GetSupportedTransportVersions()); // Ensure that all versions are now supported. EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), 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 7aabc3d4b2f..abeb64e7f7f 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 @@ -11,11 +11,11 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.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" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace { @@ -27,10 +27,6 @@ QuicVersionLabel MakeVersionLabel(char a, char b, char c, char d) { } QuicVersionLabel CreateRandomVersionLabelForNegotiation() { - if (!GetQuicReloadableFlag(quic_version_negotiation_grease)) { - return MakeVersionLabel(0xda, 0x5a, 0x3a, 0x3a); - } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_version_negotiation_grease, 2, 2); QuicVersionLabel result; if (!GetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness)) { QuicRandom::GetInstance()->RandBytes(&result, sizeof(result)); @@ -44,13 +40,8 @@ QuicVersionLabel CreateRandomVersionLabelForNegotiation() { } // namespace -ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol, - QuicTransportVersion transport_version) - : handshake_protocol(handshake_protocol), - transport_version(transport_version) {} - bool ParsedQuicVersion::KnowsWhichDecrypterToUse() const { - return transport_version >= QUIC_VERSION_47 || + return transport_version > QUIC_VERSION_46 || handshake_protocol == PROTOCOL_TLS1_3; } @@ -89,6 +80,11 @@ bool ParsedQuicVersion::SupportsAntiAmplificationLimit() const { handshake_protocol == PROTOCOL_TLS1_3; } +bool ParsedQuicVersion::CanSendCoalescedPackets() const { + return QuicVersionHasLongHeaderLengths(transport_version) && + handshake_protocol == PROTOCOL_TLS1_3; +} + bool VersionHasLengthPrefixedConnectionIds( QuicTransportVersion transport_version) { return transport_version > QUIC_VERSION_48; @@ -113,17 +109,13 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { << parsed_version.handshake_protocol; return 0; } - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); switch (parsed_version.transport_version) { - case QUIC_VERSION_39: - return MakeVersionLabel(proto, '0', '3', '9'); case QUIC_VERSION_43: return MakeVersionLabel(proto, '0', '4', '3'); case QUIC_VERSION_46: return MakeVersionLabel(proto, '0', '4', '6'); - case QUIC_VERSION_47: - return MakeVersionLabel(proto, '0', '4', '7'); case QUIC_VERSION_48: return MakeVersionLabel(proto, '0', '4', '8'); case QUIC_VERSION_49: @@ -274,22 +266,6 @@ ParsedQuicVersionVector FilterSupportedVersions( if (GetQuicReloadableFlag(quic_enable_version_50)) { filtered_versions.push_back(version); } - } else if (version.transport_version == QUIC_VERSION_49) { - if (GetQuicReloadableFlag(quic_enable_version_49)) { - filtered_versions.push_back(version); - } - } else if (version.transport_version == QUIC_VERSION_48) { - if (GetQuicReloadableFlag(quic_enable_version_48_2)) { - filtered_versions.push_back(version); - } - } else if (version.transport_version == QUIC_VERSION_47) { - if (GetQuicReloadableFlag(quic_enable_version_47)) { - filtered_versions.push_back(version); - } - } else if (version.transport_version == QUIC_VERSION_39) { - if (!GetQuicReloadableFlag(quic_disable_version_39)) { - filtered_versions.push_back(version); - } } else { filtered_versions.push_back(version); } @@ -340,7 +316,7 @@ QuicVersionLabel QuicVersionToQuicVersionLabel( } std::string QuicVersionLabelToString(QuicVersionLabel version_label) { - return QuicTagToString(QuicEndian::HostToNet32(version_label)); + return QuicTagToString(quiche::QuicheEndian::HostToNet32(version_label)); } std::string QuicVersionLabelVectorToString( @@ -377,13 +353,11 @@ HandshakeProtocol QuicVersionLabelToHandshakeProtocol( return #x std::string QuicVersionToString(QuicTransportVersion transport_version) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); switch (transport_version) { - RETURN_STRING_LITERAL(QUIC_VERSION_39); RETURN_STRING_LITERAL(QUIC_VERSION_43); RETURN_STRING_LITERAL(QUIC_VERSION_46); - RETURN_STRING_LITERAL(QUIC_VERSION_47); RETURN_STRING_LITERAL(QUIC_VERSION_48); RETURN_STRING_LITERAL(QUIC_VERSION_49); RETURN_STRING_LITERAL(QUIC_VERSION_50); @@ -430,6 +404,10 @@ std::string ParsedQuicVersionVectorToString( return result; } +bool VersionSupportsGoogleAltSvcFormat(QuicTransportVersion transport_version) { + return transport_version <= QUIC_VERSION_46; +} + bool QuicVersionLabelUses4BitConnectionIdLength( QuicVersionLabel version_label) { // As we deprecate old versions, we still need the ability to send valid @@ -478,14 +456,13 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) { void QuicVersionInitializeSupportForIetfDraft() { // Enable necessary flags. SetQuicReloadableFlag(quic_supports_tls_handshake, true); - SetQuicReloadableFlag(quic_simplify_stop_waiting, true); } void QuicEnableVersion(ParsedQuicVersion parsed_version) { if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { SetQuicReloadableFlag(quic_supports_tls_handshake, true); } - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); if (parsed_version.transport_version == QUIC_VERSION_99) { SetQuicReloadableFlag(quic_enable_version_99, true); @@ -493,15 +470,6 @@ void QuicEnableVersion(ParsedQuicVersion parsed_version) { if (parsed_version.transport_version == QUIC_VERSION_50) { SetQuicReloadableFlag(quic_enable_version_50, true); } - if (parsed_version.transport_version == QUIC_VERSION_49) { - SetQuicReloadableFlag(quic_enable_version_49, true); - } - if (parsed_version.transport_version == QUIC_VERSION_48) { - SetQuicReloadableFlag(quic_enable_version_48_2, true); - } - if (parsed_version.transport_version == QUIC_VERSION_47) { - SetQuicReloadableFlag(quic_enable_version_47, true); - } } #undef RETURN_STRING_LITERAL // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h index de5bbea167c..0a4022e2006 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h @@ -82,10 +82,9 @@ enum QuicTransportVersion { // Version 38 switched to IETF padding frame format and support for NSTP (no // stop waiting frame) connection option. - QUIC_VERSION_39 = 39, // Integers and floating numbers are written in big - // endian. Dot not ack acks. Send a connection level - // WINDOW_UPDATE every 20 sent packets which do not - // contain retransmittable frames. + // Version 39 writes integers and floating numbers in big endian, stops acking + // acks, sends a connection level WINDOW_UPDATE every 20 sent packets which do + // not contain retransmittable frames. // Version 40 was an attempt to convert QUIC to IETF frame format; it was // never shipped due to a bug. @@ -103,7 +102,7 @@ enum QuicTransportVersion { QUIC_VERSION_46 = 46, // Use IETF draft-17 header format with demultiplexing // bit. - QUIC_VERSION_47 = 47, // Allow variable-length QUIC connection IDs. + // Version 47 added variable-length QUIC server connection IDs. QUIC_VERSION_48 = 48, // Use CRYPTO frames for the handshake. QUIC_VERSION_49 = 49, // Client connection IDs, long header lengths, IETF // header format from draft-ietf-quic-invariants-06. @@ -120,7 +119,7 @@ enum QuicTransportVersion { }; // IETF draft version most closely approximated by TLS + v99. -static const int kQuicIetfDraftVersion = 23; +static const int kQuicIetfDraftVersion = 24; // The crypto handshake protocols that can be used with QUIC. enum HandshakeProtocol { @@ -135,10 +134,12 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { HandshakeProtocol handshake_protocol; QuicTransportVersion transport_version; - ParsedQuicVersion(HandshakeProtocol handshake_protocol, - QuicTransportVersion transport_version); + constexpr ParsedQuicVersion(HandshakeProtocol handshake_protocol, + QuicTransportVersion transport_version) + : handshake_protocol(handshake_protocol), + transport_version(transport_version) {} - ParsedQuicVersion(const ParsedQuicVersion& other) + constexpr ParsedQuicVersion(const ParsedQuicVersion& other) : handshake_protocol(other.handshake_protocol), transport_version(other.transport_version) {} @@ -192,6 +193,9 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { // i.e., server will send no more than FLAGS_quic_anti_amplification_factor // times received bytes until address can be validated. bool SupportsAntiAmplificationLimit() const; + + // Returns true if this version can send coalesced packets. + bool CanSendCoalescedPackets() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); @@ -215,8 +219,8 @@ using QuicVersionLabelVector = std::vector; // // See go/new-quic-version for more details on how to roll out new versions. static const QuicTransportVersion kSupportedTransportVersions[] = { - QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, - QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39, + QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, + QUIC_VERSION_48, QUIC_VERSION_46, QUIC_VERSION_43, }; // This vector contains all crypto handshake protocols that are supported. @@ -416,6 +420,11 @@ QUIC_EXPORT_PRIVATE inline bool VersionHasIetfQuicFrames( QUIC_EXPORT_PRIVATE bool VersionHasLengthPrefixedConnectionIds( QuicTransportVersion transport_version); +// Returns true if this version supports the old Google-style Alt-Svc +// advertisement format. +QUIC_EXPORT_PRIVATE bool VersionSupportsGoogleAltSvcFormat( + QuicTransportVersion transport_version); + // Returns whether this version label supports long header 4-bit encoded // connection ID lengths as described in draft-ietf-quic-invariants-05 and // draft-ietf-quic-transport-21. 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 a631187c561..283113fe37f 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 @@ -35,8 +35,8 @@ TEST_F(QuicVersionsTest, QuicVersionToQuicVersionLabel) { log.StartCapturingLogs(); // Explicitly test a specific version. - EXPECT_EQ(MakeQuicTag('9', '3', '0', 'Q'), - QuicVersionToQuicVersionLabel(QUIC_VERSION_39)); + EXPECT_EQ(MakeQuicTag('3', '4', '0', 'Q'), + QuicVersionToQuicVersionLabel(QUIC_VERSION_43)); // Loop over all supported versions and make sure that we never hit the // default case (i.e. all supported versions should be successfully converted @@ -63,8 +63,8 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToQuicTransportVersion) { log.StartCapturingLogs(); // Explicitly test specific versions. - EXPECT_EQ(QUIC_VERSION_39, - QuicVersionLabelToQuicVersion(MakeQuicTag('9', '3', '0', 'Q'))); + EXPECT_EQ(QUIC_VERSION_43, + QuicVersionLabelToQuicVersion(MakeQuicTag('3', '4', '0', 'Q'))); for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { QuicTransportVersion version = kSupportedTransportVersions[i]; @@ -112,28 +112,20 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToHandshakeProtocol) { } TEST_F(QuicVersionsTest, ParseQuicVersionLabel) { - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), - ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '3', '9'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47), - ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '7'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '8'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '5', '0'))); // Test TLS versions: - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39), - ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47), - ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '8'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), @@ -141,33 +133,25 @@ TEST_F(QuicVersionsTest, ParseQuicVersionLabel) { } TEST_F(QuicVersionsTest, ParseQuicVersionString) { - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), - ParseQuicVersionString("Q039")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), ParseQuicVersionString("Q043")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), ParseQuicVersionString("Q046")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47), - ParseQuicVersionString("Q047")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48), ParseQuicVersionString("Q048")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), ParseQuicVersionString("Q050")); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("")); - EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 47")); - EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q047 ")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 46")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q046 ")); // Test a TLS version: SetQuicReloadableFlag(quic_supports_tls_handshake, true); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39), - ParseQuicVersionString("T039")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43), ParseQuicVersionString("T043")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46), ParseQuicVersionString("T046")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47), - ParseQuicVersionString("T047")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48), ParseQuicVersionString("T048")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), @@ -175,18 +159,12 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) { } TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { - EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '9'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39))); EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '3'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43))); EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46))); - EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '7'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47))); EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '8'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48))); @@ -195,18 +173,12 @@ TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50))); // Test a TLS version: - EXPECT_EQ(MakeVersionLabel('T', '0', '3', '9'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39))); EXPECT_EQ(MakeVersionLabel('T', '0', '4', '3'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43))); EXPECT_EQ(MakeVersionLabel('T', '0', '4', '6'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46))); - EXPECT_EQ(MakeVersionLabel('T', '0', '4', '7'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47))); EXPECT_EQ(MakeVersionLabel('T', '0', '4', '8'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48))); @@ -245,25 +217,24 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToString) { } TEST_F(QuicVersionsTest, QuicVersionToString) { - EXPECT_EQ("QUIC_VERSION_39", QuicVersionToString(QUIC_VERSION_39)); EXPECT_EQ("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(QUIC_VERSION_UNSUPPORTED)); - QuicTransportVersion single_version[] = {QUIC_VERSION_39}; + QuicTransportVersion single_version[] = {QUIC_VERSION_43}; QuicTransportVersionVector versions_vector; for (size_t i = 0; i < QUIC_ARRAYSIZE(single_version); ++i) { versions_vector.push_back(single_version[i]); } - EXPECT_EQ("QUIC_VERSION_39", + EXPECT_EQ("QUIC_VERSION_43", QuicTransportVersionVectorToString(versions_vector)); QuicTransportVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, - QUIC_VERSION_39}; + QUIC_VERSION_43}; versions_vector.clear(); for (size_t i = 0; i < QUIC_ARRAYSIZE(multiple_versions); ++i) { versions_vector.push_back(multiple_versions[i]); } - EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_39", + EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_43", QuicTransportVersionVectorToString(versions_vector)); // Make sure that all supported versions are present in QuicVersionToString. @@ -275,16 +246,16 @@ TEST_F(QuicVersionsTest, QuicVersionToString) { TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { ParsedQuicVersion unsupported = UnsupportedQuicVersion(); - ParsedQuicVersion version39(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39); - EXPECT_EQ("Q039", ParsedQuicVersionToString(version39)); + ParsedQuicVersion version43(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); + EXPECT_EQ("Q043", ParsedQuicVersionToString(version43)); EXPECT_EQ("0", ParsedQuicVersionToString(unsupported)); - ParsedQuicVersionVector versions_vector = {version39}; - EXPECT_EQ("Q039", ParsedQuicVersionVectorToString(versions_vector)); + ParsedQuicVersionVector versions_vector = {version43}; + EXPECT_EQ("Q043", ParsedQuicVersionVectorToString(versions_vector)); - versions_vector = {unsupported, version39}; - EXPECT_EQ("0,Q039", ParsedQuicVersionVectorToString(versions_vector)); - EXPECT_EQ("0:Q039", ParsedQuicVersionVectorToString(versions_vector, ":", + versions_vector = {unsupported, version43}; + EXPECT_EQ("0,Q043", ParsedQuicVersionVectorToString(versions_vector)); + EXPECT_EQ("0:Q043", ParsedQuicVersionVectorToString(versions_vector, ":", versions_vector.size())); EXPECT_EQ("0|...", ParsedQuicVersionVectorToString(versions_vector, "|", 0)); @@ -307,12 +278,8 @@ TEST_F(QuicVersionsTest, AllSupportedTransportVersions) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, true); - SetQuicReloadableFlag(quic_enable_version_48_2, true); - SetQuicReloadableFlag(quic_enable_version_49, true); SetQuicReloadableFlag(quic_enable_version_50, true); SetQuicReloadableFlag(quic_enable_version_99, true); ParsedQuicVersionVector parsed_versions; @@ -320,8 +287,8 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, - QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}; + QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, + QUIC_VERSION_48, QUIC_VERSION_46, QUIC_VERSION_43}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -334,12 +301,8 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, true); - SetQuicReloadableFlag(quic_enable_version_48_2, true); - SetQuicReloadableFlag(quic_enable_version_49, true); SetQuicReloadableFlag(quic_enable_version_50, true); SetQuicReloadableFlag(quic_enable_version_99, false); ParsedQuicVersionVector parsed_versions; @@ -347,8 +310,8 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) { parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47, - QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}; + QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_46, + QUIC_VERSION_43}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -361,64 +324,6 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo50) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, true); - SetQuicReloadableFlag(quic_enable_version_48_2, true); - SetQuicReloadableFlag(quic_enable_version_49, true); - SetQuicReloadableFlag(quic_enable_version_50, false); - SetQuicReloadableFlag(quic_enable_version_99, false); - ParsedQuicVersionVector parsed_versions; - for (QuicTransportVersion version : all_versions) { - parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - QuicTransportVersionVector expected_versions = { - QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47, - QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}; - ParsedQuicVersionVector expected_parsed_versions; - for (QuicTransportVersion version : expected_versions) { - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - - ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); - ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); -} - -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo49) { - QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, - "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, true); - SetQuicReloadableFlag(quic_enable_version_48_2, true); - SetQuicReloadableFlag(quic_enable_version_49, false); - SetQuicReloadableFlag(quic_enable_version_50, false); - SetQuicReloadableFlag(quic_enable_version_99, false); - ParsedQuicVersionVector parsed_versions; - for (QuicTransportVersion version : all_versions) { - parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - QuicTransportVersionVector expected_versions = { - QUIC_VERSION_48, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, - QUIC_VERSION_39}; - ParsedQuicVersionVector expected_parsed_versions; - for (QuicTransportVersion version : expected_versions) { - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - - ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); - ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); -} - -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) { - QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, - "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, true); - SetQuicReloadableFlag(quic_enable_version_48_2, false); - SetQuicReloadableFlag(quic_enable_version_49, false); SetQuicReloadableFlag(quic_enable_version_50, false); SetQuicReloadableFlag(quic_enable_version_99, false); ParsedQuicVersionVector parsed_versions; @@ -426,7 +331,7 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) { parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}; + QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_46, QUIC_VERSION_43}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -437,14 +342,10 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) { ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); } -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) { +TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNoFlags) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_enable_version_48_2, false); - SetQuicReloadableFlag(quic_enable_version_49, false); SetQuicReloadableFlag(quic_enable_version_50, false); SetQuicReloadableFlag(quic_enable_version_99, false); ParsedQuicVersionVector parsed_versions; @@ -452,33 +353,7 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) { parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}; - ParsedQuicVersionVector expected_parsed_versions; - for (QuicTransportVersion version : expected_versions) { - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - - ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); - ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); -} - -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) { - QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, - "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_39, true); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_enable_version_48_2, false); - SetQuicReloadableFlag(quic_enable_version_49, false); - SetQuicReloadableFlag(quic_enable_version_50, false); - SetQuicReloadableFlag(quic_enable_version_99, false); - ParsedQuicVersionVector parsed_versions; - for (QuicTransportVersion version : all_versions) { - parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - QuicTransportVersionVector expected_versions = {QUIC_VERSION_46, - QUIC_VERSION_43}; + QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_46, QUIC_VERSION_43}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -490,7 +365,7 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) { } TEST_F(QuicVersionsTest, LookUpVersionByIndex) { - QuicTransportVersionVector all_versions = {QUIC_VERSION_39}; + QuicTransportVersionVector all_versions = {QUIC_VERSION_43}; int version_count = all_versions.size(); for (int i = -5; i <= version_count + 1; ++i) { if (i >= 0 && i < version_count) { @@ -528,12 +403,10 @@ TEST_F(QuicVersionsTest, ParsedVersionsToTransportVersions) { // yet a typo was made in doing the #defines and it was caught // only in some test far removed from here... Better safe than sorry. TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - EXPECT_EQ(QUIC_VERSION_39, 39); EXPECT_EQ(QUIC_VERSION_43, 43); EXPECT_EQ(QUIC_VERSION_46, 46); - EXPECT_EQ(QUIC_VERSION_47, 47); EXPECT_EQ(QUIC_VERSION_48, 48); EXPECT_EQ(QUIC_VERSION_49, 49); EXPECT_EQ(QUIC_VERSION_50, 50); @@ -541,12 +414,8 @@ TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) { } TEST_F(QuicVersionsTest, AlpnForVersion) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - ParsedQuicVersion parsed_version_q047 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47); - ParsedQuicVersion parsed_version_t047 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47); ParsedQuicVersion parsed_version_q048 = ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48); ParsedQuicVersion parsed_version_t048 = @@ -562,33 +431,21 @@ TEST_F(QuicVersionsTest, AlpnForVersion) { ParsedQuicVersion parsed_version_t099 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); - EXPECT_EQ("h3-Q047", AlpnForVersion(parsed_version_q047)); - EXPECT_EQ("h3-T047", AlpnForVersion(parsed_version_t047)); EXPECT_EQ("h3-Q048", AlpnForVersion(parsed_version_q048)); EXPECT_EQ("h3-T048", AlpnForVersion(parsed_version_t048)); EXPECT_EQ("h3-Q049", AlpnForVersion(parsed_version_q049)); EXPECT_EQ("h3-T049", AlpnForVersion(parsed_version_t049)); EXPECT_EQ("h3-Q050", AlpnForVersion(parsed_version_q050)); EXPECT_EQ("h3-T050", AlpnForVersion(parsed_version_t050)); - EXPECT_EQ("h3-23", AlpnForVersion(parsed_version_t099)); + EXPECT_EQ("h3-24", AlpnForVersion(parsed_version_t099)); + static_assert(kQuicIetfDraftVersion == 24, + "ALPN does not match draft version"); } TEST_F(QuicVersionsTest, QuicEnableVersion) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); SetQuicReloadableFlag(quic_supports_tls_handshake, true); - ParsedQuicVersion parsed_version_q047 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47); - ParsedQuicVersion parsed_version_t047 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47); - ParsedQuicVersion parsed_version_q048 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48); - ParsedQuicVersion parsed_version_t048 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48); - ParsedQuicVersion parsed_version_q049 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49); - ParsedQuicVersion parsed_version_t049 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_49); ParsedQuicVersion parsed_version_q050 = ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50); ParsedQuicVersion parsed_version_t050 = @@ -596,59 +453,13 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) { ParsedQuicVersion parsed_version_t099 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); SetQuicReloadableFlag(quic_supports_tls_handshake, false); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_enable_version_48_2, false); - SetQuicReloadableFlag(quic_enable_version_49, false); SetQuicReloadableFlag(quic_enable_version_50, false); SetQuicReloadableFlag(quic_enable_version_99, false); - { - QuicFlagSaver flag_saver; - QuicEnableVersion(parsed_version_q047); - EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); - } - - { - QuicFlagSaver flag_saver; - QuicEnableVersion(parsed_version_t047); - EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); - } - - { - QuicFlagSaver flag_saver; - QuicEnableVersion(parsed_version_q048); - EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48_2)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); - } - - { - QuicFlagSaver flag_saver; - QuicEnableVersion(parsed_version_t048); - EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48_2)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); - } - { QuicFlagSaver flag_saver; QuicEnableVersion(parsed_version_q050); EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_50)); EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); } @@ -657,38 +468,14 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) { QuicFlagSaver flag_saver; QuicEnableVersion(parsed_version_t050); EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_50)); EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); } - { - QuicFlagSaver flag_saver; - QuicEnableVersion(parsed_version_q049); - EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_49)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); - } - - { - QuicFlagSaver flag_saver; - QuicEnableVersion(parsed_version_t049); - EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_49)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); - } - { QuicFlagSaver flag_saver; QuicEnableVersion(parsed_version_t099); EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47)); - EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2)); EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_99)); } 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 7cab768a56d..b80eca6e963 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 @@ -247,9 +247,9 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { // A StaticStreamCollection is a vector of pairs plus a // eagerly-computed number of blocked static streams. - class StaticStreamCollection { + class QUIC_EXPORT_PRIVATE StaticStreamCollection { public: - struct StreamIdBlockedPair { + struct QUIC_EXPORT_PRIVATE StreamIdBlockedPair { QuicStreamId id; bool is_blocked; }; 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 674cf2cdeb3..a65fefc308f 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 @@ -43,22 +43,21 @@ void TlsClientHandshaker::ProofVerifierCallbackImpl::Cancel() { } TlsClientHandshaker::TlsClientHandshaker( + const QuicServerId& server_id, QuicCryptoStream* stream, QuicSession* session, - const QuicServerId& server_id, - ProofVerifier* proof_verifier, - SSL_CTX* ssl_ctx, std::unique_ptr verify_context, - QuicCryptoClientStream::ProofHandler* proof_handler, - const std::string& user_agent_id) - : TlsHandshaker(stream, session, ssl_ctx), + QuicCryptoClientConfig* crypto_config, + QuicCryptoClientStream::ProofHandler* proof_handler) + : TlsHandshaker(stream, session, crypto_config->ssl_ctx()), server_id_(server_id), - proof_verifier_(proof_verifier), + proof_verifier_(crypto_config->proof_verifier()), verify_context_(std::move(verify_context)), proof_handler_(proof_handler), - user_agent_id_(user_agent_id), + session_cache_(crypto_config->session_cache()), + user_agent_id_(crypto_config->user_agent_id()), crypto_negotiated_params_(new QuicCryptoNegotiatedParameters), - tls_connection_(ssl_ctx, this) {} + tls_connection_(crypto_config->ssl_ctx(), this) {} TlsClientHandshaker::~TlsClientHandshaker() { if (proof_verify_callback_) { @@ -66,11 +65,6 @@ TlsClientHandshaker::~TlsClientHandshaker() { } } -// static -bssl::UniquePtr TlsClientHandshaker::CreateSslCtx() { - return TlsClientConnection::CreateSslCtx(); -} - bool TlsClientHandshaker::CryptoConnect() { state_ = STATE_HANDSHAKE_RUNNING; @@ -92,6 +86,15 @@ bool TlsClientHandshaker::CryptoConnect() { return false; } + // Set a session to resume, if there is one. + if (session_cache_) { + std::unique_ptr cached_state = + session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl())); + if (cached_state) { + SSL_set_session(ssl(), cached_state->tls_session.get()); + } + } + // Start the handshake. AdvanceHandshake(); return session()->connection()->connected(); @@ -202,6 +205,11 @@ int TlsClientHandshaker::num_sent_client_hellos() const { return 0; } +bool TlsClientHandshaker::IsResumption() const { + QUIC_BUG_IF(!handshake_confirmed_); + return SSL_session_reused(ssl()) == 1; +} + int TlsClientHandshaker::num_scup_messages_received() const { // SCUP messages aren't sent or received when using the TLS handshake. return 0; @@ -245,7 +253,10 @@ void TlsClientHandshaker::AdvanceHandshake() { return; } if (state_ == STATE_HANDSHAKE_COMPLETE) { - // TODO(nharper): Handle post-handshake messages. + int rv = SSL_process_quic_post_handshake(ssl()); + if (rv != 1) { + CloseConnection(QUIC_HANDSHAKE_FAILED, "Unexpected post-handshake data"); + } return; } @@ -322,12 +333,9 @@ void TlsClientHandshaker::FinishHandshake() { QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string << "'"; - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); - session()->NeuterUnencryptedData(); encryption_established_ = true; handshake_confirmed_ = true; - session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED); - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + delegate()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Fill crypto_negotiated_params_: const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); @@ -337,8 +345,9 @@ void TlsClientHandshaker::FinishHandshake() { crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); crypto_negotiated_params_->peer_signature_algorithm = SSL_get_peer_signature_algorithm(ssl()); - - session()->connection()->OnHandshakeComplete(); + // TODO(fayang): Replace this with DiscardOldKeys(ENCRYPTION_HANDSHAKE) when + // handshake key discarding settles down. + delegate()->NeuterHandshakeData(); } enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { @@ -394,4 +403,25 @@ enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { } } +void TlsClientHandshaker::InsertSession(bssl::UniquePtr session) { + if (session_cache_ == nullptr) { + QUIC_DVLOG(1) << "No session cache, not inserting a session"; + return; + } + auto cache_state = std::make_unique(); + cache_state->tls_session = std::move(session); + session_cache_->Insert(server_id_, std::move(cache_state)); +} + +void TlsClientHandshaker::WriteMessage(EncryptionLevel level, + QuicStringPiece data) { + if (level == ENCRYPTION_HANDSHAKE && + state_ < STATE_ENCRYPTION_HANDSHAKE_DATA_SENT) { + state_ = STATE_ENCRYPTION_HANDSHAKE_DATA_SENT; + delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); + } + TlsHandshaker::WriteMessage(level, data); +} + } // namespace quic 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 4672821f72b..319cd1704bc 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 @@ -24,26 +24,21 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker public QuicCryptoClientStream::HandshakerDelegate, public TlsClientConnection::Delegate { public: - TlsClientHandshaker(QuicCryptoStream* stream, + TlsClientHandshaker(const QuicServerId& server_id, + QuicCryptoStream* stream, QuicSession* session, - const QuicServerId& server_id, - ProofVerifier* proof_verifier, - SSL_CTX* ssl_ctx, std::unique_ptr verify_context, - QuicCryptoClientStream::ProofHandler* proof_handler, - const std::string& user_agent_id); + QuicCryptoClientConfig* crypto_config, + QuicCryptoClientStream::ProofHandler* proof_handler); TlsClientHandshaker(const TlsClientHandshaker&) = delete; TlsClientHandshaker& operator=(const TlsClientHandshaker&) = delete; ~TlsClientHandshaker() override; - // Creates and configures an SSL_CTX to be used with a TlsClientHandshaker. - // The caller is responsible for ownership of the newly created struct. - static bssl::UniquePtr CreateSslCtx(); - // From QuicCryptoClientStream::HandshakerDelegate bool CryptoConnect() override; int num_sent_client_hellos() const override; + bool IsResumption() const override; int num_scup_messages_received() const override; std::string chlo_hash() const override; @@ -55,6 +50,9 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker CryptoMessageParser* crypto_message_parser() override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; + // Override to drop initial keys if trying to write ENCRYPTION_HANDSHAKE data. + void WriteMessage(EncryptionLevel level, QuicStringPiece data) override; + void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; } protected: @@ -73,7 +71,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker private: // ProofVerifierCallbackImpl handles the result of an asynchronous certificate // verification operation. - class ProofVerifierCallbackImpl : public ProofVerifierCallback { + class QUIC_EXPORT_PRIVATE ProofVerifierCallbackImpl + : public ProofVerifierCallback { public: explicit ProofVerifierCallbackImpl(TlsClientHandshaker* parent); ~ProofVerifierCallbackImpl() override; @@ -94,6 +93,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker STATE_IDLE, STATE_HANDSHAKE_RUNNING, STATE_CERT_VERIFY_PENDING, + STATE_ENCRYPTION_HANDSHAKE_DATA_SENT, STATE_HANDSHAKE_COMPLETE, STATE_CONNECTION_CLOSED, } state_ = STATE_IDLE; @@ -103,6 +103,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker bool ProcessTransportParameters(std::string* error_details); void FinishHandshake(); + void InsertSession(bssl::UniquePtr session) override; + QuicServerId server_id_; // Objects used for verifying the server's certificate chain. @@ -115,6 +117,10 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker // certificate verification. QuicCryptoClientStream::ProofHandler* proof_handler_; + // Used for session resumption. |session_cache_| is owned by the + // QuicCryptoClientConfig passed into TlsClientHandshaker's constructor. + SessionCache* session_cache_; + std::string user_agent_id_; // ProofVerifierCallback used for async certificate verification. This object 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 f2089cd102e..08b4eb9525c 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 @@ -16,7 +16,7 @@ namespace quic { TlsHandshaker::TlsHandshaker(QuicCryptoStream* stream, QuicSession* session, SSL_CTX* /*ssl_ctx*/) - : stream_(stream), session_(session) { + : stream_(stream), session_(session), delegate_(session) { QUIC_BUG_IF(!GetQuicReloadableFlag(quic_supports_tls_handshake)) << "Attempted to create TLS handshaker when TLS is disabled"; } @@ -64,32 +64,22 @@ const EVP_MD* TlsHandshaker::Prf() { SSL_CIPHER_get_prf_nid(SSL_get_pending_cipher(ssl()))); } -std::unique_ptr TlsHandshaker::CreateEncrypter( - const std::vector& pp_secret) { +void TlsHandshaker::SetEncryptionSecret( + EncryptionLevel level, + const std::vector& read_secret, + const std::vector& write_secret) { std::unique_ptr encrypter = QuicEncrypter::CreateFromCipherSuite( SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl()))); - CryptoUtils::SetKeyAndIV(Prf(), pp_secret, encrypter.get()); - return encrypter; -} - -std::unique_ptr TlsHandshaker::CreateDecrypter( - const std::vector& pp_secret) { + CryptoUtils::SetKeyAndIV(Prf(), write_secret, encrypter.get()); std::unique_ptr decrypter = QuicDecrypter::CreateFromCipherSuite( SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl()))); - CryptoUtils::SetKeyAndIV(Prf(), pp_secret, decrypter.get()); - return decrypter; -} - -void TlsHandshaker::SetEncryptionSecret( - EncryptionLevel level, - const std::vector& read_secret, - const std::vector& write_secret) { - std::unique_ptr encrypter = CreateEncrypter(write_secret); - session()->connection()->SetEncrypter(level, std::move(encrypter)); - std::unique_ptr decrypter = CreateDecrypter(read_secret); - session()->connection()->InstallDecrypter(level, std::move(decrypter)); + CryptoUtils::SetKeyAndIV(Prf(), read_secret, decrypter.get()); + delegate_->OnNewKeysAvailable(level, std::move(decrypter), + /*set_alternative_decrypter=*/false, + /*latch_once_used=*/false, + std::move(encrypter)); } void TlsHandshaker::WriteMessage(EncryptionLevel level, QuicStringPiece data) { 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 7d5b9bcb75f..14503cde549 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 @@ -61,17 +61,13 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate, // Returns the PRF used by the cipher suite negotiated in the TLS handshake. const EVP_MD* Prf(); - std::unique_ptr CreateEncrypter( - const std::vector& pp_secret); - std::unique_ptr CreateDecrypter( - const std::vector& pp_secret); - virtual const TlsConnection* tls_connection() const = 0; SSL* ssl() const { return tls_connection()->ssl(); } QuicCryptoStream* stream() { return stream_; } QuicSession* session() { return session_; } + HandshakerDelegateInterface* delegate() { return delegate_; } // SetEncryptionSecret provides the encryption secret to use at a particular // encryption level. The secrets provided here are the ones from the TLS 1.3 @@ -100,6 +96,7 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate, private: QuicCryptoStream* stream_; QuicSession* session_; + HandshakerDelegateInterface* delegate_; QuicErrorCode parser_error_ = QUIC_NO_ERROR; std::string parser_error_detail_; 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 index c23d56b44eb..a86b5217bfb 100644 --- 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 @@ -177,6 +177,8 @@ class TestQuicCryptoStream : public QuicCryptoStream { pending_writes_.push_back(std::make_pair(std::string(data), level)); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} + const std::vector>& pending_writes() { return pending_writes_; } @@ -223,17 +225,15 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream { public: explicit TestQuicCryptoClientStream(QuicSession* session) : TestQuicCryptoStream(session), - proof_verifier_(new FakeProofVerifier), - ssl_ctx_(TlsClientConnection::CreateSslCtx()), + crypto_config_(std::make_unique(), + /*session_cache*/ nullptr), handshaker_(new TlsClientHandshaker( + QuicServerId("test.example.com", 443, false), this, session, - QuicServerId("test.example.com", 443, false), - proof_verifier_.get(), - ssl_ctx_.get(), crypto_test_utils::ProofVerifyContextForTesting(), - &proof_handler_, - "quic-tester")) {} + &crypto_config_, + &proof_handler_)) {} ~TestQuicCryptoClientStream() override = default; @@ -244,13 +244,12 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream { bool CryptoConnect() { return handshaker_->CryptoConnect(); } FakeProofVerifier* GetFakeProofVerifier() const { - return proof_verifier_.get(); + return static_cast(crypto_config_.proof_verifier()); } private: - std::unique_ptr proof_verifier_; MockProofHandler proof_handler_; - bssl::UniquePtr ssl_ctx_; + QuicCryptoClientConfig crypto_config_; std::unique_ptr handshaker_; }; @@ -272,6 +271,10 @@ class TestQuicCryptoServerStream : public TestQuicCryptoStream { handshaker_->CancelOutstandingCallbacks(); } + void OnPacketDecrypted(EncryptionLevel level) override { + handshaker_->OnPacketDecrypted(level); + } + TlsHandshaker* handshaker() const override { return handshaker_.get(); } FakeProofSource* GetFakeProofSource() const { return proof_source_; } @@ -334,8 +337,8 @@ class TlsHandshakerTest : public QuicTest { EXPECT_TRUE(client_stream_->encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); EXPECT_TRUE(server_stream_->encryption_established()); - EXPECT_TRUE(client_conn_->IsHandshakeConfirmed()); - EXPECT_TRUE(server_conn_->IsHandshakeConfirmed()); + EXPECT_TRUE(client_conn_->IsHandshakeComplete()); + EXPECT_TRUE(server_conn_->IsHandshakeComplete()); const auto& client_crypto_params = client_stream_->crypto_negotiated_params(); @@ -370,17 +373,11 @@ class TlsHandshakerTest : public QuicTest { }; TEST_F(TlsHandshakerTest, CryptoHandshake) { - EXPECT_FALSE(client_conn_->IsHandshakeConfirmed()); - EXPECT_FALSE(server_conn_->IsHandshakeConfirmed()); + 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_session_, - OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED)); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); - EXPECT_CALL(server_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); client_stream_->CryptoConnect(); ExchangeHandshakeMessages(client_stream_, server_stream_); @@ -505,7 +502,7 @@ TEST_F(TlsHandshakerTest, ClientNotSendingALPN) { } TEST_F(TlsHandshakerTest, ClientSendingBadALPN) { - static std::string kTestBadClientAlpn = "bad-client-alpn"; + const std::string kTestBadClientAlpn = "bad-client-alpn"; EXPECT_CALL(client_session_, GetAlpnsToOffer()) .WillOnce(Return(std::vector({kTestBadClientAlpn}))); EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, @@ -539,9 +536,9 @@ TEST_F(TlsHandshakerTest, ClientSendingTooManyALPNs) { } TEST_F(TlsHandshakerTest, ServerRequiresCustomALPN) { - static const std::string kTestAlpn = "An ALPN That Client Did Not Offer"; + const std::string kTestAlpn = "An ALPN That Client Did Not Offer"; EXPECT_CALL(server_session_, SelectAlpn(_)) - .WillOnce([](const std::vector& alpns) { + .WillOnce([kTestAlpn](const std::vector& alpns) { return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); }); EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, @@ -561,23 +558,18 @@ TEST_F(TlsHandshakerTest, ServerRequiresCustomALPN) { TEST_F(TlsHandshakerTest, CustomALPNNegotiation) { EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED)); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); - EXPECT_CALL(server_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); - - static const std::string kTestAlpn = "A Custom ALPN Value"; - static const std::vector kTestAlpns( + + const std::string kTestAlpn = "A Custom ALPN Value"; + const std::vector kTestAlpns( {"foo", "bar", kTestAlpn, "something else"}); EXPECT_CALL(client_session_, GetAlpnsToOffer()) .WillRepeatedly(Return(kTestAlpns)); EXPECT_CALL(server_session_, SelectAlpn(_)) - .WillOnce([](const std::vector& alpns) { - EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns)); - return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); - }); + .WillOnce( + [kTestAlpn, kTestAlpns](const std::vector& alpns) { + EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns)); + return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); + }); EXPECT_CALL(client_session_, OnAlpnSelected(QuicStringPiece(kTestAlpn))); EXPECT_CALL(server_session_, OnAlpnSelected(QuicStringPiece(kTestAlpn))); client_stream_->CryptoConnect(); 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 f08f7817466..24af98daf00 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 @@ -39,11 +39,6 @@ void TlsServerHandshaker::SignatureCallback::Cancel() { handshaker_ = nullptr; } -// static -bssl::UniquePtr TlsServerHandshaker::CreateSslCtx() { - return TlsServerConnection::CreateSslCtx(); -} - TlsServerHandshaker::TlsServerHandshaker(QuicCryptoStream* stream, QuicSession* session, SSL_CTX* ssl_ctx, @@ -114,6 +109,15 @@ bool TlsServerHandshaker::ZeroRttAttempted() const { void TlsServerHandshaker::SetPreviousCachedNetworkParams( CachedNetworkParameters /*cached_network_params*/) {} +void TlsServerHandshaker::OnPacketDecrypted(EncryptionLevel level) { + if (level == ENCRYPTION_HANDSHAKE && + state_ < STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED) { + state_ = STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED; + delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); + } +} + bool TlsServerHandshaker::ShouldSendExpectCTHeader() const { return false; } @@ -257,11 +261,9 @@ void TlsServerHandshaker::FinishHandshake() { QUIC_LOG(INFO) << "Server: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); - session()->NeuterUnencryptedData(); encryption_established_ = true; handshake_confirmed_ = true; - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + delegate()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Fill crypto_negotiated_params_: const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); @@ -269,8 +271,9 @@ void TlsServerHandshaker::FinishHandshake() { crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); } crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); - - session()->connection()->OnHandshakeComplete(); + // TODO(fayang): Replace this with DiscardOldKeys(ENCRYPTION_HANDSHAKE) when + // handshake key discarding settles down. + delegate()->NeuterHandshakeData(); } ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign( 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 829aeaf618b..507324b9ccd 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 @@ -34,10 +34,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker ~TlsServerHandshaker() override; - // Creates and configures an SSL_CTX to be used with a TlsServerHandshaker. - // The caller is responsible for ownership of the newly created struct. - static bssl::UniquePtr CreateSslCtx(); - // From QuicCryptoServerStream::HandshakerDelegate void CancelOutstandingCallbacks() override; bool GetBase64SHA256ClientChannelID(std::string* output) const override; @@ -50,6 +46,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker bool ZeroRttAttempted() const override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; + void OnPacketDecrypted(EncryptionLevel level) override; bool ShouldSendExpectCTHeader() const override; // From QuicCryptoServerStream::HandshakerDelegate and TlsHandshaker @@ -88,7 +85,8 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker TlsConnection::Delegate* ConnectionDelegate() override { return this; } private: - class SignatureCallback : public ProofSource::SignatureCallback { + class QUIC_EXPORT_PRIVATE SignatureCallback + : public ProofSource::SignatureCallback { public: explicit SignatureCallback(TlsServerHandshaker* handshaker); void Run(bool ok, std::string signature) override; @@ -104,6 +102,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker STATE_LISTENING, STATE_SIGNATURE_PENDING, STATE_SIGNATURE_COMPLETE, + STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED, STATE_HANDSHAKE_COMPLETE, STATE_CONNECTION_CLOSED, }; diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc index f258384a46a..3fb5be8379b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc @@ -135,6 +135,14 @@ void UberQuicStreamIdManager::SetLargestPeerCreatedStreamId( largest_peer_created_stream_id); } +QuicStreamId UberQuicStreamIdManager::GetLargestPeerCreatedStreamId( + bool unidirectional) const { + if (unidirectional) { + return unidirectional_stream_id_manager_.largest_peer_created_stream_id(); + } + return bidirectional_stream_id_manager_.largest_peer_created_stream_id(); +} + QuicStreamId UberQuicStreamIdManager::next_outgoing_bidirectional_stream_id() const { return bidirectional_stream_id_manager_.next_outgoing_stream_id(); diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h index a725fdd1285..75fcb9d7d3c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h @@ -73,6 +73,8 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { void SetLargestPeerCreatedStreamId( QuicStreamId largest_peer_created_stream_id); + QuicStreamId GetLargestPeerCreatedStreamId(bool unidirectional) const; + QuicStreamId next_outgoing_bidirectional_stream_id() const; QuicStreamId next_outgoing_unidirectional_stream_id() const; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h index 1c660b5a92c..8e21fcb65db 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h @@ -5,12 +5,13 @@ #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_ #define QUICHE_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_ +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/quic/platform/impl/quic_cert_utils_impl.h" namespace quic { -class QuicCertUtils { +class QUIC_EXPORT_PRIVATE QuicCertUtils { public: static bool ExtractSubjectNameFromDERCert(QuicStringPiece cert, QuicStringPiece* subject_out) { diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_endian.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_endian.h deleted file mode 100644 index 65edd51690f..00000000000 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_endian.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 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. - -#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_ENDIAN_H_ -#define QUICHE_QUIC_PLATFORM_API_QUIC_ENDIAN_H_ - -#include "net/quic/platform/impl/quic_endian_impl.h" - -namespace quic { - -enum Endianness { - NETWORK_BYTE_ORDER, // big endian - HOST_BYTE_ORDER // little endian -}; - -// Provide utility functions that convert from/to network order (big endian) -// to/from host order (can be either little or big endian depending on the -// platform). -class QuicEndian { - 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 QuicEndianImpl::HostToNet16(x); - } - static uint32_t HostToNet32(uint32_t x) { - return QuicEndianImpl::HostToNet32(x); - } - static uint64_t HostToNet64(uint64_t x) { - return QuicEndianImpl::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 QuicEndianImpl::NetToHost16(x); - } - static uint32_t NetToHost32(uint32_t x) { - return QuicEndianImpl::NetToHost32(x); - } - static uint64_t NetToHost64(uint64_t x) { - return QuicEndianImpl::NetToHost64(x); - } - - // Returns true if current host order is little endian. - static bool HostIsLittleEndian() { - return QuicEndianImpl::HostIsLittleEndian(); - } -}; - -} // namespace quic - -#endif // QUICHE_QUIC_PLATFORM_API_QUIC_ENDIAN_H_ diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_endian_test.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_endian_test.cc deleted file mode 100644 index d054d963021..00000000000 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_endian_test.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 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 "net/third_party/quiche/src/quic/platform/api/quic_endian.h" - -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" - -namespace quic { -namespace test { -namespace { - -const uint16_t k16BitTestData = 0xaabb; -const uint16_t k16BitSwappedTestData = 0xbbaa; -const uint32_t k32BitTestData = 0xaabbccdd; -const uint32_t k32BitSwappedTestData = 0xddccbbaa; -const uint64_t k64BitTestData = 0xaabbccdd44332211; -const uint64_t k64BitSwappedTestData = 0x11223344ddccbbaa; - -class QuicEndianTest : public QuicTest {}; - -TEST_F(QuicEndianTest, HostToNet) { - if (QuicEndian::HostIsLittleEndian()) { - EXPECT_EQ(k16BitSwappedTestData, QuicEndian::HostToNet16(k16BitTestData)); - EXPECT_EQ(k32BitSwappedTestData, QuicEndian::HostToNet32(k32BitTestData)); - EXPECT_EQ(k64BitSwappedTestData, QuicEndian::HostToNet64(k64BitTestData)); - } else { - EXPECT_EQ(k16BitTestData, QuicEndian::HostToNet16(k16BitTestData)); - EXPECT_EQ(k32BitTestData, QuicEndian::HostToNet32(k32BitTestData)); - EXPECT_EQ(k64BitTestData, QuicEndian::HostToNet64(k64BitTestData)); - } -} - -TEST_F(QuicEndianTest, NetToHost) { - if (QuicEndian::HostIsLittleEndian()) { - EXPECT_EQ(k16BitTestData, QuicEndian::NetToHost16(k16BitSwappedTestData)); - EXPECT_EQ(k32BitTestData, QuicEndian::NetToHost32(k32BitSwappedTestData)); - EXPECT_EQ(k64BitTestData, QuicEndian::NetToHost64(k64BitSwappedTestData)); - } else { - EXPECT_EQ(k16BitSwappedTestData, - QuicEndian::NetToHost16(k16BitSwappedTestData)); - EXPECT_EQ(k32BitSwappedTestData, - QuicEndian::NetToHost32(k32BitSwappedTestData)); - EXPECT_EQ(k64BitSwappedTestData, - QuicEndian::NetToHost64(k64BitSwappedTestData)); - } -} - -} // namespace -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_export.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_export.h index 8ffd6765259..90696a6fba6 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_export.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_export.h @@ -7,4 +7,11 @@ #include "net/quic/platform/impl/quic_export_impl.h" +// quic_export_impl.h defines the following macros: +// - QUIC_EXPORT is not meant to be used. +// - QUIC_EXPORT_PRIVATE is meant for QUIC functionality that is built in +// Chromium as part of //net, and not fully contained in headers. +// - QUIC_NO_EXPORT is meant for QUIC functionality that is either fully defined +// in a header, or is built in Chromium as part of tests or tools. + #endif // QUICHE_QUIC_PLATFORM_API_QUIC_EXPORT_H_ diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h index d0ed4606cbb..71045e1c30e 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h @@ -12,11 +12,6 @@ namespace quic { -template -std::unique_ptr QuicMakeUnique(Args&&... args) { - return QuicMakeUniqueImpl(std::forward(args)...); -} - template std::unique_ptr QuicWrapUnique(T* ptr) { return QuicWrapUniqueImpl(ptr); diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h index 6ffc237db36..18f6f37f5ab 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h @@ -51,7 +51,7 @@ class QUIC_EXPORT_PRIVATE QuicReferenceCounted // QuicReferenceCountedPointer r_ptr_b = std::move(r_ptr_a); template -class QuicReferenceCountedPointer { +class QUIC_NO_EXPORT QuicReferenceCountedPointer { public: QuicReferenceCountedPointer() = default; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h index 2f3286541a9..f4ef99a3624 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h @@ -23,6 +23,11 @@ using ScopedEnvironmentForThreads = ScopedEnvironmentForThreadsImpl; inline std::string QuicGetTestMemoryCachePath() { return QuicGetTestMemoryCachePathImpl(); + +#define EXPECT_QUIC_DEBUG_DEATH(condition, message) \ + EXPECT_QUIC_DEBUG_DEATH_IMPL(condition, message) } +#define QUIC_SLOW_TEST(test) QUIC_SLOW_TEST_IMPL(test) + #endif // QUICHE_QUIC_PLATFORM_API_QUIC_TEST_H_ diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h index 06be8f7a501..734db63684b 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h @@ -18,7 +18,7 @@ namespace test { // Tests using QuicTestMemSliceVector need to make sure the actual data buffers // outlive QuicTestMemSliceVector, and QuicTestMemSliceVector outlive the // returned QuicMemSliceSpan. -class QuicTestMemSliceVector { +class QUIC_NO_EXPORT QuicTestMemSliceVector { public: explicit QuicTestMemSliceVector(std::vector> buffers) : impl_(std::move(buffers)) {} diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h index 1fa3c72ab16..186368f4f37 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h @@ -7,13 +7,14 @@ #include +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/quic/platform/impl/quic_text_utils_impl.h" namespace quic { // Various utilities for manipulating text. -class QuicTextUtils { +class QUIC_EXPORT_PRIVATE QuicTextUtils { public: // Returns true if |data| starts with |prefix|, case sensitively. static bool StartsWith(QuicStringPiece data, QuicStringPiece prefix) { diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_thread.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_thread.h index 7032dc425af..4b1e5642c58 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_thread.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_thread.h @@ -7,12 +7,13 @@ #include +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/quic/platform/impl/quic_thread_impl.h" namespace quic { // A class representing a thread of execution in QUIC. -class QuicThread : public QuicThreadImpl { +class QUIC_EXPORT_PRIVATE QuicThread : public QuicThreadImpl { public: QuicThread(const std::string& string) : QuicThreadImpl(string) {} QuicThread(const QuicThread&) = delete; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc index 7779a8b212f..a6913d10fd6 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc @@ -7,11 +7,11 @@ #include #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" #include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc index 303f0e280b7..99de19ca9ad 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc @@ -118,7 +118,7 @@ class IcmpReachableTest : public QuicTest { }; TEST_F(IcmpReachableTest, SendsPings) { - IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_, + IcmpReachable reachable(source_, destination_, absl::ZeroDuration(), &kernel_, &epoll_server_, &stats_); SetFdExpectations(); @@ -140,7 +140,7 @@ TEST_F(IcmpReachableTest, SendsPings) { } TEST_F(IcmpReachableTest, HandlesUnreachableEvents) { - IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_, + IcmpReachable reachable(source_, destination_, absl::ZeroDuration(), &kernel_, &epoll_server_, &stats_); SetFdExpectations(); @@ -164,7 +164,7 @@ TEST_F(IcmpReachableTest, HandlesUnreachableEvents) { } TEST_F(IcmpReachableTest, HandlesReachableEvents) { - IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_, + IcmpReachable reachable(source_, destination_, absl::ZeroDuration(), &kernel_, &epoll_server_, &stats_); SetFdExpectations(); @@ -212,7 +212,7 @@ TEST_F(IcmpReachableTest, HandlesReachableEvents) { } TEST_F(IcmpReachableTest, HandlesWriteErrors) { - IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_, + IcmpReachable reachable(source_, destination_, absl::ZeroDuration(), &kernel_, &epoll_server_, &stats_); SetFdExpectations(); @@ -232,7 +232,7 @@ TEST_F(IcmpReachableTest, HandlesWriteErrors) { } TEST_F(IcmpReachableTest, HandlesReadErrors) { - IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_, + IcmpReachable reachable(source_, destination_, absl::ZeroDuration(), &kernel_, &epoll_server_, &stats_); SetFdExpectations(); diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h new file mode 100644 index 00000000000..f74e2a3bd30 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h @@ -0,0 +1,27 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_QBONE_BONNET_MOCK_PACKET_EXCHANGER_STATS_INTERFACE_H_ +#define QUICHE_QUIC_QBONE_BONNET_MOCK_PACKET_EXCHANGER_STATS_INTERFACE_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h" + +namespace quic { + +class MockPacketExchangerStatsInterface + : public TunDevicePacketExchanger::StatsInterface { + public: + MOCK_METHOD0(OnPacketRead, void()); + MOCK_METHOD0(OnPacketWritten, void()); + MOCK_METHOD1(OnReadError, void(string*)); + MOCK_METHOD1(OnWriteError, void(string*)); + + MOCK_CONST_METHOD0(PacketsRead, int64_t()); + MOCK_CONST_METHOD0(PacketsWritten, int64_t()); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_QBONE_BONNET_MOCK_PACKET_EXCHANGER_STATS_INTERFACE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc index 6c0a8a55ed8..e266654892b 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc @@ -30,7 +30,9 @@ TunDevice::TunDevice(const string& interface_name, kernel_(*kernel) {} TunDevice::~TunDevice() { - Down(); + if (!persist_) { + Down(); + } CleanUpFileDescriptor(); } diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc index 799247c0dfa..37fd2c0163b 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc @@ -81,4 +81,9 @@ int TunDevicePacketExchanger::file_descriptor() const { return fd_; } +const TunDevicePacketExchanger::StatsInterface* +TunDevicePacketExchanger::stats_interface() const { + return stats_; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h index 12d9efa714a..42ed7fb5214 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h @@ -30,6 +30,9 @@ class TunDevicePacketExchanger : public QbonePacketExchanger { virtual void OnPacketWritten() = 0; virtual void OnReadError(string* error) = 0; virtual void OnWriteError(string* error) = 0; + + ABSL_MUST_USE_RESULT virtual int64_t PacketsRead() const = 0; + ABSL_MUST_USE_RESULT virtual int64_t PacketsWritten() const = 0; }; // |fd| is a open file descriptor on a TUN device that's opened for both read @@ -48,7 +51,9 @@ class TunDevicePacketExchanger : public QbonePacketExchanger { size_t max_pending_packets, StatsInterface* stats); - int file_descriptor() const; + ABSL_MUST_USE_RESULT int file_descriptor() const; + + ABSL_MUST_USE_RESULT const StatsInterface* stats_interface() const; private: // From QbonePacketExchanger. diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc index 026ec26da5e..0f25e73eab4 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h" #include "net/third_party/quiche/src/quic/qbone/mock_qbone_client.h" #include "net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h" @@ -26,15 +27,6 @@ class MockVisitor : public QbonePacketExchanger::Visitor { MOCK_METHOD1(OnWriteError, void(const string&)); }; -class MockStatsInterface : public TunDevicePacketExchanger::StatsInterface { - public: - MOCK_METHOD0(OnPacketRead, void()); - MOCK_METHOD0(OnPacketWritten, void()); - - MOCK_METHOD1(OnReadError, void(string*)); - MOCK_METHOD1(OnWriteError, void(string*)); -}; - class TunDevicePacketExchangerTest : public QuicTest { protected: TunDevicePacketExchangerTest() @@ -50,7 +42,7 @@ class TunDevicePacketExchangerTest : public QuicTest { MockKernel mock_kernel_; StrictMock mock_visitor_; StrictMock mock_client_; - StrictMock mock_stats_; + StrictMock mock_stats_; TunDevicePacketExchanger exchanger_; }; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc index 8ba3916b951..9039944583c 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc @@ -5,8 +5,9 @@ #include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h" #include -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" + #include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace { @@ -46,7 +47,8 @@ void CreateIcmpPacket(in6_addr src, // Set version to 6. icmp_packet.ip_header.ip6_vfc = 0x6 << 4; // Set the payload size, protocol and TTL. - icmp_packet.ip_header.ip6_plen = QuicEndian::HostToNet16(payload_size); + icmp_packet.ip_header.ip6_plen = + quiche::QuicheEndian::HostToNet16(payload_size); icmp_packet.ip_header.ip6_nxt = IPPROTO_ICMPV6; icmp_packet.ip_header.ip6_hops = kIcmpTtl; // Set the source address to the specified self IP. @@ -58,7 +60,7 @@ void CreateIcmpPacket(in6_addr src, icmp_packet.icmp_header.icmp6_cksum = 0; IPv6PseudoHeader pseudo_header{}; - pseudo_header.payload_size = QuicEndian::HostToNet32(payload_size); + pseudo_header.payload_size = quiche::QuicheEndian::HostToNet32(payload_size); InternetChecksum checksum; // Pseudoheader. diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc index 9cbe227abdc..b98c85767b4 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc index 15ebb726b86..03ad6407996 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc @@ -4,7 +4,7 @@ #include "net/third_party/quiche/src/quic/qbone/platform/ip_range.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { @@ -23,9 +23,9 @@ QuicIpAddress TruncateToLength(const QuicIpAddress& input, } uint32_t raw_address = *reinterpret_cast(input.ToPackedString().data()); - raw_address = QuicEndian::NetToHost32(raw_address); + raw_address = quiche::QuicheEndian::NetToHost32(raw_address); raw_address &= ~0U << (kIPv4Size - *prefix_length); - raw_address = QuicEndian::HostToNet32(raw_address); + raw_address = quiche::QuicheEndian::HostToNet32(raw_address); output.FromPackedString(reinterpret_cast(&raw_address), sizeof(raw_address)); return output; @@ -42,16 +42,16 @@ QuicIpAddress TruncateToLength(const QuicIpAddress& input, // out. // The endianess between raw_address[0] and raw_address[1] is handled // explicitly by handling lower and higher bytes separately. - raw_address[0] = QuicEndian::NetToHost64(raw_address[0]); - raw_address[1] = QuicEndian::NetToHost64(raw_address[1]); + raw_address[0] = quiche::QuicheEndian::NetToHost64(raw_address[0]); + raw_address[1] = quiche::QuicheEndian::NetToHost64(raw_address[1]); if (*prefix_length <= kIPv6Size / 2) { raw_address[0] &= ~uint64_t{0} << (kIPv6Size / 2 - *prefix_length); raw_address[1] = 0; } else { raw_address[1] &= ~uint64_t{0} << (kIPv6Size - *prefix_length); } - raw_address[0] = QuicEndian::HostToNet64(raw_address[0]); - raw_address[1] = QuicEndian::HostToNet64(raw_address[1]); + raw_address[0] = quiche::QuicheEndian::HostToNet64(raw_address[0]); + raw_address[1] = quiche::QuicheEndian::HostToNet64(raw_address[1]); output.FromPackedString(reinterpret_cast(raw_address), sizeof(raw_address)); return output; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc index 7bd5f6b8563..04ce68cd9a9 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc @@ -45,7 +45,7 @@ class NetlinkTest : public QuicTest { InSequence s; EXPECT_CALL(mock_kernel_, sendmsg(kSocketFd, _, _)) - .WillOnce(Invoke([this, type, flags, send_callback]( + .WillOnce(Invoke([type, flags, send_callback]( Unused, const struct msghdr* msg, int) { EXPECT_EQ(sizeof(struct sockaddr_nl), msg->msg_namelen); auto* nl_addr = @@ -251,7 +251,7 @@ TEST_F(NetlinkTest, GetLinkInfoWorks) { ExpectNetlinkPacket( RTM_GETLINK, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST, - [this, &hwaddr, &bcaddr](void* buf, size_t len, int seq) { + [&hwaddr, &bcaddr](void* buf, size_t len, int seq) { int ret = 0; struct nlmsghdr* netlink_message = @@ -291,7 +291,7 @@ TEST_F(NetlinkTest, GetAddressesWorks) { ExpectNetlinkPacket( RTM_GETADDR, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST, - [this, &addresses](void* buf, size_t len, int seq) { + [&addresses](void* buf, size_t len, int seq) { int ret = 0; struct nlmsghdr* nlm = nullptr; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc index 56fa88ab2d3..2566d25eded 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc @@ -6,9 +6,9 @@ #include -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace quic { namespace { @@ -45,8 +45,8 @@ void CreateTcpResetPacket( if (QUIC_PREDICT_FALSE(ip6_header->ip6_nxt != IPPROTO_TCP)) { return; } - if (QUIC_PREDICT_FALSE(QuicEndian::NetToHost16(ip6_header->ip6_plen) < - sizeof(tcphdr))) { + if (QUIC_PREDICT_FALSE(quiche::QuicheEndian::NetToHost16( + ip6_header->ip6_plen) < sizeof(tcphdr))) { return; } auto* tcp_header = reinterpret_cast(ip6_header + 1); @@ -60,7 +60,8 @@ void CreateTcpResetPacket( // Set version to 6. tcp_packet.ip_header.ip6_vfc = 0x6 << 4; // Set the payload size, protocol and TTL. - tcp_packet.ip_header.ip6_plen = QuicEndian::HostToNet16(payload_size); + tcp_packet.ip_header.ip6_plen = + quiche::QuicheEndian::HostToNet16(payload_size); tcp_packet.ip_header.ip6_nxt = IPPROTO_TCP; tcp_packet.ip_header.ip6_hops = kTcpTtl; // Since the TCP RST is impersonating the endpoint, flip the source and @@ -98,12 +99,12 @@ void CreateTcpResetPacket( // the sum of the sequence number and segment length of the incoming segment tcp_packet.tcp_header.ack = 1; tcp_packet.tcp_header.seq = 0; - tcp_packet.tcp_header.ack_seq = - QuicEndian::HostToNet32(QuicEndian::NetToHost32(tcp_header->seq) + 1); + tcp_packet.tcp_header.ack_seq = quiche::QuicheEndian::HostToNet32( + quiche::QuicheEndian::NetToHost32(tcp_header->seq) + 1); } TCPv6PseudoHeader pseudo_header{}; - pseudo_header.payload_size = QuicEndian::HostToNet32(payload_size); + pseudo_header.payload_size = quiche::QuicheEndian::HostToNet32(payload_size); InternetChecksum checksum; // Pseudoheader. diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc index e585d058386..95e3aeaf090 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc @@ -40,7 +40,8 @@ QboneClient::QboneClient(QuicSocketAddress server_address, new QuicEpollConnectionHelper(epoll_server, QuicAllocator::SIMPLE), new QuicEpollAlarmFactory(epoll_server), CreateNetworkHelper(epoll_server, this), - std::move(proof_verifier)), + std::move(proof_verifier), + nullptr), qbone_writer_(qbone_writer), qbone_handler_(qbone_handler), session_owner_(session_owner) { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc index db7a1382a8f..39b622b4de5 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc @@ -7,11 +7,11 @@ #include #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h" #include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h" #include "net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" namespace { @@ -171,7 +171,7 @@ QbonePacketProcessor::ProcessingResult QbonePacketProcessor::ProcessIPv6Header( // Check payload size. const size_t declared_payload_size = - QuicEndian::NetToHost16(header->ip6_plen); + quiche::QuicheEndian::NetToHost16(header->ip6_plen); const size_t actual_payload_size = packet->size() - kIPv6HeaderSize; if (declared_payload_size != actual_payload_size) { QUIC_DVLOG(1) diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc index 62bcaa4a511..c3e7731bcd0 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc @@ -4,11 +4,15 @@ #include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h" +#include +#include + #include #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h" +#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h" #include "net/third_party/quiche/src/quic/qbone/qbone_constants.h" namespace quic { @@ -137,12 +141,41 @@ void QboneSessionBase::SendPacketToPeer(QuicStringPiece packet) { QuicMemSlice slice(connection()->helper()->GetStreamSendBufferAllocator(), packet.size()); memcpy(const_cast(slice.data()), packet.data(), packet.size()); - if (SendMessage(QuicMemSliceSpan(&slice)).status == - MESSAGE_STATUS_SUCCESS) { - return; + switch (SendMessage(QuicMemSliceSpan(&slice), /*flush=*/true).status) { + case MESSAGE_STATUS_SUCCESS: + break; + case MESSAGE_STATUS_TOO_LARGE: { + if (packet.size() < sizeof(ip6_hdr)) { + QUIC_BUG << "Dropped malformed packet: IPv6 header too short"; + break; + } + auto* header = reinterpret_cast(packet.begin()); + icmp6_hdr icmp_header{}; + icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG; + icmp_header.icmp6_mtu = + connection()->GetGuaranteedLargestMessagePayload(); + + CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet, + [this](QuicStringPiece icmp_packet) { + writer_->WritePacketToNetwork(icmp_packet.data(), + icmp_packet.size()); + }); + break; + } + case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED: + QUIC_BUG << "MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED"; + break; + case MESSAGE_STATUS_UNSUPPORTED: + QUIC_BUG << "MESSAGE_STATUS_UNSUPPORTED"; + break; + case MESSAGE_STATUS_BLOCKED: + QUIC_BUG << "MESSAGE_STATUS_BLOCKED"; + break; + case MESSAGE_STATUS_INTERNAL_ERROR: + QUIC_BUG << "MESSAGE_STATUS_INTERNAL_ERROR"; + break; } - // If SendMessage() fails for any reason, fall back to ephemeral streams. - num_fallback_to_stream_++; + return; } // Qbone streams are ephemeral. diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc index 83ee0877683..19ecd2c54fe 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc @@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h" #include "net/third_party/quiche/src/quic/qbone/qbone_client_session.h" #include "net/third_party/quiche/src/quic/qbone/qbone_constants.h" #include "net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.pb.h" @@ -170,7 +171,7 @@ class DataSavingQboneControlHandler : public QboneControlHandler { class FakeTaskRunner { public: explicit FakeTaskRunner(MockQuicConnectionHelper* helper) - : tasks_([this](const TaskType& l, const TaskType& r) { + : tasks_([](const TaskType& l, const TaskType& r) { // Items at a later time should run after items at an earlier time. // Priority queue comparisons should return true if l appears after r. return l->time() > r->time(); @@ -298,7 +299,7 @@ class QboneSessionTest : public QuicTest { server_crypto_config_->GenerateConfig(QuicRandom::GetInstance(), GetClock(), options); std::unique_ptr message( - server_crypto_config_->AddConfig(std::move(primary_config), + server_crypto_config_->AddConfig(primary_config, GetClock()->WallNow())); server_peer_ = std::make_unique( @@ -353,6 +354,23 @@ class QboneSessionTest : public QuicTest { runner_.Run(); } + void ExpectICMPTooBigResponse(const std::vector& written_packets, + const int mtu, + const string& packet) { + auto* header = reinterpret_cast(packet.data()); + icmp6_hdr icmp_header{}; + icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG; + icmp_header.icmp6_mtu = mtu; + + string expected; + CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet, + [&expected](QuicStringPiece icmp_packet) { + expected = string(icmp_packet); + }); + + EXPECT_THAT(written_packets, Contains(expected)); + } + // Test handshake establishment and sending/receiving of data for two // directions. void TestStreamConnection(bool use_messages) { @@ -395,7 +413,14 @@ class QboneSessionTest : public QuicTest { QUIC_LOG(INFO) << "Sending server -> client long data"; server_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data)); runner_.Run(); - EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data))); + if (use_messages) { + ExpectICMPTooBigResponse( + server_writer_->data(), + server_peer_->connection()->GetGuaranteedLargestMessagePayload(), + TestPacketOut(long_data)); + } else { + EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data))); + } EXPECT_THAT(server_writer_->data(), Not(Contains(TestPacketOut(long_data)))); EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); @@ -404,11 +429,22 @@ class QboneSessionTest : public QuicTest { QUIC_LOG(INFO) << "Sending client -> server long data"; client_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data)); runner_.Run(); - EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data))); + if (use_messages) { + ExpectICMPTooBigResponse( + client_writer_->data(), + client_peer_->connection()->GetGuaranteedLargestMessagePayload(), + TestPacketIn(long_data)); + } else { + EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data))); + } EXPECT_THAT(client_peer_->GetNumSentClientHellos(), Eq(2)); EXPECT_THAT(client_peer_->GetNumReceivedServerConfigUpdates(), Eq(0)); - EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1)); - EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1)); + + if (!use_messages) { + EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1)); + EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1)); + } + if (use_messages) { EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(0)); EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(0)); diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc index 165139c46f1..8506067f13d 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" #include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h" #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" @@ -195,7 +196,8 @@ TEST_F(QuartcEndpointTest, return client_endpoint_delegate_.session() != nullptr && client_endpoint_delegate_.session()->error() != QUIC_NO_ERROR; })); - EXPECT_EQ(client_endpoint_delegate_.session()->error(), QUIC_INVALID_VERSION); + EXPECT_THAT(client_endpoint_delegate_.session()->error(), + test::IsError(QUIC_INVALID_VERSION)); } // Tests that the client endpoint can create a new session in order to continue diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc index 413c4f83f74..ad677fd8c94 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc @@ -63,11 +63,8 @@ void ConfigureGlobalQuicSettings() { // Fixes behavior of StopReading() with level-triggered stream sequencers. SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true); - // Enable version 47 to enable variable-length connection ids. - SetQuicReloadableFlag(quic_enable_version_47, true); - - // Enable version 48 to be compatible with the latest version of Chrome. - SetQuicReloadableFlag(quic_enable_version_48_2, true); + // Enable version 50 to be compatible with the latest version of Chrome. + SetQuicReloadableFlag(quic_enable_version_50, true); // Ensure that we don't drop data because QUIC streams refuse to buffer it. // TODO(b/120099046): Replace this with correct handling of WriteMemSlices(). @@ -98,7 +95,7 @@ QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { // In exoblaze this may return false. DCHECK to avoid problems caused by // incorrect flags configuration. - DCHECK(GetQuicReloadableFlag(quic_enable_version_47)) + DCHECK(GetQuicReloadableFlag(quic_enable_version_50)) << "Your build does not support quic reloadable flags and shouldn't " "place Quartc calls"; diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc index a8f53528e5e..3cc088b4da1 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc @@ -23,6 +23,7 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_session.h" #include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" @@ -468,8 +469,10 @@ TEST_F(QuartcMultiplexerTest, CloseEvent) { Connect(); Disconnect(); - EXPECT_EQ(client_session_delegate_.error(), QUIC_CONNECTION_CANCELLED); - EXPECT_EQ(server_session_delegate_.error(), QUIC_CONNECTION_CANCELLED); + EXPECT_THAT(client_session_delegate_.error(), + test::IsError(QUIC_CONNECTION_CANCELLED)); + EXPECT_THAT(server_session_delegate_.error(), + test::IsError(QUIC_CONNECTION_CANCELLED)); } TEST_F(QuartcMultiplexerTest, CongestionEvent) { diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc index 5ffb892ef44..f67cc774ea8 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc @@ -29,7 +29,7 @@ WriteResult QuartcPacketWriter::WritePacket( static_cast(options); if (quartc_options && quartc_options->connection) { info.packet_number = - quartc_options->connection->packet_generator().packet_number(); + quartc_options->connection->packet_creator().packet_number(); } int bytes_written = packet_transport_->Write(buffer, buf_len, info); if (bytes_written <= 0) { diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc index 0868d72adbe..654e54081aa 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc @@ -175,6 +175,36 @@ void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { } } +void QuartcSession::SetDefaultEncryptionLevel(EncryptionLevel level) { + QuicSession::SetDefaultEncryptionLevel(level); + switch (level) { + case ENCRYPTION_INITIAL: + break; + case ENCRYPTION_ZERO_RTT: + if (connection()->perspective() == Perspective::IS_CLIENT) { + DCHECK(IsEncryptionEstablished()); + DCHECK(session_delegate_); + session_delegate_->OnConnectionWritable(); + } + break; + case ENCRYPTION_HANDSHAKE: + break; + case ENCRYPTION_FORWARD_SECURE: + // On the server, handshake confirmed is the first time when you can start + // writing packets. + DCHECK(IsEncryptionEstablished()); + DCHECK(IsCryptoHandshakeConfirmed()); + + DCHECK(session_delegate_); + session_delegate_->OnConnectionWritable(); + session_delegate_->OnCryptoHandshakeComplete(); + break; + default: + QUIC_BUG << "Unknown encryption level: " + << EncryptionLevelToString(level); + } +} + void QuartcSession::CancelStream(QuicStreamId stream_id) { ResetStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h index e9001d635d9..1c0fd317b4c 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h @@ -74,6 +74,7 @@ class QuartcSession : public QuicSession, } void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(EncryptionLevel level) override; // QuicConnectionVisitorInterface overrides. void OnCongestionWindowChange(QuicTime now) override; diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc index 6ed8ec514e2..956073bade9 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc @@ -20,6 +20,7 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" @@ -543,10 +544,10 @@ TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) { EXPECT_TRUE(client_peer_->IsClosedStream(stream_id)); EXPECT_TRUE(server_peer_->IsClosedStream(stream_id)); - EXPECT_EQ(client_stream_delegate_->stream_error(stream_id), - QUIC_STREAM_CANCELLED); - EXPECT_EQ(server_stream_delegate_->stream_error(stream_id), - QUIC_STREAM_CANCELLED); + EXPECT_THAT(client_stream_delegate_->stream_error(stream_id), + test::IsStreamError(QUIC_STREAM_CANCELLED)); + EXPECT_THAT(server_stream_delegate_->stream_error(stream_id), + test::IsStreamError(QUIC_STREAM_CANCELLED)); } TEST_F(QuartcSessionTest, LostDatagramNotifications) { diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc index c8a68fcefff..0e972e50aff 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc @@ -27,7 +27,6 @@ #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h" #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.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" @@ -36,8 +35,12 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" +using ::quic::test::IsQuicStreamNoError; +using ::quic::test::IsStreamError; + namespace quic { namespace { @@ -73,7 +76,7 @@ class MockQuicSession : public QuicSession { // WritevData does not pass down a iovec, data is saved in stream before // data is consumed. Retrieve data from stream. char* buf = new char[write_length]; - QuicDataWriter writer(write_length, buf, NETWORK_BYTE_ORDER); + QuicDataWriter writer(write_length, buf, quiche::NETWORK_BYTE_ORDER); if (write_length > 0) { stream->WriteStreamData(offset, write_length, &writer); } @@ -419,7 +422,7 @@ TEST_F(QuartcStreamTest, TestCancelOnLossDisabled) { stream_->OnCanWrite(); EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); } TEST_F(QuartcStreamTest, TestCancelOnLossEnabled) { @@ -436,7 +439,7 @@ TEST_F(QuartcStreamTest, TestCancelOnLossEnabled) { stream_->OnCanWrite(); EXPECT_EQ("Foo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED); + EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); } TEST_F(QuartcStreamTest, MaxRetransmissionsAbsent) { @@ -456,7 +459,7 @@ TEST_F(QuartcStreamTest, MaxRetransmissionsAbsent) { stream_->OnCanWrite(); EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); } TEST_F(QuartcStreamTest, MaxRetransmissionsSet) { @@ -483,7 +486,7 @@ TEST_F(QuartcStreamTest, MaxRetransmissionsSet) { stream_->OnCanWrite(); EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED); + EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); } TEST_F(QuartcStreamTest, MaxRetransmissionsDisjointFrames) { @@ -542,7 +545,7 @@ TEST_F(QuartcStreamTest, MaxRetransmissionsOverlappingFrames) { stream_->OnCanWrite(); EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED); + EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); } TEST_F(QuartcStreamTest, MaxRetransmissionsWithAckedFrame) { @@ -579,7 +582,7 @@ TEST_F(QuartcStreamTest, MaxRetransmissionsWithAckedFrame) { // QuartcStream should be cancelled, but it stopped tracking the lost bytes // after they were acked, so it's not. - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); } TEST_F(QuartcStreamTest, TestBytesPendingRetransmission) { @@ -605,7 +608,7 @@ TEST_F(QuartcStreamTest, TestBytesPendingRetransmission) { EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u); EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR); + EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); } TEST_F(QuartcStreamTest, TestBytesPendingRetransmissionWithCancelOnLoss) { @@ -631,7 +634,7 @@ TEST_F(QuartcStreamTest, TestBytesPendingRetransmissionWithCancelOnLoss) { EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u); EXPECT_EQ("Foo bar", write_buffer_); - EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED); + EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc index 032f61d3bcb..e9487ec0458 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc @@ -16,9 +16,12 @@ #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" namespace quic { @@ -40,15 +43,18 @@ QuicTransportClientSession::QuicTransportClientSession( Visitor* owner, const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, - const QuicServerId& server_id, + const GURL& url, QuicCryptoClientConfig* crypto_config, - url::Origin origin) + url::Origin origin, + ClientVisitor* visitor) : QuicSession(connection, owner, config, supported_versions, /*num_expected_unidirectional_static_streams*/ 0), - origin_(origin) { + url_(url), + origin_(origin), + visitor_(visitor) { for (const ParsedQuicVersion& version : supported_versions) { QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3) << "QuicTransport requires TLS 1.3 handshake"; @@ -56,8 +62,22 @@ QuicTransportClientSession::QuicTransportClientSession( // ProofHandler API is not used by TLS 1.3. static DummyProofHandler* proof_handler = new DummyProofHandler(); crypto_stream_ = std::make_unique( - server_id, this, crypto_config->proof_verifier()->CreateDefaultContext(), - crypto_config, proof_handler); + QuicServerId(url.host(), url.EffectiveIntPort()), this, + crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config, + proof_handler); +} + +QuicStream* QuicTransportClientSession::CreateIncomingStream(QuicStreamId id) { + QUIC_DVLOG(1) << "Creating incoming QuicTransport stream " << id; + QuicTransportStream* stream = CreateStream(id); + if (stream->type() == BIDIRECTIONAL) { + incoming_bidirectional_streams_.push_back(stream); + visitor_->OnIncomingBidirectionalStreamAvailable(); + } else { + incoming_unidirectional_streams_.push_back(stream); + visitor_->OnIncomingUnidirectionalStreamAvailable(); + } + return stream; } void QuicTransportClientSession::OnCryptoHandshakeEvent( @@ -70,6 +90,59 @@ void QuicTransportClientSession::OnCryptoHandshakeEvent( SendClientIndication(); } +void QuicTransportClientSession::SetDefaultEncryptionLevel( + EncryptionLevel level) { + QuicSession::SetDefaultEncryptionLevel(level); + if (level == ENCRYPTION_FORWARD_SECURE) { + SendClientIndication(); + } +} + +QuicTransportStream* +QuicTransportClientSession::AcceptIncomingBidirectionalStream() { + if (incoming_bidirectional_streams_.empty()) { + return nullptr; + } + QuicTransportStream* stream = incoming_bidirectional_streams_.front(); + incoming_bidirectional_streams_.pop_front(); + return stream; +} + +QuicTransportStream* +QuicTransportClientSession::AcceptIncomingUnidirectionalStream() { + if (incoming_unidirectional_streams_.empty()) { + return nullptr; + } + QuicTransportStream* stream = incoming_unidirectional_streams_.front(); + incoming_unidirectional_streams_.pop_front(); + return stream; +} + +QuicTransportStream* +QuicTransportClientSession::OpenOutgoingBidirectionalStream() { + if (!CanOpenNextOutgoingBidirectionalStream()) { + QUIC_BUG << "Attempted to open a stream in violation of flow control"; + return nullptr; + } + return CreateStream(GetNextOutgoingBidirectionalStreamId()); +} + +QuicTransportStream* +QuicTransportClientSession::OpenOutgoingUnidirectionalStream() { + if (!CanOpenNextOutgoingUnidirectionalStream()) { + QUIC_BUG << "Attempted to open a stream in violation of flow control"; + return nullptr; + } + return CreateStream(GetNextOutgoingUnidirectionalStreamId()); +} + +QuicTransportStream* QuicTransportClientSession::CreateStream(QuicStreamId id) { + auto stream = std::make_unique(id, this, this); + QuicTransportStream* stream_ptr = stream.get(); + ActivateStream(std::move(stream)); + return stream_ptr; +} + std::string QuicTransportClientSession::SerializeClientIndication() { std::string serialized_origin = origin_.Serialize(); if (serialized_origin.size() > std::numeric_limits::max()) { @@ -82,16 +155,40 @@ std::string QuicTransportClientSession::SerializeClientIndication() { QUIC_DLOG(INFO) << "Sending client indication with origin " << serialized_origin; + std::string path = url_.PathForRequest(); + if (path.size() > std::numeric_limits::max()) { + connection()->CloseConnection( + QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, "Requested URL path too long", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return ""; + } + + constexpr size_t kPrefixSize = + sizeof(QuicTransportClientIndicationKeys) + sizeof(uint16_t); + const size_t buffer_size = + 2 * kPrefixSize + serialized_origin.size() + path.size(); + if (buffer_size > std::numeric_limits::max()) { + connection()->CloseConnection( + QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, + "Client indication size limit exceeded", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return ""; + } + std::string buffer; - buffer.resize(/* key */ sizeof(QuicTransportClientIndicationKeys) + - /* length */ sizeof(uint16_t) + serialized_origin.size()); + buffer.resize(buffer_size); QuicDataWriter writer(buffer.size(), &buffer[0]); - writer.WriteUInt16( - static_cast(QuicTransportClientIndicationKeys::kOrigin)); - writer.WriteUInt16(serialized_origin.size()); - writer.WriteStringPiece(serialized_origin); - - buffer.resize(writer.length()); + bool success = + writer.WriteUInt16( + static_cast(QuicTransportClientIndicationKeys::kOrigin)) && + writer.WriteUInt16(serialized_origin.size()) && + writer.WriteStringPiece(serialized_origin) && + writer.WriteUInt16( + static_cast(QuicTransportClientIndicationKeys::kPath)) && + writer.WriteUInt16(path.size()) && writer.WriteStringPiece(path); + QUIC_BUG_IF(!success) << "Failed to serialize client indication"; + QUIC_BUG_IF(writer.length() != buffer.length()) + << "Serialized client indication has length different from expected"; return buffer; } @@ -113,8 +210,11 @@ void QuicTransportClientSession::SendClientIndication() { } auto client_indication_owned = std::make_unique( - /*stream_id=*/ClientIndicationStream(), this, /*is_static=*/false, - WRITE_UNIDIRECTIONAL); + /*stream_id=*/GetNextOutgoingUnidirectionalStreamId(), this, + /*is_static=*/false, WRITE_UNIDIRECTIONAL); + QUIC_BUG_IF(client_indication_owned->id() != ClientIndicationStream()) + << "Client indication stream is " << client_indication_owned->id() + << " instead of expected " << ClientIndicationStream(); ClientIndication* client_indication = client_indication_owned.get(); ActivateStream(std::move(client_indication_owned)); diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h index 32149dfbb00..b3d8f17186b 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h @@ -8,6 +8,7 @@ #include #include +#include "url/gurl.h" #include "url/origin.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" @@ -19,24 +20,38 @@ #include "net/third_party/quiche/src/quic/core/quic_stream.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #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_string_piece.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" namespace quic { // A client session for the QuicTransport protocol. -class QUIC_EXPORT QuicTransportClientSession +class QUIC_EXPORT_PRIVATE QuicTransportClientSession : public QuicSession, public QuicTransportSessionInterface { public: + class QUIC_EXPORT_PRIVATE ClientVisitor { + public: + virtual ~ClientVisitor() {} + + // Notifies the visitor when a new stream has been received. The stream in + // question can be retrieved using AcceptIncomingBidirectionalStream() or + // AcceptIncomingUnidirectionalStream(). + virtual void OnIncomingBidirectionalStreamAvailable() = 0; + virtual void OnIncomingUnidirectionalStreamAvailable() = 0; + }; + QuicTransportClientSession(QuicConnection* connection, Visitor* owner, const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, - const QuicServerId& server_id, + const GURL& url, QuicCryptoClientConfig* crypto_config, - url::Origin origin); + url::Origin origin, + ClientVisitor* visitor); std::vector GetAlpnsToOffer() const override { return std::vector({QuicTransportAlpn()}); @@ -53,12 +68,35 @@ class QUIC_EXPORT QuicTransportClientSession return crypto_stream_.get(); } + // Returns true once the encryption has been established and the client + // indication has been sent. No application data will be read or written + // before the connection is ready. Once the connection becomes ready, this + // method will never return false. bool IsSessionReady() const override { return ready_; } + QuicStream* CreateIncomingStream(QuicStreamId id) override; + QuicStream* CreateIncomingStream(PendingStream* /*pending*/) override { + QUIC_BUG << "QuicTransportClientSession::CreateIncomingStream(" + "PendingStream) not implemented"; + return nullptr; + } + void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(EncryptionLevel level) override; + + // Return the earliest incoming stream that has been received by the session + // but has not been accepted. Returns nullptr if there are no incoming + // streams. + QuicTransportStream* AcceptIncomingBidirectionalStream(); + QuicTransportStream* AcceptIncomingUnidirectionalStream(); + + using QuicSession::CanOpenNextOutgoingBidirectionalStream; + using QuicSession::CanOpenNextOutgoingUnidirectionalStream; + QuicTransportStream* OpenOutgoingBidirectionalStream(); + QuicTransportStream* OpenOutgoingUnidirectionalStream(); protected: - class ClientIndication : public QuicStream { + class QUIC_EXPORT_PRIVATE ClientIndication : public QuicStream { public: using QuicStream::QuicStream; @@ -69,6 +107,9 @@ class QUIC_EXPORT QuicTransportClientSession } }; + // Creates and activates a QuicTransportStream for the given ID. + QuicTransportStream* CreateStream(QuicStreamId id); + // Serializes the client indication as described in // https://vasilvv.github.io/webtransport/draft-vvv-webtransport-quic.html#rfc.section.3.2 std::string SerializeClientIndication(); @@ -76,9 +117,22 @@ class QUIC_EXPORT QuicTransportClientSession void SendClientIndication(); std::unique_ptr crypto_stream_; + GURL url_; url::Origin origin_; + ClientVisitor* visitor_; // not owned bool client_indication_sent_ = false; bool ready_ = false; + + // Contains all of the streams that has been received by the session but have + // not been processed by the application. + // TODO(vasilvv): currently, we always send MAX_STREAMS as long as the overall + // maximum number of streams for the connection has not been exceeded. We + // should also limit the maximum number of streams that the consuming code + // has not accepted to a smaller number, by checking the size of + // |incoming_bidirectional_streams_| and |incoming_unidirectional_streams_| + // before sending MAX_STREAMS. + QuicDeque incoming_bidirectional_streams_; + QuicDeque incoming_unidirectional_streams_; }; } // namespace quic 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 24e1071d3e9..17a475751d6 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 @@ -20,6 +20,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h" namespace quic { namespace test { @@ -29,8 +30,6 @@ using testing::_; using testing::ElementsAre; const char* kTestOrigin = "https://test-origin.test"; -constexpr char kTestOriginClientIndication[] = - "\0\0\0\x18https://test-origin.test"; url::Origin GetTestOrigin() { GURL origin_url(kTestOrigin); return url::Origin::Create(origin_url); @@ -50,32 +49,6 @@ std::string DataInStream(QuicStream* stream) { return result; } -class TestClientSession : public QuicTransportClientSession { - public: - using QuicTransportClientSession::QuicTransportClientSession; - - class Stream : public QuicStream { - public: - using QuicStream::QuicStream; - void OnDataAvailable() override {} - }; - - QuicStream* CreateIncomingStream(QuicStreamId id) override { - auto stream = std::make_unique( - id, this, /*is_static=*/false, - QuicUtils::GetStreamType(id, connection()->perspective(), - /*peer_initiated=*/true)); - QuicStream* result = stream.get(); - ActivateStream(std::move(stream)); - return result; - } - - QuicStream* CreateIncomingStream(PendingStream* /*pending*/) override { - QUIC_NOTREACHED(); - return nullptr; - } -}; - class QuicTransportClientSessionTest : public QuicTest { protected: QuicTransportClientSessionTest() @@ -83,16 +56,16 @@ class QuicTransportClientSessionTest : public QuicTest { &alarm_factory_, Perspective::IS_CLIENT, GetVersions()), - server_id_("test.example.com", 443), crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { SetQuicReloadableFlag(quic_supports_tls_handshake, true); - CreateSession(GetTestOrigin()); + CreateSession(GetTestOrigin(), ""); } - void CreateSession(url::Origin origin) { - session_ = std::make_unique( - &connection_, nullptr, DefaultQuicConfig(), GetVersions(), server_id_, - &crypto_config_, origin); + void CreateSession(url::Origin origin, std::string url_suffix) { + session_ = std::make_unique( + &connection_, nullptr, DefaultQuicConfig(), GetVersions(), + GURL("quic-transport://test.example.com:50000" + url_suffix), + &crypto_config_, origin, &visitor_); session_->Initialize(); crypto_stream_ = static_cast( session_->GetMutableCryptoStream()); @@ -101,18 +74,20 @@ class QuicTransportClientSessionTest : public QuicTest { void Connect() { session_->CryptoConnect(); QuicConfig server_config = DefaultQuicConfig(); + std::unique_ptr crypto_config( + crypto_test_utils::CryptoServerConfigForTesting()); crypto_test_utils::HandshakeWithFakeServer( - &server_config, &helper_, &alarm_factory_, &connection_, crypto_stream_, - QuicTransportAlpn()); + &server_config, crypto_config.get(), &helper_, &alarm_factory_, + &connection_, crypto_stream_, QuicTransportAlpn()); } MockAlarmFactory alarm_factory_; MockQuicConnectionHelper helper_; PacketSavingConnection connection_; - QuicServerId server_id_; QuicCryptoClientConfig crypto_config_; - std::unique_ptr session_; + MockClientVisitor visitor_; + std::unique_ptr session_; QuicCryptoClientStream* crypto_stream_; }; @@ -121,6 +96,39 @@ TEST_F(QuicTransportClientSessionTest, HasValidAlpn) { } TEST_F(QuicTransportClientSessionTest, SuccessfulConnection) { + constexpr char kTestOriginClientIndication[] = + "\0\0" // key (0x0000, origin) + "\0\x18" // length + "https://test-origin.test" // value + "\0\x01" // key (0x0001, path) + "\0\x01" // length + "/"; // value + + Connect(); + EXPECT_TRUE(session_->IsSessionReady()); + + QuicStream* client_indication_stream = + QuicSessionPeer::zombie_streams(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{ + kTestOriginClientIndication, + QUIC_ARRAYSIZE(kTestOriginClientIndication) - 1}; + EXPECT_EQ(client_indication, expected_client_indication); +} + +TEST_F(QuicTransportClientSessionTest, SuccessfulConnectionWithPath) { + constexpr char kSuffix[] = "/foo/bar?hello=world#not-sent"; + constexpr char kTestOriginClientIndication[] = + "\0\0" // key (0x0000, origin) + "\0\x18" // length + "https://test-origin.test" // value + "\0\x01" // key (0x0001, path) + "\0\x14" // length + "/foo/bar?hello=world"; // value + + CreateSession(GetTestOrigin(), kSuffix); Connect(); EXPECT_TRUE(session_->IsSessionReady()); @@ -139,11 +147,28 @@ TEST_F(QuicTransportClientSessionTest, OriginTooLong) { std::string long_string(68000, 'a'); GURL bad_origin_url{"https://" + long_string + ".example/"}; EXPECT_TRUE(bad_origin_url.is_valid()); - CreateSession(url::Origin::Create(bad_origin_url)); + CreateSession(url::Origin::Create(bad_origin_url), ""); EXPECT_QUIC_BUG(Connect(), "Client origin too long"); } +TEST_F(QuicTransportClientSessionTest, ReceiveNewStreams) { + Connect(); + ASSERT_TRUE(session_->IsSessionReady()); + ASSERT_TRUE(session_->AcceptIncomingUnidirectionalStream() == nullptr); + + const QuicStreamId id = GetNthServerInitiatedUnidirectionalStreamId( + session_->transport_version(), 0); + QuicStreamFrame frame(id, /*fin=*/false, /*offset=*/0, "test"); + EXPECT_CALL(visitor_, OnIncomingUnidirectionalStreamAvailable()).Times(1); + session_->OnStreamFrame(frame); + + QuicTransportStream* stream = session_->AcceptIncomingUnidirectionalStream(); + ASSERT_TRUE(stream != nullptr); + EXPECT_EQ(stream->ReadableBytes(), 4u); + EXPECT_EQ(stream->id(), id); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc new file mode 100644 index 00000000000..57f53804c3a --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc @@ -0,0 +1,331 @@ +// 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. + +// An integration test that covers interactions between QuicTransport client and +// server sessions. + +#include +#include + +#include "url/gurl.h" +#include "url/origin.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.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_versions.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" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" +#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h" + +namespace quic { +namespace test { +namespace { + +using simulator::QuicEndpointBase; +using simulator::Simulator; +using testing::Assign; + +url::Origin GetTestOrigin() { + constexpr char kTestOrigin[] = "https://test-origin.test"; + GURL origin_url(kTestOrigin); + return url::Origin::Create(origin_url); +} + +ParsedQuicVersionVector GetVersions() { + return {ParsedQuicVersion{PROTOCOL_TLS1_3, QUIC_VERSION_99}}; +} + +class QuicTransportEndpointBase : public QuicEndpointBase { + public: + QuicTransportEndpointBase(Simulator* simulator, + const std::string& name, + const std::string& peer_name, + Perspective perspective) + : QuicEndpointBase(simulator, name, peer_name) { + connection_ = std::make_unique( + TestConnectionId(0x10), simulator::GetAddressFromName(peer_name), + simulator, simulator->GetAlarmFactory(), &writer_, + /*owns_writer=*/false, perspective, GetVersions()); + connection_->SetSelfAddress(simulator::GetAddressFromName(name)); + + SetQuicReloadableFlag(quic_supports_tls_handshake, true); + } +}; + +class QuicTransportClientEndpoint : public QuicTransportEndpointBase { + public: + QuicTransportClientEndpoint(Simulator* simulator, + const std::string& name, + const std::string& peer_name, + url::Origin origin) + : QuicTransportEndpointBase(simulator, + name, + peer_name, + Perspective::IS_CLIENT), + crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + session_(connection_.get(), + nullptr, + DefaultQuicConfig(), + GetVersions(), + GURL("quic-transport://test.example.com:50000"), + &crypto_config_, + origin, + &visitor_) { + session_.Initialize(); + } + + QuicTransportClientSession* session() { return &session_; } + MockClientVisitor* visitor() { return &visitor_; } + + private: + QuicCryptoClientConfig crypto_config_; + MockClientVisitor visitor_; + QuicTransportClientSession session_; +}; + +class QuicTransportServerEndpoint : public QuicTransportEndpointBase { + public: + QuicTransportServerEndpoint(Simulator* simulator, + const std::string& name, + const std::string& peer_name, + QuicTransportSimpleServerSession::Mode mode, + std::vector accepted_origins) + : QuicTransportEndpointBase(simulator, + name, + peer_name, + Perspective::IS_SERVER), + crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance(), + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default()), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), + session_(connection_.get(), + /*owns_connection=*/false, + nullptr, + DefaultQuicConfig(), + GetVersions(), + &crypto_config_, + &compressed_certs_cache_, + mode, + accepted_origins) { + session_.Initialize(); + } + + QuicTransportServerSession* session() { return &session_; } + + private: + QuicCryptoServerConfig crypto_config_; + QuicCompressedCertsCache compressed_certs_cache_; + QuicTransportSimpleServerSession session_; +}; + +std::unique_ptr VisitorExpectingFin() { + auto visitor = std::make_unique(); + EXPECT_CALL(*visitor, OnFinRead()); + return visitor; +} + +constexpr QuicBandwidth kClientBandwidth = + QuicBandwidth::FromKBitsPerSecond(10000); +constexpr QuicTime::Delta kClientPropagationDelay = + QuicTime::Delta::FromMilliseconds(2); +constexpr QuicBandwidth kServerBandwidth = + QuicBandwidth::FromKBitsPerSecond(4000); +constexpr QuicTime::Delta kServerPropagationDelay = + QuicTime::Delta::FromMilliseconds(50); +const QuicTime::Delta kTransferTime = + kClientBandwidth.TransferTime(kMaxOutgoingPacketSize) + + kServerBandwidth.TransferTime(kMaxOutgoingPacketSize); +const QuicTime::Delta kRtt = + (kClientPropagationDelay + kServerPropagationDelay + kTransferTime) * 2; +const QuicByteCount kBdp = kRtt * kServerBandwidth; + +constexpr QuicTime::Delta kDefaultTimeout = QuicTime::Delta::FromSeconds(3); + +class QuicTransportIntegrationTest : public QuicTest { + public: + QuicTransportIntegrationTest() + : switch_(&simulator_, "Switch", 8, 2 * kBdp) {} + + void CreateDefaultEndpoints(QuicTransportSimpleServerSession::Mode mode) { + client_ = std::make_unique( + &simulator_, "Client", "Server", GetTestOrigin()); + server_ = std::make_unique( + &simulator_, "Server", "Client", mode, accepted_origins_); + } + + void WireUpEndpoints() { + client_link_ = std::make_unique( + client_.get(), switch_.port(1), kClientBandwidth, + kClientPropagationDelay); + server_link_ = std::make_unique( + server_.get(), switch_.port(2), kServerBandwidth, + kServerPropagationDelay); + } + + void RunHandshake() { + client_->session()->CryptoConnect(); + bool result = simulator_.RunUntilOrTimeout( + [this]() { + return IsHandshakeDone(client_->session()) && + IsHandshakeDone(server_->session()); + }, + kDefaultTimeout); + EXPECT_TRUE(result); + } + + protected: + template + static bool IsHandshakeDone(const Session* session) { + return session->IsSessionReady() || session->error() != QUIC_NO_ERROR; + } + + Simulator simulator_; + simulator::Switch switch_; + std::unique_ptr client_link_; + std::unique_ptr server_link_; + + std::unique_ptr client_; + std::unique_ptr server_; + + std::vector accepted_origins_ = {GetTestOrigin()}; +}; + +TEST_F(QuicTransportIntegrationTest, SuccessfulHandshake) { + CreateDefaultEndpoints(QuicTransportSimpleServerSession::DISCARD); + WireUpEndpoints(); + RunHandshake(); + EXPECT_TRUE(client_->session()->IsSessionReady()); + EXPECT_TRUE(server_->session()->IsSessionReady()); +} + +TEST_F(QuicTransportIntegrationTest, OriginMismatch) { + accepted_origins_ = {url::Origin::Create(GURL{"https://wrong-origin.test"})}; + CreateDefaultEndpoints(QuicTransportSimpleServerSession::DISCARD); + WireUpEndpoints(); + RunHandshake(); + // Wait until the client receives CONNECTION_CLOSE. + simulator_.RunUntilOrTimeout( + [this]() { return !client_->session()->connection()->connected(); }, + kDefaultTimeout); + EXPECT_TRUE(client_->session()->IsSessionReady()); + EXPECT_FALSE(server_->session()->IsSessionReady()); + EXPECT_FALSE(client_->session()->connection()->connected()); + EXPECT_FALSE(server_->session()->connection()->connected()); + EXPECT_THAT(client_->session()->error(), + IsError(QUIC_TRANSPORT_INVALID_CLIENT_INDICATION)); + EXPECT_THAT(server_->session()->error(), + IsError(QUIC_TRANSPORT_INVALID_CLIENT_INDICATION)); +} + +TEST_F(QuicTransportIntegrationTest, SendOutgoingStreams) { + CreateDefaultEndpoints(QuicTransportSimpleServerSession::DISCARD); + WireUpEndpoints(); + RunHandshake(); + + std::vector streams; + for (int i = 0; i < 10; i++) { + QuicTransportStream* stream = + client_->session()->OpenOutgoingUnidirectionalStream(); + ASSERT_TRUE(stream->Write("test")); + streams.push_back(stream); + } + ASSERT_TRUE(simulator_.RunUntilOrTimeout( + [this]() { + return server_->session()->GetNumOpenIncomingStreams() == 10; + }, + kDefaultTimeout)); + + for (QuicTransportStream* stream : streams) { + ASSERT_TRUE(stream->SendFin()); + } + ASSERT_TRUE(simulator_.RunUntilOrTimeout( + [this]() { return server_->session()->GetNumOpenIncomingStreams() == 0; }, + kDefaultTimeout)); +} + +TEST_F(QuicTransportIntegrationTest, EchoBidirectionalStreams) { + CreateDefaultEndpoints(QuicTransportSimpleServerSession::ECHO); + WireUpEndpoints(); + RunHandshake(); + + QuicTransportStream* stream = + client_->session()->OpenOutgoingBidirectionalStream(); + EXPECT_TRUE(stream->Write("Hello!")); + + ASSERT_TRUE(simulator_.RunUntilOrTimeout( + [stream]() { return stream->ReadableBytes() == strlen("Hello!"); }, + kDefaultTimeout)); + std::string received; + EXPECT_EQ(stream->Read(&received), strlen("Hello!")); + EXPECT_EQ(received, "Hello!"); + + EXPECT_TRUE(stream->SendFin()); + ASSERT_TRUE(simulator_.RunUntilOrTimeout( + [this]() { return server_->session()->GetNumOpenIncomingStreams() == 0; }, + kDefaultTimeout)); +} + +TEST_F(QuicTransportIntegrationTest, EchoUnidirectionalStreams) { + CreateDefaultEndpoints(QuicTransportSimpleServerSession::ECHO); + WireUpEndpoints(); + RunHandshake(); + + // Send two streams, but only send FIN on the second one. + QuicTransportStream* stream1 = + client_->session()->OpenOutgoingUnidirectionalStream(); + EXPECT_TRUE(stream1->Write("Stream One")); + QuicTransportStream* stream2 = + client_->session()->OpenOutgoingUnidirectionalStream(); + EXPECT_TRUE(stream2->Write("Stream Two")); + EXPECT_TRUE(stream2->SendFin()); + + // Wait until a stream is received. + bool stream_received = false; + EXPECT_CALL(*client_->visitor(), OnIncomingUnidirectionalStreamAvailable()) + .Times(2) + .WillRepeatedly(Assign(&stream_received, true)); + ASSERT_TRUE(simulator_.RunUntilOrTimeout( + [&stream_received]() { return stream_received; }, kDefaultTimeout)); + + // Receive a reply stream and expect it to be the second one. + QuicTransportStream* reply = + client_->session()->AcceptIncomingUnidirectionalStream(); + ASSERT_TRUE(reply != nullptr); + std::string buffer; + reply->set_visitor(VisitorExpectingFin()); + EXPECT_GT(reply->Read(&buffer), 0u); + EXPECT_EQ(buffer, "Stream Two"); + + // Reset reply-related variables. + stream_received = false; + buffer = ""; + + // Send FIN on the first stream, and expect to receive it back. + EXPECT_TRUE(stream1->SendFin()); + ASSERT_TRUE(simulator_.RunUntilOrTimeout( + [&stream_received]() { return stream_received; }, kDefaultTimeout)); + reply = client_->session()->AcceptIncomingUnidirectionalStream(); + ASSERT_TRUE(reply != nullptr); + reply->set_visitor(VisitorExpectingFin()); + EXPECT_GT(reply->Read(&buffer), 0u); + EXPECT_EQ(buffer, "Stream One"); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h index 307354f32ad..f97b8e777de 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h @@ -12,23 +12,24 @@ namespace quic { // The ALPN used by QuicTransport. -QUIC_EXPORT inline const char* QuicTransportAlpn() { +QUIC_EXPORT_PRIVATE inline const char* QuicTransportAlpn() { return "wq-vvv-01"; } // The stream ID on which the client indication is sent. -QUIC_EXPORT constexpr QuicStreamId ClientIndicationStream() { +QUIC_EXPORT_PRIVATE constexpr QuicStreamId ClientIndicationStream() { return 2; } // The maximum allowed size of the client indication. -QUIC_EXPORT constexpr QuicByteCount ClientIndicationMaxSize() { +QUIC_EXPORT_PRIVATE constexpr QuicByteCount ClientIndicationMaxSize() { return 65536; } // The keys of the fields in the client indication. enum class QuicTransportClientIndicationKeys : uint16_t { kOrigin = 0x0000, + kPath = 0x0001, }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.cc index 92cffcd9156..7f00acd470f 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.cc @@ -12,8 +12,8 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" -#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" namespace quic { @@ -63,9 +63,11 @@ QuicStream* QuicTransportServerSession::CreateIncomingStream(QuicStreamId id) { return indication_ptr; } - // TODO(vasilvv): implement incoming data streams. - QUIC_BUG << "Not implemented"; - return nullptr; + auto stream = std::make_unique(id, this, this); + QuicTransportStream* stream_ptr = stream.get(); + ActivateStream(std::move(stream)); + OnIncomingDataStream(stream_ptr); + return stream_ptr; } QuicTransportServerSession::ClientIndication::ClientIndication( diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h index 7183eada1c8..b3fcfa07588 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h @@ -12,15 +12,16 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" namespace quic { // A server session for the QuicTransport protocol. -class QUIC_EXPORT QuicTransportServerSession +class QUIC_EXPORT_PRIVATE QuicTransportServerSession : public QuicSession, public QuicTransportSessionInterface { public: - class ServerVisitor { + class QUIC_EXPORT_PRIVATE ServerVisitor { public: virtual ~ServerVisitor() {} @@ -49,6 +50,10 @@ class QUIC_EXPORT QuicTransportServerSession return crypto_stream_.get(); } + // Returns true once the encryption has been established, the client + // indication has been received and the origin has been verified. No + // application data will be read or written before the connection is ready. + // Once the connection becomes ready, this method will never return false. bool IsSessionReady() const override { return ready_; } QuicStream* CreateIncomingStream(QuicStreamId id) override; @@ -59,7 +64,7 @@ class QUIC_EXPORT QuicTransportServerSession } protected: - class ClientIndication : public QuicStream { + class QUIC_EXPORT_PRIVATE ClientIndication : public QuicStream { public: explicit ClientIndication(QuicTransportServerSession* session); void OnDataAvailable() override; @@ -70,7 +75,7 @@ class QUIC_EXPORT QuicTransportServerSession }; // Utility class for parsing the client indication. - class ClientIndicationParser { + class QUIC_EXPORT_PRIVATE ClientIndicationParser { public: ClientIndicationParser(QuicTransportServerSession* session, QuicStringPiece indication) @@ -93,6 +98,8 @@ class QUIC_EXPORT QuicTransportServerSession // https://vasilvv.github.io/webtransport/draft-vvv-webtransport-quic.html#rfc.section.3.2 void ProcessClientIndication(QuicStringPiece indication); + virtual void OnIncomingDataStream(QuicTransportStream* /*stream*/) {} + std::unique_ptr crypto_stream_; bool ready_ = false; ServerVisitor* visitor_; diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc index 818c08db9e4..5e6774810f0 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc @@ -21,6 +21,7 @@ #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h" namespace quic { namespace test { @@ -48,11 +49,6 @@ ParsedQuicVersionVector GetVersions() { return {ParsedQuicVersion{PROTOCOL_TLS1_3, QUIC_VERSION_99}}; } -class MockVisitor : public QuicTransportServerSession::ServerVisitor { - public: - MOCK_METHOD1(CheckOrigin, bool(url::Origin)); -}; - class QuicTransportServerSessionTest : public QuicTest { public: QuicTransportServerSessionTest() @@ -76,7 +72,9 @@ class QuicTransportServerSessionTest : public QuicTest { session_->Initialize(); crypto_stream_ = static_cast( session_->GetMutableCryptoStream()); - crypto_stream_->OnSuccessfulVersionNegotiation(GetVersions()[0]); + if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + crypto_stream_->OnSuccessfulVersionNegotiation(GetVersions()[0]); + } } void Connect() { @@ -111,7 +109,7 @@ class QuicTransportServerSessionTest : public QuicTest { QuicCryptoServerConfig crypto_config_; std::unique_ptr session_; QuicCompressedCertsCache compressed_certs_cache_; - testing::StrictMock visitor_; + testing::StrictMock visitor_; QuicCryptoServerStream* crypto_stream_; }; diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h index 971fa5b3c73..cdb3e999790 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h @@ -5,11 +5,13 @@ #ifndef QUICHE_QUIC_QUIC_TRANSPORT_QUIC_TRANSPORT_SESSION_INTERFACE_H_ #define QUICHE_QUIC_QUIC_TRANSPORT_QUIC_TRANSPORT_SESSION_INTERFACE_H_ +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + namespace quic { // Shared interface between QuicTransportClientSession and // QuicTransportServerSession. -class QuicTransportSessionInterface { +class QUIC_EXPORT_PRIVATE QuicTransportSessionInterface { public: virtual ~QuicTransportSessionInterface() {} diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc new file mode 100644 index 00000000000..61f4345d61b --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" + +#include + +#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_string_piece.h" + +namespace quic { + +QuicTransportStream::QuicTransportStream( + QuicStreamId id, + QuicSession* session, + QuicTransportSessionInterface* session_interface) + : QuicStream(id, + session, + /*is_static=*/false, + QuicUtils::GetStreamType(id, + session->connection()->perspective(), + session->IsIncomingStream(id))), + session_interface_(session_interface) {} + +size_t QuicTransportStream::Read(char* buffer, size_t buffer_size) { + if (!session_interface_->IsSessionReady()) { + return 0; + } + + iovec iov; + iov.iov_base = buffer; + iov.iov_len = buffer_size; + const size_t result = sequencer()->Readv(&iov, 1); + if (sequencer()->IsClosed() && visitor_ != nullptr) { + visitor_->OnFinRead(); + } + return result; +} + +size_t QuicTransportStream::Read(std::string* output) { + const size_t old_size = output->size(); + const size_t bytes_to_read = ReadableBytes(); + output->resize(old_size + bytes_to_read); + size_t bytes_read = Read(&(*output)[old_size], bytes_to_read); + DCHECK_EQ(bytes_to_read, bytes_read); + output->resize(old_size + bytes_read); + return bytes_read; +} + +bool QuicTransportStream::Write(QuicStringPiece data) { + if (!CanWrite()) { + return false; + } + + // TODO(vasilvv): use WriteMemSlices() + WriteOrBufferData(data, /*fin=*/false, nullptr); + return true; +} + +bool QuicTransportStream::SendFin() { + if (!CanWrite()) { + return false; + } + + WriteOrBufferData(QuicStringPiece(), /*fin=*/true, nullptr); + return true; +} + +bool QuicTransportStream::CanWrite() const { + return session_interface_->IsSessionReady() && CanWriteNewData(); +} + +size_t QuicTransportStream::ReadableBytes() const { + if (!session_interface_->IsSessionReady()) { + return 0; + } + + return sequencer()->ReadableBytes(); +} + +void QuicTransportStream::OnDataAvailable() { + if (sequencer()->IsClosed()) { + if (visitor_ != nullptr) { + visitor_->OnFinRead(); + } + OnFinRead(); + return; + } + + if (visitor_ == nullptr) { + return; + } + if (ReadableBytes() == 0) { + return; + } + visitor_->OnCanRead(); +} + +void QuicTransportStream::OnCanWriteNewData() { + // Ensure the origin check has been completed, as the stream can be notified + // about being writable before that. + if (!CanWrite()) { + return; + } + if (visitor_ != nullptr) { + visitor_->OnCanWrite(); + } +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h new file mode 100644 index 00000000000..1651a1cb082 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h @@ -0,0 +1,72 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_QUIC_TRANSPORT_QUIC_TRANSPORT_STREAM_H_ +#define QUICHE_QUIC_QUIC_TRANSPORT_QUIC_TRANSPORT_STREAM_H_ + +#include +#include + +#include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h" + +namespace quic { + +// QuicTransportStream is an extension of QuicStream that provides I/O interface +// that is safe to use in the QuicTransport context. The interface ensures no +// application data is processed before the client indication is processed. +class QUIC_EXPORT_PRIVATE QuicTransportStream : public QuicStream { + public: + class QUIC_EXPORT_PRIVATE Visitor { + public: + virtual ~Visitor() {} + virtual void OnCanRead() = 0; + virtual void OnFinRead() = 0; + virtual void OnCanWrite() = 0; + }; + + QuicTransportStream(QuicStreamId id, + QuicSession* session, + QuicTransportSessionInterface* session_interface); + + // Reads at most |buffer_size| bytes into |buffer| and returns the number of + // bytes actually read. + size_t Read(char* buffer, size_t buffer_size); + // Reads all available data and appends it to the end of |output|. + size_t Read(std::string* output); + // Writes |data| into the stream. Returns true on success. + QUIC_MUST_USE_RESULT bool Write(QuicStringPiece data); + // Sends the FIN on the stream. Returns true on success. + QUIC_MUST_USE_RESULT bool SendFin(); + + // Indicates whether it is possible to write into stream right now. + bool CanWrite() const; + // Indicates the number of bytes that can be read from the stream. + size_t ReadableBytes() const; + + // QuicSession method implementations. + void OnDataAvailable() override; + void OnCanWriteNewData() override; + + Visitor* visitor() { return visitor_.get(); } + void set_visitor(std::unique_ptr visitor) { + visitor_ = std::move(visitor); + } + + protected: + // Hide the methods that allow writing data without checking IsSessionReady(). + using QuicStream::WriteMemSlices; + using QuicStream::WriteOrBufferData; + + QuicTransportSessionInterface* session_interface_; + std::unique_ptr visitor_ = nullptr; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_QUIC_TRANSPORT_QUIC_TRANSPORT_STREAM_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc new file mode 100644 index 00000000000..c291b54cf2b --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" + +#include + +#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_session_interface.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h" + +namespace quic { +namespace test { +namespace { + +using testing::Return; + +ParsedQuicVersionVector GetVersions() { + return {ParsedQuicVersion{PROTOCOL_TLS1_3, QUIC_VERSION_99}}; +} + +class MockQuicTransportSessionInterface : public QuicTransportSessionInterface { + public: + MOCK_CONST_METHOD0(IsSessionReady, bool()); +}; + +class QuicTransportStreamTest : public QuicTest { + public: + QuicTransportStreamTest() + : connection_(new MockQuicConnection(&helper_, + &alarm_factory_, + Perspective::IS_CLIENT, + GetVersions())), + session_(connection_) { + session_.Initialize(); + + stream_ = new QuicTransportStream(0, &session_, &interface_); + session_.ActivateStream(QuicWrapUnique(stream_)); + + auto visitor = std::make_unique(); + visitor_ = visitor.get(); + stream_->set_visitor(std::move(visitor)); + } + + void ReceiveStreamData(QuicStringPiece data, QuicStreamOffset offset) { + QuicStreamFrame frame(0, false, offset, data); + stream_->OnStreamFrame(frame); + } + + protected: + MockAlarmFactory alarm_factory_; + MockQuicConnectionHelper helper_; + + MockQuicConnection* connection_; // Owned by |session_|. + MockQuicSession session_; + MockQuicTransportSessionInterface interface_; + QuicTransportStream* stream_; // Owned by |session_|. + MockStreamVisitor* visitor_; // Owned by |stream_|. +}; + +TEST_F(QuicTransportStreamTest, NotReady) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(false)); + ReceiveStreamData("test", 0); + EXPECT_EQ(stream_->ReadableBytes(), 0u); + EXPECT_FALSE(stream_->CanWrite()); +} + +TEST_F(QuicTransportStreamTest, ReadWhenNotReady) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(false)); + ReceiveStreamData("test", 0); + char buffer[4]; + QuicByteCount bytes_read = stream_->Read(buffer, sizeof(buffer)); + EXPECT_EQ(bytes_read, 0u); +} + +TEST_F(QuicTransportStreamTest, WriteWhenNotReady) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(false)); + EXPECT_FALSE(stream_->Write("test")); +} + +TEST_F(QuicTransportStreamTest, Ready) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true)); + ReceiveStreamData("test", 0); + EXPECT_EQ(stream_->ReadableBytes(), 4u); + EXPECT_TRUE(stream_->CanWrite()); + EXPECT_TRUE(stream_->Write("test")); +} + +TEST_F(QuicTransportStreamTest, ReceiveData) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true)); + EXPECT_CALL(*visitor_, OnCanRead()); + ReceiveStreamData("test", 0); +} + +TEST_F(QuicTransportStreamTest, FinReadWithNoDataPending) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true)); + EXPECT_CALL(*visitor_, OnFinRead()); + QuicStreamFrame frame(0, true, 0, ""); + stream_->OnStreamFrame(frame); +} + +TEST_F(QuicTransportStreamTest, FinReadWithDataPending) { + EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true)); + + EXPECT_CALL(*visitor_, OnCanRead()); + EXPECT_CALL(*visitor_, OnFinRead()).Times(0); + QuicStreamFrame frame(0, true, 0, "test"); + stream_->OnStreamFrame(frame); + + EXPECT_CALL(*visitor_, OnFinRead()).Times(1); + std::string buffer; + ASSERT_EQ(stream_->Read(&buffer), 4u); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc index 98d65e8d0fe..6716dec2605 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc @@ -209,7 +209,14 @@ class FullChloGenerator { } // namespace +std::unique_ptr CryptoServerConfigForTesting() { + return std::make_unique( + QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), + ProofSourceForTesting(), KeyExchangeSource::Default()); +} + int HandshakeWithFakeServer(QuicConfig* server_quic_config, + QuicCryptoServerConfig* crypto_config, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, PacketSavingConnection* client_conn, @@ -219,19 +226,19 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, helper, alarm_factory, Perspective::IS_SERVER, ParsedVersionOfIndex(client_conn->supported_versions(), 0)); - QuicCryptoServerConfig crypto_config( - QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - ProofSourceForTesting(), KeyExchangeSource::Default()); QuicCompressedCertsCache compressed_certs_cache( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); SetupCryptoServerConfigForTest( - server_conn->clock(), server_conn->random_generator(), &crypto_config); + server_conn->clock(), server_conn->random_generator(), crypto_config); TestQuicSpdyServerSession server_session( server_conn, *server_quic_config, client_conn->supported_versions(), - &crypto_config, &compressed_certs_cache); - server_session.OnSuccessfulVersionNegotiation( - client_conn->supported_versions().front()); + crypto_config, &compressed_certs_cache); + server_session.Initialize(); + if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + server_session.OnSuccessfulVersionNegotiation( + client_conn->supported_versions().front()); + } EXPECT_CALL(*server_session.helper(), CanAcceptClientHello(testing::_, testing::_, testing::_, testing::_, testing::_)) @@ -346,7 +353,8 @@ void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, MovePackets(client_conn, &client_i, server, server_conn, Perspective::IS_SERVER); - if (client->handshake_confirmed() && server->handshake_confirmed()) { + if (client->handshake_confirmed() && server->handshake_confirmed() && + server_conn->encrypted_packets_.size() == server_i) { break; } ASSERT_GT(server_conn->encrypted_packets_.size(), server_i); @@ -782,7 +790,7 @@ std::string GenerateClientNonceHex(const QuicClock* clock, QuicRandom::GetInstance(), clock, new_config_options); primary_config.set_primary_time(clock->WallNow().ToUNIXSeconds()); std::unique_ptr msg = - crypto_config->AddConfig(std::move(primary_config), clock->WallNow()); + crypto_config->AddConfig(primary_config, clock->WallNow()); QuicStringPiece orbit; CHECK(msg->GetStringPiece(kORBT, &orbit)); std::string nonce; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h index 6f87e90494c..327eb673523 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h @@ -64,8 +64,13 @@ struct FakeClientOptions { bool only_tls_versions = false; }; +// Returns a QuicCryptoServerConfig that is in a reasonable configuration to +// pass into HandshakeWithFakeServer. +std::unique_ptr CryptoServerConfigForTesting(); + // returns: the number of client hellos that the client sent. int HandshakeWithFakeServer(QuicConfig* server_quic_config, + QuicCryptoServerConfig* crypto_config, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, PacketSavingConnection* client_conn, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc index 59a3947393e..656549772fa 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc @@ -128,7 +128,7 @@ TEST_F(CryptoTestUtilsTest, TestGenerateFullCHLO) { QuicRandom::GetInstance(), &clock, new_config_options); primary_config.set_primary_time(clock.WallNow().ToUNIXSeconds()); std::unique_ptr msg = - crypto_config.AddConfig(std::move(primary_config), clock.WallNow()); + crypto_config.AddConfig(primary_config, clock.WallNow()); QuicStringPiece orbit; ASSERT_TRUE(msg->GetStringPiece(kORBT, &orbit)); std::string nonce; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc new file mode 100644 index 00000000000..2b835ae2e46 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h" + +#include +#include +#include + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +void NoopEncoderStreamErrorDelegate::OnEncoderStreamError( + QuicStringPiece /*error_message*/) {} + +TestHeadersHandler::TestHeadersHandler() + : decoding_completed_(false), decoding_error_detected_(false) {} + +void TestHeadersHandler::OnHeaderDecoded(QuicStringPiece name, + QuicStringPiece value) { + ASSERT_FALSE(decoding_completed_); + ASSERT_FALSE(decoding_error_detected_); + + header_list_.AppendValueOrAddHeader(name, value); +} + +void TestHeadersHandler::OnDecodingCompleted() { + ASSERT_FALSE(decoding_completed_); + ASSERT_FALSE(decoding_error_detected_); + + decoding_completed_ = true; +} + +void TestHeadersHandler::OnDecodingErrorDetected( + QuicStringPiece error_message) { + ASSERT_FALSE(decoding_completed_); + ASSERT_FALSE(decoding_error_detected_); + + decoding_error_detected_ = true; + error_message_.assign(error_message.data(), error_message.size()); +} + +spdy::SpdyHeaderBlock TestHeadersHandler::ReleaseHeaderList() { + DCHECK(decoding_completed_); + DCHECK(!decoding_error_detected_); + + return std::move(header_list_); +} + +bool TestHeadersHandler::decoding_completed() const { + return decoding_completed_; +} + +bool TestHeadersHandler::decoding_error_detected() const { + return decoding_error_detected_; +} + +const std::string& TestHeadersHandler::error_message() const { + DCHECK(decoding_error_detected_); + return error_message_; +} + +void QpackDecode( + uint64_t maximum_dynamic_table_capacity, + uint64_t maximum_blocked_streams, + QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate, + QpackStreamSenderDelegate* decoder_stream_sender_delegate, + QpackProgressiveDecoder::HeadersHandlerInterface* handler, + const FragmentSizeGenerator& fragment_size_generator, + QuicStringPiece data) { + QpackDecoder decoder(maximum_dynamic_table_capacity, maximum_blocked_streams, + encoder_stream_error_delegate); + decoder.set_qpack_stream_sender_delegate(decoder_stream_sender_delegate); + auto progressive_decoder = + decoder.CreateProgressiveDecoder(/* stream_id = */ 1, handler); + while (!data.empty()) { + size_t fragment_size = std::min(fragment_size_generator(), data.size()); + progressive_decoder->Decode(data.substr(0, fragment_size)); + data = data.substr(fragment_size); + } + progressive_decoder->EndHeaderBlock(); +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h new file mode 100644 index 00000000000..213aded1ba5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h @@ -0,0 +1,103 @@ +// Copyright (c) 2018 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_TEST_TOOLS_QPACK_QPACK_DECODER_TEST_UTILS_H_ +#define QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_DECODER_TEST_UTILS_H_ + +#include + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" + +namespace quic { +namespace test { + +// QpackDecoder::EncoderStreamErrorDelegate implementation that does nothing. +class NoopEncoderStreamErrorDelegate + : public QpackDecoder::EncoderStreamErrorDelegate { + public: + ~NoopEncoderStreamErrorDelegate() override = default; + + void OnEncoderStreamError(QuicStringPiece error_message) override; +}; + +// Mock QpackDecoder::EncoderStreamErrorDelegate implementation. +class MockEncoderStreamErrorDelegate + : public QpackDecoder::EncoderStreamErrorDelegate { + public: + ~MockEncoderStreamErrorDelegate() override = default; + + MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message)); +}; + +// HeadersHandlerInterface implementation that collects decoded headers +// into a SpdyHeaderBlock. +class TestHeadersHandler + : public QpackProgressiveDecoder::HeadersHandlerInterface { + public: + TestHeadersHandler(); + ~TestHeadersHandler() override = default; + + // HeadersHandlerInterface implementation: + void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override; + void OnDecodingCompleted() override; + void OnDecodingErrorDetected(QuicStringPiece error_message) override; + + // Release decoded header list. Must only be called if decoding is complete + // and no errors have been detected. + spdy::SpdyHeaderBlock ReleaseHeaderList(); + + bool decoding_completed() const; + bool decoding_error_detected() const; + const std::string& error_message() const; + + private: + spdy::SpdyHeaderBlock header_list_; + bool decoding_completed_; + bool decoding_error_detected_; + std::string error_message_; +}; + +class MockHeadersHandler + : public QpackProgressiveDecoder::HeadersHandlerInterface { + public: + MockHeadersHandler() = default; + MockHeadersHandler(const MockHeadersHandler&) = delete; + MockHeadersHandler& operator=(const MockHeadersHandler&) = delete; + ~MockHeadersHandler() override = default; + + MOCK_METHOD2(OnHeaderDecoded, + void(QuicStringPiece name, QuicStringPiece value)); + MOCK_METHOD0(OnDecodingCompleted, void()); + MOCK_METHOD1(OnDecodingErrorDetected, void(QuicStringPiece error_message)); +}; + +class NoOpHeadersHandler + : public QpackProgressiveDecoder::HeadersHandlerInterface { + public: + ~NoOpHeadersHandler() override = default; + + void OnHeaderDecoded(QuicStringPiece /*name*/, + QuicStringPiece /*value*/) override {} + void OnDecodingCompleted() override {} + void OnDecodingErrorDetected(QuicStringPiece /*error_message*/) override {} +}; + +void QpackDecode( + uint64_t maximum_dynamic_table_capacity, + uint64_t maximum_blocked_streams, + QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate, + QpackStreamSenderDelegate* decoder_stream_sender_delegate, + QpackProgressiveDecoder::HeadersHandlerInterface* handler, + const FragmentSizeGenerator& fragment_size_generator, + QuicStringPiece data); + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_DECODER_TEST_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc new file mode 100644 index 00000000000..709686a85e8 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h" + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" + +namespace quic { +namespace test { + +// static +QpackHeaderTable* QpackEncoderPeer::header_table(QpackEncoder* encoder) { + return &encoder->header_table_; +} + +// static +uint64_t QpackEncoderPeer::maximum_blocked_streams( + const QpackEncoder* encoder) { + return encoder->maximum_blocked_streams_; +} + +// static +uint64_t QpackEncoderPeer::smallest_blocking_index( + const QpackEncoder* encoder) { + return encoder->blocking_manager_.smallest_blocking_index(); +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h new file mode 100644 index 00000000000..a824276bc4c --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h @@ -0,0 +1,30 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_ENCODER_PEER_H_ +#define QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_ENCODER_PEER_H_ + +#include + +namespace quic { + +class QpackEncoder; +class QpackHeaderTable; + +namespace test { + +class QpackEncoderPeer { + public: + QpackEncoderPeer() = delete; + + static QpackHeaderTable* header_table(QpackEncoder* encoder); + static uint64_t maximum_blocked_streams(const QpackEncoder* encoder); + static uint64_t smallest_blocking_index(const QpackEncoder* encoder); +}; + +} // namespace test + +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_ENCODER_PEER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.cc new file mode 100644 index 00000000000..dbdd3690d55 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" + +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" + +namespace quic { +namespace test { + +void NoopDecoderStreamErrorDelegate::OnDecoderStreamError( + QuicStringPiece /*error_message*/) {} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h new file mode 100644 index 00000000000..5fa229256b4 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h @@ -0,0 +1,40 @@ +// Copyright (c) 2018 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_TEST_TOOLS_QPACK_QPACK_ENCODER_TEST_UTILS_H_ +#define QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_ENCODER_TEST_UTILS_H_ + +#include + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" + +namespace quic { +namespace test { + +// QpackEncoder::DecoderStreamErrorDelegate implementation that does nothing. +class NoopDecoderStreamErrorDelegate + : public QpackEncoder::DecoderStreamErrorDelegate { + public: + ~NoopDecoderStreamErrorDelegate() override = default; + + void OnDecoderStreamError(QuicStringPiece error_message) override; +}; + +// Mock QpackEncoder::DecoderStreamErrorDelegate implementation. +class MockDecoderStreamErrorDelegate + : public QpackEncoder::DecoderStreamErrorDelegate { + public: + ~MockDecoderStreamErrorDelegate() override = default; + + MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message)); +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_ENCODER_TEST_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc new file mode 100644 index 00000000000..c554a97d1ce --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h" + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" + +namespace quic { +namespace test { + +// static +uint64_t QpackHeaderTablePeer::dynamic_table_capacity( + const QpackHeaderTable* header_table) { + return header_table->dynamic_table_capacity_; +} + +// static +uint64_t QpackHeaderTablePeer::maximum_dynamic_table_capacity( + const QpackHeaderTable* header_table) { + return header_table->maximum_dynamic_table_capacity_; +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h new file mode 100644 index 00000000000..19e8d0d64e3 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h @@ -0,0 +1,29 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_HEADER_TABLE_PEER_H_ +#define QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_HEADER_TABLE_PEER_H_ + +#include + +namespace quic { + +class QpackHeaderTable; + +namespace test { + +class QpackHeaderTablePeer { + public: + QpackHeaderTablePeer() = delete; + + static uint64_t dynamic_table_capacity(const QpackHeaderTable* header_table); + static uint64_t maximum_dynamic_table_capacity( + const QpackHeaderTable* header_table); +}; + +} // namespace test + +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_HEADER_TABLE_PEER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc new file mode 100644 index 00000000000..a5a74aa4cb0 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc @@ -0,0 +1,334 @@ +// Copyright (c) 2018 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. + +// Decoder to test QPACK Offline Interop corpus +// +// See https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop for +// description of test data format. +// +// Example usage +// +// cd $TEST_DATA +// git clone https://github.com/qpackers/qifs.git +// TEST_ENCODED_DATA=$TEST_DATA/qifs/encoded/qpack-06 +// TEST_QIF_DATA=$TEST_DATA/qifs/qifs +// $BIN/qpack_offline_decoder \ +// $TEST_ENCODED_DATA/f5/fb-req.qifencoded.4096.100.0 \ +// $TEST_QIF_DATA/fb-req.qif +// $TEST_ENCODED_DATA/h2o/fb-req-hq.out.512.0.1 \ +// $TEST_QIF_DATA/fb-req-hq.qif +// $TEST_ENCODED_DATA/ls-qpack/fb-resp-hq.out.0.0.0 \ +// $TEST_QIF_DATA/fb-resp-hq.qif +// $TEST_ENCODED_DATA/proxygen/netbsd.qif.proxygen.out.4096.0.0 \ +// $TEST_QIF_DATA/netbsd.qif +// + +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h" + +#include +#include +#include + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_file_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" + +namespace quic { + +QpackOfflineDecoder::QpackOfflineDecoder() + : encoder_stream_error_detected_(false) {} + +bool QpackOfflineDecoder::DecodeAndVerifyOfflineData( + QuicStringPiece input_filename, + QuicStringPiece expected_headers_filename) { + if (!ParseInputFilename(input_filename)) { + QUIC_LOG(ERROR) << "Error parsing input filename " << input_filename; + return false; + } + + if (!DecodeHeaderBlocksFromFile(input_filename)) { + QUIC_LOG(ERROR) << "Error decoding header blocks in " << input_filename; + return false; + } + + if (!VerifyDecodedHeaderLists(expected_headers_filename)) { + QUIC_LOG(ERROR) << "Header lists decoded from " << input_filename + << " to not match expected headers parsed from " + << expected_headers_filename; + return false; + } + + return true; +} + +void QpackOfflineDecoder::OnEncoderStreamError(QuicStringPiece error_message) { + QUIC_LOG(ERROR) << "Encoder stream error: " << error_message; + encoder_stream_error_detected_ = true; +} + +bool QpackOfflineDecoder::ParseInputFilename(QuicStringPiece input_filename) { + auto pieces = QuicTextUtils::Split(input_filename, '.'); + + if (pieces.size() < 3) { + QUIC_LOG(ERROR) << "Not enough fields in input filename " << input_filename; + return false; + } + + auto piece_it = pieces.rbegin(); + + // Acknowledgement mode: 1 for immediate, 0 for none. + bool immediate_acknowledgement = false; + if (*piece_it == "0") { + immediate_acknowledgement = false; + } else if (*piece_it == "1") { + immediate_acknowledgement = true; + } else { + QUIC_LOG(ERROR) + << "Header acknowledgement field must be 0 or 1 in input filename " + << input_filename; + return false; + } + + ++piece_it; + + // Maximum allowed number of blocked streams. + uint64_t max_blocked_streams = 0; + if (!QuicTextUtils::StringToUint64(*piece_it, &max_blocked_streams)) { + QUIC_LOG(ERROR) << "Error parsing part of input filename \"" << *piece_it + << "\" as an integer."; + return false; + } + + ++piece_it; + + // Maximum Dynamic Table Capacity in bytes + uint64_t maximum_dynamic_table_capacity = 0; + if (!QuicTextUtils::StringToUint64(*piece_it, + &maximum_dynamic_table_capacity)) { + QUIC_LOG(ERROR) << "Error parsing part of input filename \"" << *piece_it + << "\" as an integer."; + return false; + } + qpack_decoder_ = std::make_unique( + maximum_dynamic_table_capacity, max_blocked_streams, this); + qpack_decoder_->set_qpack_stream_sender_delegate( + &decoder_stream_sender_delegate_); + + // The initial dynamic table capacity is zero according to + // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#eviction. + // However, for historical reasons, offline interop encoders use + // |maximum_dynamic_table_capacity| as initial capacity. + qpack_decoder_->OnSetDynamicTableCapacity(maximum_dynamic_table_capacity); + + return true; +} + +bool QpackOfflineDecoder::DecodeHeaderBlocksFromFile( + QuicStringPiece input_filename) { + // Store data in |input_data_storage|; use a QuicStringPiece to efficiently + // keep track of remaining portion yet to be decoded. + std::string input_data_storage; + ReadFileContents(input_filename, &input_data_storage); + QuicStringPiece input_data(input_data_storage); + + while (!input_data.empty()) { + // Parse stream_id and length. + if (input_data.size() < sizeof(uint64_t) + sizeof(uint32_t)) { + QUIC_LOG(ERROR) << "Unexpected end of input file."; + return false; + } + + uint64_t stream_id = quiche::QuicheEndian::NetToHost64( + *reinterpret_cast(input_data.data())); + input_data = input_data.substr(sizeof(uint64_t)); + + uint32_t length = quiche::QuicheEndian::NetToHost32( + *reinterpret_cast(input_data.data())); + input_data = input_data.substr(sizeof(uint32_t)); + + if (input_data.size() < length) { + QUIC_LOG(ERROR) << "Unexpected end of input file."; + return false; + } + + // Parse data. + QuicStringPiece data = input_data.substr(0, length); + input_data = input_data.substr(length); + + // Process data. + if (stream_id == 0) { + qpack_decoder_->encoder_stream_receiver()->Decode(data); + + if (encoder_stream_error_detected_) { + QUIC_LOG(ERROR) << "Error detected on encoder stream."; + return false; + } + } else { + auto headers_handler = std::make_unique(); + auto progressive_decoder = qpack_decoder_->CreateProgressiveDecoder( + stream_id, headers_handler.get()); + + progressive_decoder->Decode(data); + progressive_decoder->EndHeaderBlock(); + + if (headers_handler->decoding_error_detected()) { + QUIC_LOG(ERROR) << "Sync decoding error on stream " << stream_id << ": " + << headers_handler->error_message(); + return false; + } + + decoders_.push_back({std::move(headers_handler), + std::move(progressive_decoder), stream_id}); + } + + // Move decoded header lists from TestHeadersHandlers and append them to + // |decoded_header_lists_| while preserving the order in |decoders_|. + while (!decoders_.empty() && + decoders_.front().headers_handler->decoding_completed()) { + Decoder* decoder = &decoders_.front(); + + if (decoder->headers_handler->decoding_error_detected()) { + QUIC_LOG(ERROR) << "Async decoding error on stream " + << decoder->stream_id << ": " + << decoder->headers_handler->error_message(); + return false; + } + + if (!decoder->headers_handler->decoding_completed()) { + QUIC_LOG(ERROR) << "Decoding incomplete after reading entire" + " file, on stream " + << decoder->stream_id; + return false; + } + + decoded_header_lists_.push_back( + decoder->headers_handler->ReleaseHeaderList()); + decoders_.pop_front(); + } + } + + if (!decoders_.empty()) { + DCHECK(!decoders_.front().headers_handler->decoding_completed()); + + QUIC_LOG(ERROR) << "Blocked decoding uncomplete after reading entire" + " file, on stream " + << decoders_.front().stream_id; + return false; + } + + return true; +} + +bool QpackOfflineDecoder::VerifyDecodedHeaderLists( + QuicStringPiece expected_headers_filename) { + // Store data in |expected_headers_data_storage|; use a QuicStringPiece to + // efficiently keep track of remaining portion yet to be decoded. + std::string expected_headers_data_storage; + ReadFileContents(expected_headers_filename, &expected_headers_data_storage); + QuicStringPiece expected_headers_data(expected_headers_data_storage); + + while (!decoded_header_lists_.empty()) { + spdy::SpdyHeaderBlock decoded_header_list = + std::move(decoded_header_lists_.front()); + decoded_header_lists_.pop_front(); + + spdy::SpdyHeaderBlock expected_header_list; + if (!ReadNextExpectedHeaderList(&expected_headers_data, + &expected_header_list)) { + QUIC_LOG(ERROR) + << "Error parsing expected header list to match next decoded " + "header list."; + return false; + } + + if (!CompareHeaderBlocks(std::move(decoded_header_list), + std::move(expected_header_list))) { + QUIC_LOG(ERROR) << "Decoded header does not match expected header."; + return false; + } + } + + if (!expected_headers_data.empty()) { + QUIC_LOG(ERROR) + << "Not enough encoded header lists to match expected ones."; + return false; + } + + return true; +} + +bool QpackOfflineDecoder::ReadNextExpectedHeaderList( + QuicStringPiece* expected_headers_data, + spdy::SpdyHeaderBlock* expected_header_list) { + while (true) { + QuicStringPiece::size_type endline = expected_headers_data->find('\n'); + + // Even last header list must be followed by an empty line. + if (endline == QuicStringPiece::npos) { + QUIC_LOG(ERROR) << "Unexpected end of expected header list file."; + return false; + } + + if (endline == 0) { + // Empty line indicates end of header list. + *expected_headers_data = expected_headers_data->substr(1); + return true; + } + + QuicStringPiece header_field = expected_headers_data->substr(0, endline); + auto pieces = QuicTextUtils::Split(header_field, '\t'); + + if (pieces.size() != 2) { + QUIC_LOG(ERROR) << "Header key and value must be separated by TAB."; + return false; + } + + expected_header_list->AppendValueOrAddHeader(pieces[0], pieces[1]); + + *expected_headers_data = expected_headers_data->substr(endline + 1); + } +} + +bool QpackOfflineDecoder::CompareHeaderBlocks( + spdy::SpdyHeaderBlock decoded_header_list, + spdy::SpdyHeaderBlock expected_header_list) { + if (decoded_header_list == expected_header_list) { + return true; + } + + // The h2o decoder reshuffles the "content-length" header and pseudo-headers, + // see + // https://github.com/qpackers/qifs/blob/master/encoded/qpack-03/h2o/README.md. + // Remove such headers one by one if they match. + const char* kContentLength = "content-length"; + const char* kPseudoHeaderPrefix = ":"; + for (spdy::SpdyHeaderBlock::iterator decoded_it = decoded_header_list.begin(); + decoded_it != decoded_header_list.end();) { + const QuicStringPiece key = decoded_it->first; + if (key != kContentLength && + !QuicTextUtils::StartsWith(key, kPseudoHeaderPrefix)) { + ++decoded_it; + continue; + } + spdy::SpdyHeaderBlock::iterator expected_it = + expected_header_list.find(key); + if (expected_it == expected_header_list.end() || + decoded_it->second != expected_it->second) { + ++decoded_it; + continue; + } + // SpdyHeaderBlock does not support erasing by iterator, only by key. + ++decoded_it; + expected_header_list.erase(key); + // This will invalidate |key|. + decoded_header_list.erase(key); + } + + return decoded_header_list == expected_header_list; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h new file mode 100644 index 00000000000..cb7dedd3aaf --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h @@ -0,0 +1,86 @@ +// Copyright (c) 2018 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_TEST_TOOLS_QPACK_QPACK_OFFLINE_DECODER_H_ +#define QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_OFFLINE_DECODER_H_ + +#include + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" + +namespace quic { + +// A decoder to read encoded data from a file, decode it, and compare to +// a list of expected header lists read from another file. File format is +// described at +// https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop. +class QpackOfflineDecoder : public QpackDecoder::EncoderStreamErrorDelegate { + public: + QpackOfflineDecoder(); + ~QpackOfflineDecoder() override = default; + + // Read encoded header blocks and encoder stream data from |input_filename| + // and decode them, read expected header lists from + // |expected_headers_filename|, and compare decoded header lists to expected + // ones. Returns true if there is an equal number of them and the + // corresponding ones match, false otherwise. + bool DecodeAndVerifyOfflineData(QuicStringPiece input_filename, + QuicStringPiece expected_headers_filename); + + // QpackDecoder::EncoderStreamErrorDelegate implementation: + void OnEncoderStreamError(QuicStringPiece error_message) override; + + private: + // Data structure to hold TestHeadersHandler and QpackProgressiveDecoder until + // decoding of a header header block (and all preceding header blocks) is + // complete. + struct Decoder { + std::unique_ptr headers_handler; + std::unique_ptr progressive_decoder; + uint64_t stream_id; + }; + + // Parse decoder parameters from |input_filename| and set up |qpack_decoder_| + // accordingly. + bool ParseInputFilename(QuicStringPiece input_filename); + + // Read encoded header blocks and encoder stream data from |input_filename|, + // pass them to |qpack_decoder_| for decoding, and add decoded header lists to + // |decoded_header_lists_|. + bool DecodeHeaderBlocksFromFile(QuicStringPiece input_filename); + + // Read expected header lists from |expected_headers_filename| and verify + // decoded header lists in |decoded_header_lists_| against them. + bool VerifyDecodedHeaderLists(QuicStringPiece expected_headers_filename); + + // Parse next header list from |*expected_headers_data| into + // |*expected_header_list|, removing consumed data from the beginning of + // |*expected_headers_data|. Returns true on success, false if parsing fails. + bool ReadNextExpectedHeaderList(QuicStringPiece* expected_headers_data, + spdy::SpdyHeaderBlock* expected_header_list); + + // Compare two header lists. Allow for different orders of certain headers as + // described at + // https://github.com/qpackers/qifs/blob/master/encoded/qpack-03/h2o/README.md. + bool CompareHeaderBlocks(spdy::SpdyHeaderBlock decoded_header_list, + spdy::SpdyHeaderBlock expected_header_list); + + bool encoder_stream_error_detected_; + test::NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_; + std::unique_ptr qpack_decoder_; + + // Objects necessary for decoding, one list element for each header block. + std::list decoders_; + + // Decoded header lists. + std::list decoded_header_lists_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_OFFLINE_DECODER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.cc new file mode 100644 index 00000000000..faaddcb2187 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" + +#include + +namespace quic { +namespace test { + +FragmentSizeGenerator FragmentModeToFragmentSizeGenerator( + FragmentMode fragment_mode) { + switch (fragment_mode) { + case FragmentMode::kSingleChunk: + return []() { return std::numeric_limits::max(); }; + case FragmentMode::kOctetByOctet: + return []() { return 1; }; + } +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h new file mode 100644 index 00000000000..08cab4e0b2c --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h @@ -0,0 +1,47 @@ +// Copyright (c) 2018 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_TEST_TOOLS_QPACK_QPACK_TEST_UTILS_H_ +#define QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_TEST_UTILS_H_ + +#include +#include + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +// Called repeatedly to determine the size of each fragment when encoding or +// decoding. Must return a positive value. +using FragmentSizeGenerator = std::function; + +enum class FragmentMode { + kSingleChunk, + kOctetByOctet, +}; + +FragmentSizeGenerator FragmentModeToFragmentSizeGenerator( + FragmentMode fragment_mode); + +// Mock QpackUnidirectionalStreamSenderDelegate implementation. +class MockQpackStreamSenderDelegate : public QpackStreamSenderDelegate { + public: + ~MockQpackStreamSenderDelegate() override = default; + + MOCK_METHOD1(WriteStreamData, void(QuicStringPiece data)); +}; + +class NoopQpackStreamSenderDelegate : public QpackStreamSenderDelegate { + public: + ~NoopQpackStreamSenderDelegate() override = default; + + void WriteStreamData(QuicStringPiece /*data*/) override {} +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_TEST_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc deleted file mode 100644 index 9719bdb9b7a..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h" - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" - -namespace quic { -namespace test { - -// static -QpackHeaderTable* QpackEncoderPeer::header_table(QpackEncoder* encoder) { - return &encoder->header_table_; -} - -// static -uint64_t QpackEncoderPeer::maximum_blocked_streams( - const QpackEncoder* encoder) { - return encoder->maximum_blocked_streams_; -} - -// static -uint64_t QpackEncoderPeer::smallest_blocking_index( - const QpackEncoder* encoder) { - return encoder->blocking_manager_.smallest_blocking_index(); -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h deleted file mode 100644 index 2edf4274611..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_ENCODER_PEER_H_ -#define QUICHE_QUIC_TEST_TOOLS_QPACK_ENCODER_PEER_H_ - -#include - -namespace quic { - -class QpackEncoder; -class QpackHeaderTable; - -namespace test { - -class QpackEncoderPeer { - public: - QpackEncoderPeer() = delete; - - static QpackHeaderTable* header_table(QpackEncoder* encoder); - static uint64_t maximum_blocked_streams(const QpackEncoder* encoder); - static uint64_t smallest_blocking_index(const QpackEncoder* encoder); -}; - -} // namespace test - -} // namespace quic - -#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_ENCODER_PEER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc deleted file mode 100644 index bb18731dae7..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h" - -#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" - -namespace quic { -namespace test { - -// static -uint64_t QpackHeaderTablePeer::dynamic_table_capacity( - const QpackHeaderTable* header_table) { - return header_table->dynamic_table_capacity_; -} - -// static -uint64_t QpackHeaderTablePeer::maximum_dynamic_table_capacity( - const QpackHeaderTable* header_table) { - return header_table->maximum_dynamic_table_capacity_; -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h deleted file mode 100644 index cbf3f448a28..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_HEADER_TABLE_PEER_H_ -#define QUICHE_QUIC_TEST_TOOLS_QPACK_HEADER_TABLE_PEER_H_ - -#include - -namespace quic { - -class QpackHeaderTable; - -namespace test { - -class QpackHeaderTablePeer { - public: - QpackHeaderTablePeer() = delete; - - static uint64_t dynamic_table_capacity(const QpackHeaderTable* header_table); - static uint64_t maximum_dynamic_table_capacity( - const QpackHeaderTable* header_table); -}; - -} // namespace test - -} // namespace quic - -#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_HEADER_TABLE_PEER_H_ 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 02775caf901..7b9264c31b8 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 @@ -9,7 +9,6 @@ #include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h" namespace quic { @@ -36,23 +35,10 @@ void QuicConnectionPeer::PopulateStopWaitingFrame( connection->PopulateStopWaitingFrame(stop_waiting); } -// static -QuicConnectionVisitorInterface* QuicConnectionPeer::GetVisitor( - QuicConnection* connection) { - return connection->visitor_; -} - // static QuicPacketCreator* QuicConnectionPeer::GetPacketCreator( QuicConnection* connection) { - return QuicPacketGeneratorPeer::GetPacketCreator( - &connection->packet_generator_); -} - -// static -QuicPacketGenerator* QuicConnectionPeer::GetPacketGenerator( - QuicConnection* connection) { - return &connection->packet_generator_; + return &connection->packet_creator_; } // static @@ -226,22 +212,7 @@ QuicConnectionStats* QuicConnectionPeer::GetStats(QuicConnection* connection) { // static QuicPacketCount QuicConnectionPeer::GetPacketsBetweenMtuProbes( QuicConnection* connection) { - if (connection->mtu_discovery_v2_) { - return connection->mtu_discoverer_.packets_between_probes(); - } - return connection->packets_between_mtu_probes_; -} - -// static -void QuicConnectionPeer::SetPacketsBetweenMtuProbes(QuicConnection* connection, - QuicPacketCount packets) { - connection->packets_between_mtu_probes_ = packets; -} - -// static -void QuicConnectionPeer::SetNextMtuProbeAt(QuicConnection* connection, - QuicPacketNumber number) { - connection->next_mtu_probe_at_ = number; + return connection->mtu_discoverer_.packets_between_probes(); } // static @@ -307,16 +278,14 @@ void QuicConnectionPeer::SetMaxTrackedPackets( connection->max_tracked_packets_ = max_tracked_packets; } -// static -void QuicConnectionPeer::SetSessionDecidesWhatToWrite( - QuicConnection* connection) { - connection->sent_packet_manager_.SetSessionDecideWhatToWrite(true); - connection->packet_generator_.SetCanSetTransmissionType(true); -} - // static void QuicConnectionPeer::SetNegotiatedVersion(QuicConnection* connection) { connection->version_negotiated_ = true; + if (connection->perspective() == Perspective::IS_SERVER && + !QuicFramerPeer::infer_packet_header_type_from_version( + &connection->framer_)) { + connection->framer_.InferPacketHeaderTypeFromVersion(); + } } // static @@ -364,5 +333,18 @@ void QuicConnectionPeer::SendConnectionClosePacket(QuicConnection* connection, connection->SendConnectionClosePacket(error, details); } +// static +size_t QuicConnectionPeer::GetNumEncryptionLevels(QuicConnection* connection) { + size_t count = 0; + for (EncryptionLevel level : + {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, + ENCRYPTION_FORWARD_SECURE}) { + if (connection->framer_.HasEncrypterOfEncryptionLevel(level)) { + ++count; + } + } + return count; +} + } // 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 c5c972f9cc0..b7140ded5ed 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 @@ -20,7 +20,6 @@ class QuicConnectionVisitorInterface; class QuicEncryptedPacket; class QuicFramer; class QuicPacketCreator; -class QuicPacketGenerator; class QuicPacketWriter; class QuicSentPacketManager; class SendAlgorithmInterface; @@ -41,12 +40,8 @@ class QuicConnectionPeer { static void PopulateStopWaitingFrame(QuicConnection* connection, QuicStopWaitingFrame* stop_waiting); - static QuicConnectionVisitorInterface* GetVisitor(QuicConnection* connection); - static QuicPacketCreator* GetPacketCreator(QuicConnection* connection); - static QuicPacketGenerator* GetPacketGenerator(QuicConnection* connection); - static QuicSentPacketManager* GetSentPacketManager( QuicConnection* connection); @@ -107,10 +102,6 @@ class QuicConnectionPeer { static QuicPacketCount GetPacketsBetweenMtuProbes(QuicConnection* connection); - static void SetPacketsBetweenMtuProbes(QuicConnection* connection, - QuicPacketCount packets); - static void SetNextMtuProbeAt(QuicConnection* connection, - QuicPacketNumber number); static void ReInitializeMtuDiscoverer( QuicConnection* connection, QuicPacketCount packets_between_probes_base, @@ -127,7 +118,6 @@ class QuicConnectionPeer { bool no_stop_waiting_frames); static void SetMaxTrackedPackets(QuicConnection* connection, QuicPacketCount max_tracked_packets); - static void SetSessionDecidesWhatToWrite(QuicConnection* connection); static void SetNegotiatedVersion(QuicConnection* connection); static void SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames( QuicConnection* connection, @@ -143,6 +133,8 @@ class QuicConnectionPeer { static void SendConnectionClosePacket(QuicConnection* connection, QuicErrorCode error, const std::string& details); + + static size_t GetNumEncryptionLevels(QuicConnection* connection); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc index 2590834891c..b460165d906 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc @@ -10,6 +10,12 @@ namespace quic { namespace test { +// static +QuicTimeWaitListManager* QuicDispatcherPeer::GetTimeWaitListManager( + QuicDispatcher* dispatcher) { + return dispatcher->time_wait_list_manager_.get(); +} + // static void QuicDispatcherPeer::SetTimeWaitListManager( QuicDispatcher* dispatcher, @@ -77,8 +83,7 @@ const QuicDispatcher::SessionMap& QuicDispatcherPeer::session_map( void QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop( QuicDispatcher* dispatcher, size_t num_session_allowed) { - return dispatcher->set_new_sessions_allowed_per_event_loop( - num_session_allowed); + dispatcher->new_sessions_allowed_per_event_loop_ = num_session_allowed; } // static diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h index a888b4e0967..7cb4c92c5a9 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h @@ -17,6 +17,9 @@ class QuicDispatcherPeer { public: QuicDispatcherPeer() = delete; + static QuicTimeWaitListManager* GetTimeWaitListManager( + QuicDispatcher* dispatcher); + static void SetTimeWaitListManager( QuicDispatcher* dispatcher, QuicTimeWaitListManager* time_wait_list_manager); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h index 661def5493a..d462555a104 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h @@ -187,6 +187,10 @@ class QuicFramerPeer { uint64_t current_received_frame_type) { framer->current_received_frame_type_ = current_received_frame_type; } + + static bool infer_packet_header_type_from_version(QuicFramer* framer) { + return framer->infer_packet_header_type_from_version_; + } }; } // 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 d4e5598ffa0..7c8db91da7f 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 @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h" #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" @@ -63,6 +64,11 @@ void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator, creator->packet_.packet_number = QuicPacketNumber(s); } +void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator, + QuicPacketNumber num) { + creator->packet_.packet_number = num; +} + // static void QuicPacketCreatorPeer::ClearPacketNumber(QuicPacketCreator* creator) { creator->packet_.packet_number.Clear(); @@ -102,14 +108,13 @@ SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames( DCHECK(creator->queued_frames_.empty()); DCHECK(!frames.empty()); for (const QuicFrame& frame : frames) { - bool success = creator->AddFrame(frame, false, NOT_RETRANSMISSION); + bool success = creator->AddFrame(frame, NOT_RETRANSMISSION); DCHECK(success); } creator->SerializePacket(buffer, buffer_len); - SerializedPacket packet = creator->packet_; + SerializedPacket packet = std::move(creator->packet_); // The caller takes ownership of the QuicEncryptedPacket. creator->packet_.encrypted_buffer = nullptr; - DCHECK(packet.retransmittable_frames.empty()); return packet; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h index e040090f6dd..88587a212b5 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h @@ -31,6 +31,7 @@ class QuicPacketCreatorPeer { static QuicVariableLengthIntegerLength GetLengthLength( QuicPacketCreator* creator); static void SetPacketNumber(QuicPacketCreator* creator, uint64_t s); + static void SetPacketNumber(QuicPacketCreator* creator, QuicPacketNumber num); static void ClearPacketNumber(QuicPacketCreator* creator); static void FillPacketHeader(QuicPacketCreator* creator, QuicPacketHeader* header); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.cc deleted file mode 100644 index 91a875282c2..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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 "net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h" - -#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" -#include "net/third_party/quiche/src/quic/core/quic_packet_generator.h" - -namespace quic { -namespace test { - -// static -QuicPacketCreator* QuicPacketGeneratorPeer::GetPacketCreator( - QuicPacketGenerator* generator) { - return &generator->packet_creator_; -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h deleted file mode 100644 index 6941b089d23..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 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_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_ -#define QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_ - -#include "net/third_party/quiche/src/quic/core/quic_packets.h" - -namespace quic { - -class QuicPacketCreator; -class QuicPacketGenerator; - -namespace test { - -class QuicPacketGeneratorPeer { - public: - QuicPacketGeneratorPeer() = delete; - - static QuicPacketCreator* GetPacketCreator(QuicPacketGenerator* generator); -}; - -} // namespace test - -} // namespace quic - -#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc index b680f66d815..cd8297a961e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc @@ -86,18 +86,9 @@ bool QuicSentPacketManagerPeer::IsRetransmission( if (!HasRetransmittableFrames(sent_packet_manager, packet_number)) { return false; } - if (sent_packet_manager->session_decides_what_to_write()) { - return sent_packet_manager->unacked_packets_ - .GetTransmissionInfo(QuicPacketNumber(packet_number)) - .transmission_type != NOT_RETRANSMISSION; - } - for (auto transmission_info : sent_packet_manager->unacked_packets_) { - if (transmission_info.retransmission.IsInitialized() && - transmission_info.retransmission == QuicPacketNumber(packet_number)) { - return true; - } - } - return false; + return sent_packet_manager->unacked_packets_ + .GetTransmissionInfo(QuicPacketNumber(packet_number)) + .transmission_type != NOT_RETRANSMISSION; } // static @@ -223,5 +214,12 @@ bool QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled( .use_adaptive_reordering_threshold(); } +// static +bool QuicSentPacketManagerPeer::AdaptiveTimeThresholdEnabled( + QuicSentPacketManager* sent_packet_manager) { + return sent_packet_manager->uber_loss_algorithm_.general_loss_algorithms_[0] + .use_adaptive_time_threshold(); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h index 6be8b46308f..3927189ee3f 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h @@ -98,6 +98,9 @@ class QuicSentPacketManagerPeer { static bool AdaptiveReorderingThresholdEnabled( QuicSentPacketManager* sent_packet_manager); + + static bool AdaptiveTimeThresholdEnabled( + QuicSentPacketManager* sent_packet_manager); }; } // namespace test 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 001f1ca2b87..f9e785d2c98 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 @@ -225,15 +225,6 @@ QuicStreamIdManager* QuicSessionPeer::v99_unidirectional_stream_id_manager( return &session->v99_streamid_manager_.unidirectional_stream_id_manager_; } -// static -void QuicSessionPeer::SendRstStreamInner(QuicSession* session, - QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written, - bool close_write_side_only) { - session->SendRstStreamInner(id, error, bytes_written, close_write_side_only); -} - // static PendingStream* QuicSessionPeer::GetPendingStream(QuicSession* session, QuicStreamId stream_id) { 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 eed3bddcf88..446cd67b176 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 @@ -79,11 +79,6 @@ class QuicSessionPeer { QuicSession* session); static QuicStreamIdManager* v99_unidirectional_stream_id_manager( QuicSession* session); - static void SendRstStreamInner(QuicSession* session, - QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written, - bool close_write_side_only); static PendingStream* GetPendingStream(QuicSession* session, QuicStreamId stream_id); static void set_is_configured(QuicSession* session, bool value); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc index d501debb7e3..42961984527 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc @@ -29,7 +29,7 @@ void QuicStreamPeer::SetStreamBytesWritten( // static bool QuicStreamPeer::read_side_closed(QuicStream* stream) { - return stream->read_side_closed(); + return stream->read_side_closed_; } // static diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h index f61cb0049a5..3adb173b91d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h @@ -20,6 +20,10 @@ class QuicStreamSendBufferPeer { QuicStreamSendBuffer* send_buffer); static QuicByteCount TotalLength(QuicStreamSendBuffer* send_buffer); + + static int32_t write_index(QuicStreamSendBuffer* send_buffer) { + return send_buffer->write_index_; + } }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc index 36d2b04ee60..b3bf224df4e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc @@ -7,6 +7,7 @@ #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/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" typedef quic::QuicStreamSequencerBuffer::BufferBlock BufferBlock; @@ -28,8 +29,8 @@ size_t QuicStreamSequencerBufferPeer::Read(char* dest_buffer, size_t size) { dest.iov_base = dest_buffer, dest.iov_len = size; size_t bytes_read; std::string error_details; - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->Readv(&dest, 1, &bytes_read, &error_details)); + EXPECT_THAT(buffer_->Readv(&dest, 1, &bytes_read, &error_details), + IsQuicNoError()); return bytes_read; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc index 237d9f66d8f..ca5e95ab0f6 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc @@ -382,7 +382,9 @@ ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) { QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId( session->transport_version(), 0); - session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0); + QuicStream* stream = session->GetOrCreateStream(stream_id); + session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, + stream->stream_bytes_written()); return ret; } 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 a893830102e..81b54d47260 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 @@ -230,12 +230,20 @@ ImmediateGoAwaySession::ImmediateGoAwaySession( quic_simple_server_backend) {} void ImmediateGoAwaySession::OnStreamFrame(const QuicStreamFrame& frame) { - SendGoAway(QUIC_PEER_GOING_AWAY, ""); + if (VersionUsesHttp3(transport_version())) { + SendHttp3GoAway(); + } else { + SendGoAway(QUIC_PEER_GOING_AWAY, ""); + } QuicSimpleServerSession::OnStreamFrame(frame); } void ImmediateGoAwaySession::OnCryptoFrame(const QuicCryptoFrame& frame) { - SendGoAway(QUIC_PEER_GOING_AWAY, ""); + // In IETF QUIC, GOAWAY lives up in HTTP/3 layer. Even if it's a immediate + // goaway session, goaway shouldn't be sent when crypto frame is received. + if (!VersionUsesHttp3(transport_version())) { + SendGoAway(QUIC_PEER_GOING_AWAY, ""); + } QuicSimpleServerSession::OnCryptoFrame(frame); } 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 ff0239213a2..4b10826660b 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 @@ -22,12 +22,12 @@ #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_endian.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" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" using testing::_; @@ -44,14 +44,14 @@ QuicConnectionId TestConnectionId() { QuicConnectionId TestConnectionId(uint64_t connection_number) { const uint64_t connection_id64_net = - QuicEndian::HostToNet64(connection_number); + quiche::QuicheEndian::HostToNet64(connection_number); return QuicConnectionId(reinterpret_cast(&connection_id64_net), sizeof(connection_id64_net)); } QuicConnectionId TestConnectionIdNineBytesLong(uint64_t connection_number) { const uint64_t connection_number_net = - QuicEndian::HostToNet64(connection_number); + quiche::QuicheEndian::HostToNet64(connection_number); char connection_id_bytes[9] = {}; static_assert( sizeof(connection_id_bytes) == 1 + sizeof(connection_number_net), @@ -67,7 +67,7 @@ uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) { memcpy(&connection_id64_net, connection_id.data(), std::min(static_cast(connection_id.length()), sizeof(connection_id64_net))); - return QuicEndian::NetToHost64(connection_id64_net); + return quiche::QuicheEndian::NetToHost64(connection_id64_net); } QuicAckFrame InitAckFrame(const std::vector& ack_blocks) { @@ -531,7 +531,7 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) { // Transfer ownership of the packet to the SentPacketManager and the // ack notifier to the AckNotifierManager. QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( - packet, QuicPacketNumber(), clock_.ApproximateNow(), NOT_RETRANSMISSION, + packet, clock_.ApproximateNow(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); } @@ -576,7 +576,7 @@ QuicConsumedData MockQuicSession::ConsumeData(QuicStream* stream, StreamSendingState state) { if (write_length > 0) { auto buf = std::make_unique(write_length); - QuicDataWriter writer(write_length, buf.get(), HOST_BYTE_ORDER); + QuicDataWriter writer(write_length, buf.get(), quiche::HOST_BYTE_ORDER); stream->WriteStreamData(offset, write_length, &writer); } else { DCHECK(state != NO_FIN); @@ -652,7 +652,6 @@ TestQuicSpdyServerSession::TestQuicSpdyServerSession( &helper_, crypto_config, compressed_certs_cache) { - Initialize(); ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _)) .WillByDefault(testing::Return(true)); } @@ -992,7 +991,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( QuicConnectionIdIncluded destination_connection_id_included, QuicConnectionIdIncluded source_connection_id_included, QuicPacketNumberLength packet_number_length, - ParsedQuicVersionVector* versions, + ParsedQuicVersion version, Perspective perspective) { QuicPacketHeader header; header.destination_connection_id = destination_connection_id; @@ -1004,7 +1003,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( header.reset_flag = reset_flag; header.packet_number_length = packet_number_length; header.packet_number = QuicPacketNumber(packet_number); - if (QuicVersionHasLongHeaderLengths((*versions)[0].transport_version) && + if (QuicVersionHasLongHeaderLengths(version.transport_version) && version_flag) { header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; @@ -1012,10 +1011,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( QuicFrame frame(QuicStreamFrame(1, false, 0, QuicStringPiece(data))); QuicFrames frames; frames.push_back(frame); - ParsedQuicVersion version = - (versions != nullptr ? *versions : AllSupportedVersions())[0]; - QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(), - QuicTime::Zero(), perspective, + QuicFramer framer({version}, QuicTime::Zero(), perspective, kQuicDefaultConnectionIdLength); framer.SetInitialObfuscators(destination_connection_id); EncryptionLevel level = @@ -1184,6 +1180,7 @@ void CreateServerSessionForTest( *server_session = new TestQuicSpdyServerSession( *server_connection, DefaultQuicConfig(), supported_versions, server_crypto_config, compressed_certs_cache); + (*server_session)->Initialize(); // We advance the clock initially because the default time is zero and the // strike register worries that we've just overflowed a uint32_t time. 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 be6e84d7746..7919ef30299 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 @@ -23,6 +23,7 @@ #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.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_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.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" @@ -161,7 +162,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( QuicConnectionIdIncluded destination_connection_id_included, QuicConnectionIdIncluded source_connection_id_included, QuicPacketNumberLength packet_number_length, - ParsedQuicVersionVector* versions, + ParsedQuicVersion version, Perspective perspective); void CompareCharArraysWithHexError(const std::string& description, @@ -412,7 +413,8 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD1(OnMaxStreamsFrame, bool(const QuicMaxStreamsFrame& frame)); MOCK_METHOD1(OnStreamsBlockedFrame, bool(const QuicStreamsBlockedFrame& frame)); - MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame)); + MOCK_METHOD1(OnStopSendingFrame, void(const QuicStopSendingFrame& frame)); + MOCK_METHOD1(OnPacketDecrypted, void(EncryptionLevel)); }; class MockQuicConnectionHelper : public QuicConnectionHelperInterface { @@ -533,7 +535,8 @@ class MockQuicConnection : public QuicConnection { MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode)); MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame)); - MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicMemSliceSpan)); + MOCK_METHOD3(SendMessage, + MessageStatus(QuicMessageId, QuicMemSliceSpan, bool)); MOCK_METHOD3(OnConnectionClosed, void(QuicErrorCode error, const std::string& error_details, @@ -666,6 +669,12 @@ class MockQuicSession : public QuicSession { QuicStreamOffset offset, StreamSendingState state); + void ReallySendRstStream(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written) { + QuicSession::SendRstStream(id, error, bytes_written); + } + private: std::unique_ptr crypto_stream_; }; @@ -681,6 +690,7 @@ class MockQuicCryptoStream : public QuicCryptoStream { const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; CryptoMessageParser* crypto_message_parser() override; + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} private: QuicReferenceCountedPointer params_; @@ -947,7 +957,9 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType()); MOCK_METHOD3(AdjustNetworkParameters, void(QuicBandwidth, QuicTime::Delta, bool)); + MOCK_METHOD1(AdjustNetworkParameters, void(const NetworkParams&)); MOCK_METHOD1(OnApplicationLimited, void(QuicByteCount)); + MOCK_CONST_METHOD1(PopulateConnectionStats, void(QuicConnectionStats*)); }; class MockLossAlgorithm : public LossDetectionInterface { @@ -966,11 +978,6 @@ class MockLossAlgorithm : public LossDetectionInterface { const AckedPacketVector& packets_acked, LostPacketVector* packets_lost)); MOCK_CONST_METHOD0(GetLossTimeout, QuicTime()); - MOCK_METHOD4(SpuriousRetransmitDetected, - void(const QuicUnackedPacketMap&, - QuicTime, - const RttStats&, - QuicPacketNumber)); MOCK_METHOD5(SpuriousLossDetected, void(const QuicUnackedPacketMap&, const RttStats&, @@ -1014,11 +1021,8 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&)); - MOCK_METHOD4(OnPacketSent, - void(const SerializedPacket&, - QuicPacketNumber, - TransmissionType, - QuicTime)); + MOCK_METHOD3(OnPacketSent, + void(const SerializedPacket&, TransmissionType, QuicTime)); MOCK_METHOD0(OnPingSent, void()); @@ -1195,8 +1199,6 @@ void ExpectApproxEq(T expected, T actual, float relative_margin) { template QuicHeaderList AsHeaderList(const T& container) { QuicHeaderList l; - // No need to enforce header list size limits again in this handler. - l.set_max_header_list_size(UINT_MAX); l.OnHeaderBlockStart(); size_t total_size = 0; for (auto p : container) { @@ -1254,6 +1256,46 @@ MATCHER_P2(InRange, min, max, "") { return arg >= min && arg <= max; } +// A GMock matcher that prints expected and actual QuicErrorCode strings +// upon failure. Example usage: +// EXPECT_THAT(stream_->connection_error()), IsError(QUIC_INTERNAL_ERROR)); +MATCHER_P(IsError, + expected, + QuicStrCat(negation ? "isn't equal to " : "is equal to ", + QuicErrorCodeToString(expected))) { + *result_listener << QuicErrorCodeToString(arg); + return arg == expected; +} + +// Shorthand for IsError(QUIC_NO_ERROR). +// Example usage: EXPECT_THAT(stream_->connection_error(), IsQuicNoError()); +MATCHER(IsQuicNoError, + QuicStrCat(negation ? "isn't equal to " : "is equal to ", + QuicErrorCodeToString(QUIC_NO_ERROR))) { + *result_listener << QuicErrorCodeToString(arg); + return arg == QUIC_NO_ERROR; +} + +// A GMock matcher that prints expected and actual QuicRstStreamErrorCode +// strings upon failure. Example usage: +// EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_INTERNAL_ERROR)); +MATCHER_P(IsStreamError, + expected, + QuicStrCat(negation ? "isn't equal to " : "is equal to ", + QuicRstStreamErrorCodeToString(expected))) { + *result_listener << QuicRstStreamErrorCodeToString(arg); + return arg == expected; +} + +// Shorthand for IsStreamError(QUIC_STREAM_NO_ERROR). Example usage: +// EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); +MATCHER(IsQuicStreamNoError, + QuicStrCat(negation ? "isn't equal to " : "is equal to ", + QuicRstStreamErrorCodeToString(QUIC_STREAM_NO_ERROR))) { + *result_listener << QuicRstStreamErrorCodeToString(arg); + return arg == QUIC_STREAM_NO_ERROR; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h new file mode 100644 index 00000000000..c6a8b46496e --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h @@ -0,0 +1,36 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_TRANSPORT_TEST_TOOLS_H_ +#define QUICHE_QUIC_TEST_TOOLS_QUIC_TRANSPORT_TEST_TOOLS_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h" + +namespace quic { +namespace test { + +class MockClientVisitor : public QuicTransportClientSession::ClientVisitor { + public: + MOCK_METHOD0(OnIncomingBidirectionalStreamAvailable, void()); + MOCK_METHOD0(OnIncomingUnidirectionalStreamAvailable, void()); +}; + +class MockServerVisitor : public QuicTransportServerSession::ServerVisitor { + public: + MOCK_METHOD1(CheckOrigin, bool(url::Origin)); +}; + +class MockStreamVisitor : public QuicTransportStream::Visitor { + public: + MOCK_METHOD0(OnCanRead, void()); + MOCK_METHOD0(OnFinRead, void()); + MOCK_METHOD0(OnCanWrite, void()); +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_TRANSPORT_TEST_TOOLS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc index be03aa1c869..588f3b66d43 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc @@ -59,7 +59,9 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { return true; } - void OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) override {} + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override { + coalesced_packet_ = packet.Clone(); + } void OnUndecryptablePacket(const QuicEncryptedPacket& /*packet*/, EncryptionLevel /*decryption_level*/, @@ -253,6 +255,9 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { return version_negotiation_packet_.get(); } EncryptionLevel last_decrypted_level() const { return last_decrypted_level_; } + const QuicEncryptedPacket* coalesced_packet() const { + return coalesced_packet_.get(); + } private: QuicErrorCode error_; @@ -284,6 +289,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { std::vector> stream_data_; std::vector> crypto_data_; EncryptionLevel last_decrypted_level_; + std::unique_ptr coalesced_packet_; }; SimpleQuicFramer::SimpleQuicFramer() @@ -404,5 +410,9 @@ const std::vector& SimpleQuicFramer::padding_frames() const { return visitor_->padding_frames(); } +const QuicEncryptedPacket* SimpleQuicFramer::coalesced_packet() const { + return visitor_->coalesced_packet(); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h index a254ce523e9..3e063d07334 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h @@ -50,6 +50,7 @@ class SimpleQuicFramer { const std::vector& padding_frames() const; const QuicVersionNegotiationPacket* version_negotiation_packet() const; EncryptionLevel last_decrypted_level() const; + const QuicEncryptedPacket* coalesced_packet() const; QuicFramer* framer(); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc new file mode 100644 index 00000000000..7787fbeb059 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc @@ -0,0 +1,28 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" + +namespace quic { +namespace test { + +void SimpleSessionCache::Insert(const QuicServerId& server_id, + std::unique_ptr state) { + cache_entries_.insert(std::make_pair(server_id, std::move(state))); +} + +std::unique_ptr SimpleSessionCache::Lookup( + const QuicServerId& server_id, + const SSL_CTX* /*ctx*/) { + auto it = cache_entries_.find(server_id); + if (it == cache_entries_.end()) { + return nullptr; + } + std::unique_ptr state = std::move(it->second); + cache_entries_.erase(it); + return state; +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h new file mode 100644 index 00000000000..40a6946dfde --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_ +#define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" + +namespace quic { +namespace test { + +// SimpleSessionCache provides a simple implementation of SessionCache that +// stores only one QuicResumptionState per QuicServerId. No limit is placed on +// the total number of entries in the cache. When Lookup is called, if a cache +// entry exists for the provided QuicServerId, the entry will be removed from +// the cached when it is returned. +class SimpleSessionCache : public SessionCache { + public: + SimpleSessionCache() = default; + ~SimpleSessionCache() override = default; + + void Insert(const QuicServerId& server_id, + std::unique_ptr state) override; + std::unique_ptr Lookup(const QuicServerId& server_id, + const SSL_CTX* ctx) override; + + private: + std::map> cache_entries_; +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc index 72a23d73178..9e67c899f51 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc @@ -46,7 +46,6 @@ QuicConsumedData SimpleSessionNotifier::WriteOrBufferData( StreamState& stream_state = stream_map_.find(id)->second; const bool had_buffered_data = HasBufferedStreamData() || HasBufferedControlFrames(); - QuicConsumedData total_consumed(0, false); QuicStreamOffset offset = stream_state.bytes_sent; QUIC_DVLOG(1) << "WriteOrBuffer stream_id: " << id << " [" << offset << ", " << offset + data_length << "), fin: " << (state != NO_FIN); @@ -127,8 +126,13 @@ void SimpleSessionNotifier::WriteOrBufferPing() { } void SimpleSessionNotifier::NeuterUnencryptedData() { - // TODO(nharper): Handle CRYPTO frame case. if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_INITIAL]) { + QuicCryptoFrame crypto_frame(ENCRYPTION_INITIAL, interval.min(), + interval.max() - interval.min()); + OnFrameAcked(QuicFrame(&crypto_frame), QuicTime::Delta::Zero(), + QuicTime::Zero()); + } return; } for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_INITIAL]) { 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 93f11aa387d..4dc48a7c1d5 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 @@ -42,7 +42,7 @@ class SimpleSessionNotifierTest : public QuicTest { : connection_(&helper_, &alarm_factory_, Perspective::IS_CLIENT), notifier_(&connection_) { connection_.set_visitor(&visitor_); - QuicConnectionPeer::SetSessionDecidesWhatToWrite(&connection_); + connection_.SetSessionNotifier(¬ifier_); EXPECT_FALSE(notifier_.WillingToWrite()); EXPECT_EQ(0u, notifier_.StreamBytesSent()); EXPECT_FALSE(notifier_.HasBufferedStreamData()); @@ -135,6 +135,8 @@ TEST_F(SimpleSessionNotifierTest, WriteOrBufferPing) { TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) { if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + // This test writes crypto data through crypto streams. It won't work when + // crypto frames are used instead. return; } InSequence s; @@ -175,6 +177,8 @@ TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) { TEST_F(SimpleSessionNotifierTest, OnCanWrite) { if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + // This test writes crypto data through crypto streams. It won't work when + // crypto frames are used instead. return; } InSequence s; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc index bd01c43d252..9f504359dbf 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h" +#include #include #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" @@ -23,89 +24,41 @@ const QuicStreamId kDataStream = 3; const QuicByteCount kWriteChunkSize = 128 * 1024; const char kStreamDataContents = 'Q'; -// Takes a SHA-1 hash of the name and converts it into five 32-bit integers. -static std::vector HashNameIntoFive32BitIntegers(std::string name) { - const std::string hash = test::Sha1Hash(name); - - std::vector output; - uint32_t current_number = 0; - for (size_t i = 0; i < hash.size(); i++) { - current_number = (current_number << 8) + hash[i]; - if (i % 4 == 3) { - output.push_back(i); - current_number = 0; - } - } - - return output; -} - -QuicSocketAddress GetAddressFromName(std::string name) { - const std::vector hash = HashNameIntoFive32BitIntegers(name); - - // Generate a random port between 1025 and 65535. - const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1); - - // Generate a random 10.x.x.x address, where x is between 1 and 254. - std::string ip_address{"\xa\0\0\0", 4}; - for (size_t i = 1; i < 4; i++) { - ip_address[i] = 1 + hash[i] % 254; - } - QuicIpAddress host; - host.FromPackedString(ip_address.c_str(), ip_address.length()); - return QuicSocketAddress(host, port); -} - QuicEndpoint::QuicEndpoint(Simulator* simulator, std::string name, std::string peer_name, Perspective perspective, QuicConnectionId connection_id) - : Endpoint(simulator, name), - peer_name_(peer_name), - writer_(this), - nic_tx_queue_(simulator, - QuicStringPrintf("%s (TX Queue)", name.c_str()), - kMaxOutgoingPacketSize * kTxQueueSize), - connection_(connection_id, - GetAddressFromName(peer_name), - simulator, - simulator->GetAlarmFactory(), - &writer_, - false, - perspective, - ParsedVersionOfIndex(CurrentSupportedVersions(), 0)), + : QuicEndpointBase(simulator, name, peer_name), bytes_to_transfer_(0), bytes_transferred_(0), - write_blocked_count_(0), wrong_data_received_(false), - drop_next_packet_(false), notifier_(nullptr) { - nic_tx_queue_.set_listener_interface(this); - - connection_.SetSelfAddress(GetAddressFromName(name)); - connection_.set_visitor(this); - connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, - std::make_unique(perspective)); - connection_.SetEncrypter(ENCRYPTION_INITIAL, nullptr); - if (connection_.version().KnowsWhichDecrypterToUse()) { - connection_.InstallDecrypter(ENCRYPTION_FORWARD_SECURE, - std::make_unique(perspective)); - connection_.RemoveDecrypter(ENCRYPTION_INITIAL); + connection_ = std::make_unique( + connection_id, GetAddressFromName(peer_name), simulator, + simulator->GetAlarmFactory(), &writer_, false, perspective, + ParsedVersionOfIndex(CurrentSupportedVersions(), 0)); + connection_->SetSelfAddress(GetAddressFromName(name)); + connection_->set_visitor(this); + connection_->SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique(perspective)); + connection_->SetEncrypter(ENCRYPTION_INITIAL, nullptr); + if (connection_->version().KnowsWhichDecrypterToUse()) { + connection_->InstallDecrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique(perspective)); + connection_->RemoveDecrypter(ENCRYPTION_INITIAL); } else { - connection_.SetDecrypter(ENCRYPTION_FORWARD_SECURE, - std::make_unique(perspective)); + connection_->SetDecrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique(perspective)); } - connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); if (perspective == Perspective::IS_SERVER) { // Skip version negotiation. - test::QuicConnectionPeer::SetNegotiatedVersion(&connection_); - } - connection_.SetDataProducer(&producer_); - connection_.SetSessionNotifier(this); - if (connection_.session_decides_what_to_write()) { - notifier_ = std::make_unique(&connection_); + test::QuicConnectionPeer::SetNegotiatedVersion(connection_.get()); } + connection_->SetDataProducer(&producer_); + connection_->SetSessionNotifier(this); + notifier_ = std::make_unique(connection_.get()); // Configure the connection as if it received a handshake. This is important // primarily because @@ -122,19 +75,7 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator, peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT, &error); DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error; - connection_.SetFromConfig(config); -} - -QuicEndpoint::~QuicEndpoint() { - if (trace_visitor_ != nullptr) { - const char* perspective_prefix = - connection_.perspective() == Perspective::IS_CLIENT ? "C" : "S"; - - std::string identifier = - QuicStrCat(perspective_prefix, connection_.connection_id().ToString()); - QuicRecordTestOutput(identifier, - trace_visitor_->trace()->SerializeAsString()); - } + connection_->SetFromConfig(config); } QuicByteCount QuicEndpoint::bytes_received() const { @@ -176,48 +117,6 @@ void QuicEndpoint::AddBytesToTransfer(QuicByteCount bytes) { WriteStreamData(); } -void QuicEndpoint::DropNextIncomingPacket() { - drop_next_packet_ = true; -} - -void QuicEndpoint::RecordTrace() { - trace_visitor_ = std::make_unique(&connection_); - connection_.set_debug_visitor(trace_visitor_.get()); -} - -void QuicEndpoint::AcceptPacket(std::unique_ptr packet) { - if (packet->destination != name_) { - return; - } - if (drop_next_packet_) { - drop_next_packet_ = false; - return; - } - - QuicReceivedPacket received_packet(packet->contents.data(), - packet->contents.size(), clock_->Now()); - connection_.ProcessUdpPacket(connection_.self_address(), - connection_.peer_address(), received_packet); -} - -UnconstrainedPortInterface* QuicEndpoint::GetRxPort() { - return this; -} - -void QuicEndpoint::SetTxPort(ConstrainedPortInterface* port) { - // Any egress done by the endpoint is actually handled by a queue on an NIC. - nic_tx_queue_.set_tx_port(port); -} - -void QuicEndpoint::OnPacketDequeued() { - if (writer_.IsWriteBlocked() && - (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >= - kMaxOutgoingPacketSize) { - writer_.SetWritable(); - connection_.OnCanWrite(); - } -} - void QuicEndpoint::OnStreamFrame(const QuicStreamFrame& frame) { // Verify that the data received always matches the expected. DCHECK(frame.stream_id == kDataStream); @@ -302,73 +201,6 @@ bool QuicEndpoint::HasUnackedStreamData() const { return false; } -QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint) - : endpoint_(endpoint), is_blocked_(false) {} - -QuicEndpoint::Writer::~Writer() {} - -WriteResult QuicEndpoint::Writer::WritePacket( - const char* buffer, - size_t buf_len, - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/, - PerPacketOptions* options) { - DCHECK(!IsWriteBlocked()); - DCHECK(options == nullptr); - DCHECK(buf_len <= kMaxOutgoingPacketSize); - - // Instead of losing a packet, become write-blocked when the egress queue is - // full. - if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) { - is_blocked_ = true; - endpoint_->write_blocked_count_++; - return WriteResult(WRITE_STATUS_BLOCKED, 0); - } - - auto packet = std::make_unique(); - packet->source = endpoint_->name(); - packet->destination = endpoint_->peer_name_; - packet->tx_timestamp = endpoint_->clock_->Now(); - - packet->contents = std::string(buffer, buf_len); - packet->size = buf_len; - - endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet)); - - return WriteResult(WRITE_STATUS_OK, buf_len); -} - -bool QuicEndpoint::Writer::IsWriteBlocked() const { - return is_blocked_; -} - -void QuicEndpoint::Writer::SetWritable() { - is_blocked_ = false; -} - -QuicByteCount QuicEndpoint::Writer::GetMaxPacketSize( - const QuicSocketAddress& /*peer_address*/) const { - return kMaxOutgoingPacketSize; -} - -bool QuicEndpoint::Writer::SupportsReleaseTime() const { - return false; -} - -bool QuicEndpoint::Writer::IsBatchMode() const { - return false; -} - -char* QuicEndpoint::Writer::GetNextWriteLocation( - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/) { - return nullptr; -} - -WriteResult QuicEndpoint::Writer::Flush() { - return WriteResult(WRITE_STATUS_OK, 0); -} - WriteStreamDataResult QuicEndpoint::DataProducer::WriteStreamData( QuicStreamId /*id*/, QuicStreamOffset /*offset*/, @@ -388,14 +220,14 @@ bool QuicEndpoint::DataProducer::WriteCryptoData(EncryptionLevel /*level*/, void QuicEndpoint::WriteStreamData() { // Instantiate a flusher which would normally be here due to QuicSession. - QuicConnection::ScopedPacketFlusher flusher(&connection_); + QuicConnection::ScopedPacketFlusher flusher(connection_.get()); while (bytes_to_transfer_ > 0) { // Transfer data in chunks of size at most |kWriteChunkSize|. const size_t transmission_size = std::min(kWriteChunkSize, bytes_to_transfer_); - QuicConsumedData consumed_data = connection_.SendStreamData( + QuicConsumedData consumed_data = connection_->SendStreamData( kDataStream, transmission_size, bytes_transferred_, NO_FIN); DCHECK(consumed_data.bytes_consumed <= transmission_size); @@ -407,33 +239,5 @@ void QuicEndpoint::WriteStreamData() { } } -QuicEndpointMultiplexer::QuicEndpointMultiplexer( - std::string name, - const std::vector& endpoints) - : Endpoint((*endpoints.begin())->simulator(), name) { - for (QuicEndpoint* endpoint : endpoints) { - mapping_.insert(std::make_pair(endpoint->name(), endpoint)); - } -} - -QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {} - -void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr packet) { - auto key_value_pair_it = mapping_.find(packet->destination); - if (key_value_pair_it == mapping_.end()) { - return; - } - - key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet)); -} -UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() { - return this; -} -void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) { - for (auto& key_value_pair : mapping_) { - key_value_pair.second->SetTxPort(port); - } -} - } // namespace simulator } // namespace quic 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 43fce53bb4c..c2d24ac5404 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 @@ -16,26 +16,17 @@ #include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h" namespace quic { namespace simulator { -// Size of the TX queue used by the kernel/NIC. 1000 is the Linux -// kernel default. -const QuicByteCount kTxQueueSize = 1000; - -// Generate a random local network host-port tuple based on the name of the -// endpoint. -QuicSocketAddress GetAddressFromName(std::string name); - // A QUIC connection endpoint. Wraps around QuicConnection. In order to // initiate a transfer, the caller has to call AddBytesToTransfer(). The data // transferred is always the same and is always transferred on a single stream. // The endpoint receives all packets addressed to it, and verifies that the data // received is what it's supposed to be. -class QuicEndpoint : public Endpoint, - public UnconstrainedPortInterface, - public Queue::ListenerInterface, +class QuicEndpoint : public QuicEndpointBase, public QuicConnectionVisitorInterface, public SessionNotifierInterface { public: @@ -44,40 +35,16 @@ class QuicEndpoint : public Endpoint, std::string peer_name, Perspective perspective, QuicConnectionId connection_id); - ~QuicEndpoint() override; - inline QuicConnection* connection() { return &connection_; } QuicByteCount bytes_to_transfer() const; QuicByteCount bytes_transferred() const; QuicByteCount bytes_received() const; - inline size_t write_blocked_count() { return write_blocked_count_; } inline bool wrong_data_received() const { return wrong_data_received_; } // Send |bytes| bytes. Initiates the transfer if one is not already in // progress. void AddBytesToTransfer(QuicByteCount bytes); - // Drop the next packet upon receipt. - void DropNextIncomingPacket(); - - // UnconstrainedPortInterface method. Called whenever the endpoint receives a - // packet. - void AcceptPacket(std::unique_ptr packet) override; - - // Enables logging of the connection trace at the end of the unit test. - void RecordTrace(); - - // Begin Endpoint implementation. - UnconstrainedPortInterface* GetRxPort() override; - void SetTxPort(ConstrainedPortInterface* port) override; - // End Endpoint implementation. - - // Actor method. - void Act() override {} - - // Queue::ListenerInterface method. - void OnPacketDequeued() override; - // Begin QuicConnectionVisitorInterface implementation. void OnStreamFrame(const QuicStreamFrame& frame) override; void OnCryptoFrame(const QuicCryptoFrame& frame) override; @@ -114,9 +81,8 @@ class QuicEndpoint : public Endpoint, const QuicStreamsBlockedFrame& /*frame*/) override { return true; } - bool OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override { - return true; - } + void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override {} + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} // End QuicConnectionVisitorInterface implementation. @@ -134,33 +100,6 @@ class QuicEndpoint : public Endpoint, // End SessionNotifierInterface implementation. private: - // A Writer object that writes into the |nic_tx_queue_|. - class Writer : public QuicPacketWriter { - public: - explicit Writer(QuicEndpoint* endpoint); - ~Writer() override; - - WriteResult WritePacket(const char* buffer, - size_t buf_len, - const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address, - PerPacketOptions* options) override; - bool IsWriteBlocked() const override; - void SetWritable() override; - QuicByteCount GetMaxPacketSize( - const QuicSocketAddress& peer_address) const override; - bool SupportsReleaseTime() const override; - bool IsBatchMode() const override; - char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) override; - WriteResult Flush() override; - - private: - QuicEndpoint* endpoint_; - - bool is_blocked_; - }; - // The producer outputs the repetition of the same byte. That sequence is // verified by the receiver. class DataProducer : public QuicStreamFrameDataProducer { @@ -175,60 +114,30 @@ class QuicEndpoint : public Endpoint, QuicDataWriter* writer) override; }; + std::unique_ptr CreateConnection( + Simulator* simulator, + std::string name, + std::string peer_name, + Perspective perspective, + QuicConnectionId connection_id); + // Write stream data until |bytes_to_transfer_| is zero or the connection is // write-blocked. void WriteStreamData(); - std::string peer_name_; - - Writer writer_; DataProducer producer_; - // The queue for the outgoing packets. In reality, this might be either on - // the network card, or in the kernel, but for concreteness we assume it's on - // the network card. - Queue nic_tx_queue_; - QuicConnection connection_; QuicByteCount bytes_to_transfer_; QuicByteCount bytes_transferred_; - // Counts the number of times the writer became write-blocked. - size_t write_blocked_count_; - // Set to true if the endpoint receives stream data different from what it // expects. bool wrong_data_received_; - // If true, drop the next packet when receiving it. - bool drop_next_packet_; - // Record of received offsets in the data stream. QuicIntervalSet offsets_received_; std::unique_ptr notifier_; - std::unique_ptr trace_visitor_; -}; - -// Multiplexes multiple connections at the same host on the network. -class QuicEndpointMultiplexer : public Endpoint, - public UnconstrainedPortInterface { - public: - QuicEndpointMultiplexer(std::string name, - const std::vector& endpoints); - ~QuicEndpointMultiplexer() override; - - // Receives a packet and passes it to the specified endpoint if that endpoint - // is one of the endpoints being multiplexed, otherwise ignores the packet. - void AcceptPacket(std::unique_ptr packet) override; - UnconstrainedPortInterface* GetRxPort() override; - - // Sets the egress port for all the endpoints being multiplexed. - void SetTxPort(ConstrainedPortInterface* port) override; - - void Act() override {} - - private: - QuicUnorderedMap mapping_; }; } // namespace simulator diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc new file mode 100644 index 00000000000..537a94737b4 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc @@ -0,0 +1,222 @@ +// Copyright (c) 2012 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 "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h" + +#include +#include + +#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" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test_output.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" + +namespace quic { +namespace simulator { + +// Takes a SHA-1 hash of the name and converts it into five 32-bit integers. +static std::vector HashNameIntoFive32BitIntegers(std::string name) { + const std::string hash = test::Sha1Hash(name); + + std::vector output; + uint32_t current_number = 0; + for (size_t i = 0; i < hash.size(); i++) { + current_number = (current_number << 8) + hash[i]; + if (i % 4 == 3) { + output.push_back(i); + current_number = 0; + } + } + + return output; +} + +QuicSocketAddress GetAddressFromName(std::string name) { + const std::vector hash = HashNameIntoFive32BitIntegers(name); + + // Generate a random port between 1025 and 65535. + const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1); + + // Generate a random 10.x.x.x address, where x is between 1 and 254. + std::string ip_address{"\xa\0\0\0", 4}; + for (size_t i = 1; i < 4; i++) { + ip_address[i] = 1 + hash[i] % 254; + } + QuicIpAddress host; + host.FromPackedString(ip_address.c_str(), ip_address.length()); + return QuicSocketAddress(host, port); +} + +QuicEndpointBase::QuicEndpointBase(Simulator* simulator, + std::string name, + std::string peer_name) + : Endpoint(simulator, name), + peer_name_(peer_name), + writer_(this), + nic_tx_queue_(simulator, + QuicStringPrintf("%s (TX Queue)", name.c_str()), + kMaxOutgoingPacketSize * kTxQueueSize), + connection_(nullptr), + write_blocked_count_(0), + drop_next_packet_(false) { + nic_tx_queue_.set_listener_interface(this); +} + +QuicEndpointBase::~QuicEndpointBase() { + if (trace_visitor_ != nullptr) { + const char* perspective_prefix = + connection_->perspective() == Perspective::IS_CLIENT ? "C" : "S"; + + std::string identifier = + QuicStrCat(perspective_prefix, connection_->connection_id().ToString()); + QuicRecordTestOutput(identifier, + trace_visitor_->trace()->SerializeAsString()); + } +} + +void QuicEndpointBase::DropNextIncomingPacket() { + drop_next_packet_ = true; +} + +void QuicEndpointBase::RecordTrace() { + trace_visitor_ = std::make_unique(connection_.get()); + connection_->set_debug_visitor(trace_visitor_.get()); +} + +void QuicEndpointBase::AcceptPacket(std::unique_ptr packet) { + if (packet->destination != name_) { + return; + } + if (drop_next_packet_) { + drop_next_packet_ = false; + return; + } + + QuicReceivedPacket received_packet(packet->contents.data(), + packet->contents.size(), clock_->Now()); + connection_->ProcessUdpPacket(connection_->self_address(), + connection_->peer_address(), received_packet); +} + +UnconstrainedPortInterface* QuicEndpointBase::GetRxPort() { + return this; +} + +void QuicEndpointBase::SetTxPort(ConstrainedPortInterface* port) { + // Any egress done by the endpoint is actually handled by a queue on an NIC. + nic_tx_queue_.set_tx_port(port); +} + +void QuicEndpointBase::OnPacketDequeued() { + if (writer_.IsWriteBlocked() && + (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >= + kMaxOutgoingPacketSize) { + writer_.SetWritable(); + connection_->OnCanWrite(); + } +} + +QuicEndpointBase::Writer::Writer(QuicEndpointBase* endpoint) + : endpoint_(endpoint), is_blocked_(false) {} + +QuicEndpointBase::Writer::~Writer() {} + +WriteResult QuicEndpointBase::Writer::WritePacket( + const char* buffer, + size_t buf_len, + const QuicIpAddress& /*self_address*/, + const QuicSocketAddress& /*peer_address*/, + PerPacketOptions* options) { + DCHECK(!IsWriteBlocked()); + DCHECK(options == nullptr); + DCHECK(buf_len <= kMaxOutgoingPacketSize); + + // Instead of losing a packet, become write-blocked when the egress queue is + // full. + if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) { + is_blocked_ = true; + endpoint_->write_blocked_count_++; + return WriteResult(WRITE_STATUS_BLOCKED, 0); + } + + auto packet = std::make_unique(); + packet->source = endpoint_->name(); + packet->destination = endpoint_->peer_name_; + packet->tx_timestamp = endpoint_->clock_->Now(); + + packet->contents = std::string(buffer, buf_len); + packet->size = buf_len; + + endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet)); + + return WriteResult(WRITE_STATUS_OK, buf_len); +} + +bool QuicEndpointBase::Writer::IsWriteBlocked() const { + return is_blocked_; +} + +void QuicEndpointBase::Writer::SetWritable() { + is_blocked_ = false; +} + +QuicByteCount QuicEndpointBase::Writer::GetMaxPacketSize( + const QuicSocketAddress& /*peer_address*/) const { + return kMaxOutgoingPacketSize; +} + +bool QuicEndpointBase::Writer::SupportsReleaseTime() const { + return false; +} + +bool QuicEndpointBase::Writer::IsBatchMode() const { + return false; +} + +char* QuicEndpointBase::Writer::GetNextWriteLocation( + const QuicIpAddress& /*self_address*/, + const QuicSocketAddress& /*peer_address*/) { + return nullptr; +} + +WriteResult QuicEndpointBase::Writer::Flush() { + return WriteResult(WRITE_STATUS_OK, 0); +} + +QuicEndpointMultiplexer::QuicEndpointMultiplexer( + std::string name, + const std::vector& endpoints) + : Endpoint((*endpoints.begin())->simulator(), name) { + for (QuicEndpointBase* endpoint : endpoints) { + mapping_.insert(std::make_pair(endpoint->name(), endpoint)); + } +} + +QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {} + +void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr packet) { + auto key_value_pair_it = mapping_.find(packet->destination); + if (key_value_pair_it == mapping_.end()) { + return; + } + + key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet)); +} +UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() { + return this; +} +void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) { + for (auto& key_value_pair : mapping_) { + key_value_pair.second->SetTxPort(port); + } +} + +} // namespace simulator +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h new file mode 100644 index 00000000000..ae9f69b95fc --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h @@ -0,0 +1,158 @@ +// Copyright (c) 2012 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_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_BASE_H_ +#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_BASE_H_ + +#include + +#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/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_default_packet_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h" +#include "net/third_party/quiche/src/quic/core/quic_trace_visitor.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h" + +namespace quic { +namespace simulator { + +// Size of the TX queue used by the kernel/NIC. 1000 is the Linux +// kernel default. +const QuicByteCount kTxQueueSize = 1000; + +// Generate a random local network host-port tuple based on the name of the +// endpoint. +QuicSocketAddress GetAddressFromName(std::string name); + +// A QUIC connection endpoint. If the specific data transmitted does not matter +// (e.g. for congestion control purposes), QuicEndpoint is the subclass that +// transmits dummy data. If the actual semantics of the connection matter, +// subclassing QuicEndpointBase is required. +class QuicEndpointBase : public Endpoint, + public UnconstrainedPortInterface, + public Queue::ListenerInterface { + public: + // Does not create the connection; the subclass has to create connection by + // itself. + QuicEndpointBase(Simulator* simulator, + std::string name, + std::string peer_name); + ~QuicEndpointBase() override; + + inline QuicConnection* connection() { return connection_.get(); } + inline size_t write_blocked_count() { return write_blocked_count_; } + + // Drop the next packet upon receipt. + void DropNextIncomingPacket(); + + // UnconstrainedPortInterface method. Called whenever the endpoint receives a + // packet. + void AcceptPacket(std::unique_ptr packet) override; + + // Enables logging of the connection trace at the end of the unit test. + void RecordTrace(); + + // Begin Endpoint implementation. + UnconstrainedPortInterface* GetRxPort() override; + void SetTxPort(ConstrainedPortInterface* port) override; + // End Endpoint implementation. + + // Actor method. + void Act() override {} + + // Queue::ListenerInterface method. + void OnPacketDequeued() override; + + protected: + // A Writer object that writes into the |nic_tx_queue_|. + class Writer : public QuicPacketWriter { + public: + explicit Writer(QuicEndpointBase* endpoint); + ~Writer() override; + + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override; + bool IsWriteBlocked() const override; + void SetWritable() override; + QuicByteCount GetMaxPacketSize( + const QuicSocketAddress& peer_address) const override; + bool SupportsReleaseTime() const override; + bool IsBatchMode() const override; + char* GetNextWriteLocation(const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) override; + WriteResult Flush() override; + + private: + QuicEndpointBase* endpoint_; + + bool is_blocked_; + }; + + // The producer outputs the repetition of the same byte. That sequence is + // verified by the receiver. + class DataProducer : public QuicStreamFrameDataProducer { + public: + WriteStreamDataResult WriteStreamData(QuicStreamId id, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) override; + bool WriteCryptoData(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) override; + }; + + std::string peer_name_; + + Writer writer_; + // The queue for the outgoing packets. In reality, this might be either on + // the network card, or in the kernel, but for concreteness we assume it's on + // the network card. + Queue nic_tx_queue_; + // Created by the subclass. + std::unique_ptr connection_; + + // Counts the number of times the writer became write-blocked. + size_t write_blocked_count_; + + // If true, drop the next packet when receiving it. + bool drop_next_packet_; + + std::unique_ptr trace_visitor_; +}; + +// Multiplexes multiple connections at the same host on the network. +class QuicEndpointMultiplexer : public Endpoint, + public UnconstrainedPortInterface { + public: + QuicEndpointMultiplexer(std::string name, + const std::vector& endpoints); + ~QuicEndpointMultiplexer() override; + + // Receives a packet and passes it to the specified endpoint if that endpoint + // is one of the endpoints being multiplexed, otherwise ignores the packet. + void AcceptPacket(std::unique_ptr packet) override; + UnconstrainedPortInterface* GetRxPort() override; + + // Sets the egress port for all the endpoints being multiplexed. + void SetTxPort(ConstrainedPortInterface* port) override; + + void Act() override {} + + private: + QuicUnorderedMap mapping_; +}; + +} // namespace simulator +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_BASE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc index 772cd2e4ffd..0989a3bc0f7 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc @@ -104,8 +104,8 @@ TEST_F(QuicEndpointTest, WriteBlocked) { EXPECT_CALL(*sender, BandwidthEstimate()) .WillRepeatedly(Return(10 * kDefaultBandwidth)); EXPECT_CALL(*sender, GetCongestionWindow()) - .WillRepeatedly( - Return(kMaxOutgoingPacketSize * kDefaultMaxCongestionWindowPackets)); + .WillRepeatedly(Return(kMaxOutgoingPacketSize * + GetQuicFlag(FLAGS_quic_max_congestion_window))); test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(), sender); // First transmit a small, packet-size chunk of data. 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 cccb7ba3e6f..379cfac3c13 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 @@ -70,7 +70,24 @@ QuicClient::QuicClient(QuicSocketAddress server_address, QuicConfig(), epoll_server, QuicWrapUnique(new QuicClientEpollNetworkHelper(epoll_server, this)), - std::move(proof_verifier)) {} + std::move(proof_verifier), + nullptr) {} + +QuicClient::QuicClient(QuicSocketAddress server_address, + const QuicServerId& server_id, + const ParsedQuicVersionVector& supported_versions, + QuicEpollServer* epoll_server, + std::unique_ptr proof_verifier, + std::unique_ptr session_cache) + : QuicClient( + server_address, + server_id, + supported_versions, + QuicConfig(), + epoll_server, + QuicWrapUnique(new QuicClientEpollNetworkHelper(epoll_server, this)), + std::move(proof_verifier), + std::move(session_cache)) {} QuicClient::QuicClient( QuicSocketAddress server_address, @@ -85,7 +102,8 @@ QuicClient::QuicClient( QuicConfig(), epoll_server, std::move(network_helper), - std::move(proof_verifier)) {} + std::move(proof_verifier), + nullptr) {} QuicClient::QuicClient( QuicSocketAddress server_address, @@ -95,6 +113,24 @@ QuicClient::QuicClient( QuicEpollServer* epoll_server, std::unique_ptr network_helper, std::unique_ptr proof_verifier) + : QuicClient(server_address, + server_id, + supported_versions, + config, + epoll_server, + std::move(network_helper), + std::move(proof_verifier), + nullptr) {} + +QuicClient::QuicClient( + QuicSocketAddress server_address, + const QuicServerId& server_id, + const ParsedQuicVersionVector& supported_versions, + const QuicConfig& config, + QuicEpollServer* epoll_server, + std::unique_ptr network_helper, + std::unique_ptr proof_verifier, + std::unique_ptr session_cache) : QuicSpdyClientBase( server_id, supported_versions, @@ -102,7 +138,8 @@ QuicClient::QuicClient( new QuicEpollConnectionHelper(epoll_server, QuicAllocator::SIMPLE), new QuicEpollAlarmFactory(epoll_server), std::move(network_helper), - std::move(proof_verifier)) { + std::move(proof_verifier), + std::move(session_cache)) { set_server_address(server_address); } 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 8e43be8498b..10c61f378d0 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 @@ -37,12 +37,18 @@ QuicSocketAddress LookupAddress(std::string host, std::string port); class QuicClient : public QuicSpdyClientBase { public: - // This will create its own QuicClientEpollNetworkHelper. + // These will create their own QuicClientEpollNetworkHelper. QuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, const ParsedQuicVersionVector& supported_versions, QuicEpollServer* epoll_server, std::unique_ptr proof_verifier); + QuicClient(QuicSocketAddress server_address, + const QuicServerId& server_id, + const ParsedQuicVersionVector& supported_versions, + QuicEpollServer* epoll_server, + std::unique_ptr proof_verifier, + std::unique_ptr session_cache); // This will take ownership of a passed in network primitive. QuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, @@ -57,6 +63,14 @@ class QuicClient : public QuicSpdyClientBase { QuicEpollServer* epoll_server, std::unique_ptr network_helper, std::unique_ptr proof_verifier); + QuicClient(QuicSocketAddress server_address, + const QuicServerId& server_id, + const ParsedQuicVersionVector& supported_versions, + const QuicConfig& config, + QuicEpollServer* epoll_server, + std::unique_ptr network_helper, + std::unique_ptr proof_verifier, + std::unique_ptr session_cache); QuicClient(const QuicClient&) = delete; QuicClient& operator=(const QuicClient&) = delete; 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 b03f7cc342d..b6c33759b47 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 @@ -23,12 +23,13 @@ QuicClientBase::QuicClientBase( QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, std::unique_ptr network_helper, - std::unique_ptr proof_verifier) + std::unique_ptr proof_verifier, + std::unique_ptr session_cache) : server_id_(server_id), initialized_(false), local_port_(0), config_(config), - crypto_config_(std::move(proof_verifier)), + crypto_config_(std::move(proof_verifier), std::move(session_cache)), helper_(helper), alarm_factory_(alarm_factory), supported_versions_(supported_versions), 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 fb15b862b08..8cb639bd58f 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 @@ -23,6 +23,7 @@ namespace quic { class ProofVerifier; class QuicServerId; +class SessionCache; // QuicClientBase handles establishing a connection to the passed in // server id, including ensuring that it supports the passed in versions @@ -64,7 +65,8 @@ class QuicClientBase { QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, std::unique_ptr network_helper, - std::unique_ptr proof_verifier); + std::unique_ptr proof_verifier, + std::unique_ptr session_cache); QuicClientBase(const QuicClientBase&) = delete; QuicClientBase& operator=(const QuicClientBase&) = delete; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc index 278a22e29ba..8c9f6d16930 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc @@ -13,6 +13,8 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h" #include "net/quic/platform/impl/quic_epoll_clock.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" #include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" #include "net/third_party/quiche/src/quic/tools/quic_client.h" #include "net/third_party/quiche/src/quic/tools/quic_url.h" @@ -36,6 +38,8 @@ enum class Feature { kStreamData, // The connection close procedcure completes with a zero error code. kConnectionClose, + // The connection was established using TLS resumption. + kResumption, // A RETRY packet was successfully processed. kRetry, @@ -46,6 +50,9 @@ enum class Feature { // Third row of features (H3 tests) // An H3 transaction succeeded. kHttp3, + // One or both endpoints insert entries into dynamic table and subsequenly + // reference them from header blocks. + kDynamicEntryReferenced, }; char MatrixLetter(Feature f) { @@ -58,39 +65,80 @@ char MatrixLetter(Feature f) { return 'D'; case Feature::kConnectionClose: return 'C'; - case Feature::kHttp3: - return '3'; + case Feature::kResumption: + return 'R'; case Feature::kRetry: return 'S'; case Feature::kRebinding: return 'B'; + case Feature::kHttp3: + return '3'; + case Feature::kDynamicEntryReferenced: + return 'd'; + } +} + +// Attempts a resumption using |client| by disconnecting and reconnecting. If +// resumption is successful, |features| is modified to add Feature::kResumption +// to it, otherwise it is left unmodified. +void AttemptResumption(QuicClient* client, std::set* features) { + client->Disconnect(); + if (!client->Initialize()) { + QUIC_LOG(ERROR) << "Failed to reinitialize client"; + return; + } + if (!client->Connect() || !client->session()->IsCryptoHandshakeConfirmed()) { + return; + } + if (static_cast( + test::QuicSessionPeer::GetMutableCryptoStream(client->session())) + ->IsResumption()) { + features->insert(Feature::kResumption); } } std::set AttemptRequest(QuicSocketAddress addr, std::string authority, QuicServerId server_id, - ParsedQuicVersionVector versions, + bool test_version_negotiation, bool attempt_rebind) { + ParsedQuicVersion version(PROTOCOL_TLS1_3, QUIC_VERSION_99); + ParsedQuicVersionVector versions = {version}; + if (test_version_negotiation) { + versions.insert(versions.begin(), QuicVersionReservedForNegotiation()); + } + std::set features; auto proof_verifier = std::make_unique(); + auto session_cache = std::make_unique(); QuicEpollServer epoll_server; QuicEpollClock epoll_clock(&epoll_server); auto client = std::make_unique( - addr, server_id, versions, &epoll_server, std::move(proof_verifier)); + addr, server_id, versions, &epoll_server, std::move(proof_verifier), + std::move(session_cache)); if (!client->Initialize()) { + QUIC_LOG(ERROR) << "Failed to initialize client"; return features; } - if (!client->Connect()) { - QuicErrorCode error = client->session()->error(); - if (error == QUIC_INVALID_VERSION) { - // QuicFramer::ProcessPacket returns RaiseError(QUIC_INVALID_VERSION) if - // it receives a packet containing a version in the header that is not our - // version. It might be possible that we didn't actually process a VN - // packet here. + const bool connect_result = client->Connect(); + QuicConnection* connection = client->session()->connection(); + if (connection != nullptr) { + QuicConnectionStats client_stats = connection->GetStats(); + if (client_stats.retry_packet_processed) { + features.insert(Feature::kRetry); + } + if (test_version_negotiation && connection->version() == version) { features.insert(Feature::kVersionNegotiation); - return features; } + } + if (test_version_negotiation && !connect_result) { + // Failed to negotiate version, retry without version negotiation. + std::set features_without_version_negotiation = + AttemptRequest(addr, authority, server_id, + /*test_version_negotiation=*/false, attempt_rebind); + + features.insert(features_without_version_negotiation.begin(), + features_without_version_negotiation.end()); return features; } if (!client->session()->IsCryptoHandshakeConfirmed()) { @@ -109,19 +157,17 @@ std::set AttemptRequest(QuicSocketAddress addr, const QuicTime request_start_time = epoll_clock.Now(); static const auto request_timeout = QuicTime::Delta::FromSeconds(20); + bool request_timed_out = false; while (client->WaitForEvents()) { if (epoll_clock.Now() - request_start_time >= request_timeout) { QUIC_LOG(ERROR) << "Timed out waiting for HTTP response"; - return features; + request_timed_out = true; + break; } } - QuicConnection* connection = client->session()->connection(); if (connection != nullptr) { QuicConnectionStats client_stats = connection->GetStats(); - if (client_stats.retry_packet_processed) { - features.insert(Feature::kRetry); - } QuicSentPacketManager* sent_packet_manager = test::QuicConnectionPeer::GetSentPacketManager(connection); const bool received_forward_secure_ack = @@ -133,13 +179,17 @@ std::set AttemptRequest(QuicSocketAddress addr, } } - if (!client->connected()) { + if (request_timed_out || !client->connected()) { return features; } if (client->latest_response_code() != -1) { features.insert(Feature::kHttp3); + if (client->client_session()->dynamic_table_entry_referenced()) { + features.insert(Feature::kDynamicEntryReferenced); + } + if (attempt_rebind) { // Now make a second request after switching to a different client port. if (client->ChangeEphemeralPort()) { @@ -150,11 +200,19 @@ std::set AttemptRequest(QuicSocketAddress addr, if (epoll_clock.Now() - second_request_start_time >= request_timeout) { // Rebinding does not work, retry without attempting it. - return AttemptRequest(addr, authority, server_id, versions, - /*attempt_rebind=*/false); + std::set features_without_rebind = AttemptRequest( + addr, authority, server_id, test_version_negotiation, + /*attempt_rebind=*/false); + features.insert(features_without_rebind.begin(), + features_without_rebind.end()); + return features; } } features.insert(Feature::kRebinding); + + if (client->client_session()->dynamic_table_entry_referenced()) { + features.insert(Feature::kDynamicEntryReferenced); + } } else { QUIC_LOG(ERROR) << "Failed to change ephemeral port"; } @@ -170,6 +228,7 @@ std::set AttemptRequest(QuicSocketAddress addr, client->epoll_network_helper()->RunEventLoop(); if (epoll_clock.Now() - close_start_time >= close_timeout) { QUIC_LOG(ERROR) << "Timed out waiting for connection close"; + AttemptResumption(client.get(), &features); return features; } } @@ -183,35 +242,27 @@ std::set AttemptRequest(QuicSocketAddress addr, } } + AttemptResumption(client.get(), &features); return features; } std::set ServerSupport(std::string host, int port) { - // Configure version list. + // Enable IETF version support. QuicVersionInitializeSupportForIetfDraft(); - ParsedQuicVersion version = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); - ParsedQuicVersionVector versions = {version}; - QuicEnableVersion(version); + QuicEnableVersion(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99)); // Build the client, and try to connect. QuicSocketAddress addr = tools::LookupAddress(host, QuicStrCat(port)); + if (!addr.IsInitialized()) { + QUIC_LOG(ERROR) << "Failed to resolve " << host; + return std::set(); + } QuicServerId server_id(host, port, false); std::string authority = QuicStrCat(host, ":", port); - ParsedQuicVersionVector versions_with_negotiation = versions; - versions_with_negotiation.insert(versions_with_negotiation.begin(), - QuicVersionReservedForNegotiation()); - auto supported_features = - AttemptRequest(addr, authority, server_id, versions_with_negotiation, - /*attempt_rebind=*/true); - if (!supported_features.empty()) { - supported_features.insert(Feature::kVersionNegotiation); - } else { - supported_features = AttemptRequest(addr, authority, server_id, versions, - /*attempt_rebind=*/true); - } - return supported_features; + return AttemptRequest(addr, authority, server_id, + /*test_version_negotiation=*/true, + /*attempt_rebind=*/true); } } // namespace quic 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 6452d22c5ed..38d25e53734 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 @@ -289,7 +289,6 @@ void QuicMemoryCacheBackend::GenerateDynamicResponses() { QuicWriterMutexLock lock(&response_mutex_); // Add a generate bytes response. spdy::SpdyHeaderBlock response_headers; - response_headers[":version"] = "HTTP/1.1"; response_headers[":status"] = "200"; generate_bytes_response_ = std::make_unique(); generate_bytes_response_->set_headers(std::move(response_headers)); 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 e0ff400f410..f88d458e965 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 @@ -134,9 +134,6 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { // 'response'. void AddDefaultResponse(QuicBackendResponse* response); - // |cache_cirectory| can be generated using `wget -p --save-headers `. - void InitializeFromDirectory(const std::string& cache_directory); - // Once called, URLs which have a numeric path will send a dynamically // generated response of that many bytes. void GenerateDynamicResponses(); diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc index 80b1b293206..01ac334d1dd 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc @@ -59,7 +59,6 @@ TEST_F(QuicMemoryCacheBackendTest, AddResponse) { const std::string kResponseBody("hello response"); spdy::SpdyHeaderBlock response_headers; - response_headers[":version"] = "HTTP/1.1"; response_headers[":status"] = "200"; response_headers["content-length"] = QuicTextUtils::Uint64ToString(kResponseBody.size()); @@ -123,7 +122,6 @@ TEST_F(QuicMemoryCacheBackendTest, DefaultResponse) { // Add a default response. spdy::SpdyHeaderBlock response_headers; - response_headers[":version"] = "HTTP/1.1"; response_headers[":status"] = "200"; response_headers["content-length"] = "0"; Response* default_response = new Response; @@ -164,7 +162,6 @@ TEST_F(QuicMemoryCacheBackendTest, AddSimpleResponseWithServerPushResources) { std::string body = QuicStrCat("This is server push response body for ", path); spdy::SpdyHeaderBlock response_headers; - response_headers[":version"] = "HTTP/1.1"; response_headers[":status"] = "200"; response_headers["content-length"] = QuicTextUtils::Uint64ToString(body.size()); @@ -203,7 +200,6 @@ TEST_F(QuicMemoryCacheBackendTest, GetServerPushResourcesAndPushResponses) { QuicUrl resource_url(url); std::string body = "This is server push response body for " + path; spdy::SpdyHeaderBlock response_headers; - response_headers[":version"] = "HTTP/1.1"; response_headers[":status"] = push_response_status[i]; response_headers["content-length"] = QuicTextUtils::Uint64ToString(body.size()); diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc index 294dbc50ee7..04cc9508aad 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc @@ -218,8 +218,6 @@ void QuicServer::OnEvent(int fd, QuicEpollEvent* event) { event->out_ready_mask |= EPOLLOUT; } } - if (event->in_events & EPOLLERR) { - } } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.cc index a627007972c..b851a1d7eb0 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.cc @@ -26,8 +26,4 @@ void QuicSimpleClientStream::OnBodyAvailable() { } } -void QuicSimpleClientStream::OnStopSending(uint16_t code) { - last_stop_sending_code_ = code; -} - } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h index f1eb653bea4..aa6d2f6fe44 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h @@ -16,17 +16,11 @@ class QuicSimpleClientStream : public QuicSpdyClientStream { StreamType type, bool drop_response_body) : QuicSpdyClientStream(id, session, type), - drop_response_body_(drop_response_body), - last_stop_sending_code_(0) {} + drop_response_body_(drop_response_body) {} void OnBodyAvailable() override; - void OnStopSending(uint16_t code) override; - uint16_t last_stop_sending_code() { return last_stop_sending_code_; } private: const bool drop_response_body_; - // Application code value that was in the most recently received - // STOP_SENDING frame for this stream. - uint16_t last_stop_sending_code_; }; } // namespace quic 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 a4bab0f5380..a548c6c906a 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 @@ -10,10 +10,12 @@ #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/http/http_encoder.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h" #include "net/third_party/quiche/src/quic/core/quic_connection.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.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_containers.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" @@ -228,9 +230,10 @@ class QuicSimpleServerSessionTest QuicRandom::GetInstance(), &clock, QuicCryptoServerConfig::ConfigOptions()); session_->Initialize(); - QuicSessionPeer::GetMutableCryptoStream(session_.get()) - ->OnSuccessfulVersionNegotiation(supported_versions.front()); - visitor_ = QuicConnectionPeer::GetVisitor(connection_); + if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + QuicSessionPeer::GetMutableCryptoStream(session_.get()) + ->OnSuccessfulVersionNegotiation(supported_versions.front()); + } if (VersionHasIetfQuicFrames(transport_version())) { EXPECT_CALL(*connection_, SendControlFrame(_)) @@ -284,12 +287,12 @@ class QuicSimpleServerSessionTest QuicMemoryCacheBackend memory_cache_backend_; std::unique_ptr session_; std::unique_ptr handshake_message_; - QuicConnectionVisitorInterface* visitor_; }; INSTANTIATE_TEST_SUITE_P(Tests, QuicSimpleServerSessionTest, - ::testing::ValuesIn(AllSupportedVersions())); + ::testing::ValuesIn(AllSupportedVersions()), + ::testing::PrintToStringParamName()); TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { // Open a stream, then reset it. @@ -311,7 +314,7 @@ TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { OnStreamReset(GetNthClientInitiatedBidirectionalId(0), QUIC_RST_ACKNOWLEDGEMENT)); } - visitor_->OnRstStream(rst1); + session_->OnRstStream(rst1); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes // a one-way close. @@ -320,7 +323,7 @@ TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); // Send the same two bytes of payload in a new packet. - visitor_->OnStreamFrame(data1); + session_->OnStreamFrame(data1); // The stream should not be re-opened. EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); @@ -340,7 +343,7 @@ TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { OnStreamReset(GetNthClientInitiatedBidirectionalId(0), QUIC_RST_ACKNOWLEDGEMENT)); } - visitor_->OnRstStream(rst1); + session_->OnRstStream(rst1); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes // a one-way close. @@ -352,7 +355,7 @@ TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { // Send two bytes of payload. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, QuicStringPiece("HT")); - visitor_->OnStreamFrame(data1); + session_->OnStreamFrame(data1); // The stream should never be opened, now that the reset is received. EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); @@ -365,8 +368,8 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { QuicStringPiece("\1\0\0\0\0\0\0\0HT")); QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0, QuicStringPiece("\2\0\0\0\0\0\0\0HT")); - visitor_->OnStreamFrame(frame1); - visitor_->OnStreamFrame(frame2); + session_->OnStreamFrame(frame1); + session_->OnStreamFrame(frame2); EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); // Send a reset (and expect the peer to send a RST in response). @@ -381,7 +384,7 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { OnStreamReset(GetNthClientInitiatedBidirectionalId(0), QUIC_RST_ACKNOWLEDGEMENT)); } - visitor_->OnRstStream(rst); + session_->OnRstStream(rst); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes // a one-way close. @@ -395,8 +398,8 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { QuicStringPiece("TP")); QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2, QuicStringPiece("TP")); - visitor_->OnStreamFrame(frame3); - visitor_->OnStreamFrame(frame4); + session_->OnStreamFrame(frame3); + session_->OnStreamFrame(frame4); // The stream should never be opened, now that the reset is received. EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); EXPECT_TRUE(connection_->connected()); @@ -589,8 +592,10 @@ class QuicSimpleServerSessionServerPushTest config_, connection_, &owner_, &stream_helper_, &crypto_config_, &compressed_certs_cache_, &memory_cache_backend_); session_->Initialize(); - QuicSessionPeer::GetMutableCryptoStream(session_.get()) - ->OnSuccessfulVersionNegotiation(supported_versions.front()); + if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + QuicSessionPeer::GetMutableCryptoStream(session_.get()) + ->OnSuccessfulVersionNegotiation(supported_versions.front()); + } // Needed to make new session flow control window and server push work. if (VersionHasIetfQuicFrames(transport_version())) { @@ -600,8 +605,6 @@ class QuicSimpleServerSessionServerPushTest } session_->OnConfigNegotiated(); - visitor_ = QuicConnectionPeer::GetVisitor(connection_); - if (!VersionUsesHttp3(connection_->transport_version())) { session_->UnregisterStreamPriority( QuicUtils::GetHeadersStreamId(connection_->transport_version()), @@ -657,10 +660,9 @@ class QuicSimpleServerSessionServerPushTest std::string data; data_frame_header_length = 0; if (VersionUsesHttp3(connection_->transport_version())) { - HttpEncoder encoder; std::unique_ptr buffer; data_frame_header_length = - encoder.SerializeDataFrameHeader(body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); std::string header(buffer.get(), data_frame_header_length); data = header + body; } else { @@ -813,6 +815,12 @@ TEST_P(QuicSimpleServerSessionServerPushTest, // prevent a promised resource to be send out. TEST_P(QuicSimpleServerSessionServerPushTest, ResetPromisedStreamToCancelServerPush) { + if (VersionHasIetfQuicFrames(transport_version())) { + // This test is resetting a stream that is not opened yet. IETF QUIC has no + // way to handle this. Some similar tests can be added once CANCEL_PUSH is + // supported. + return; + } MaybeConsumeHeadersStreamData(); session_->SetMaxAllowedPushId(kMaxQuicStreamId); @@ -844,7 +852,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest, .WillOnce(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); - visitor_->OnRstStream(rst); + session_->OnRstStream(rst); // When the first 2 streams becomes draining, the two queued up stream could // be created. But since one of them was marked cancelled due to RST frame, @@ -863,8 +871,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest, EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, 1, offset, NO_FIN)); offset++; - } - if (VersionUsesHttp3(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, kHeadersFrameHeaderLength, offset, NO_FIN)); @@ -873,8 +879,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest, SendStreamData(stream_not_reset, kHeadersFramePayloadLength, offset, NO_FIN)); offset += kHeadersFramePayloadLength; - } - if (VersionUsesHttp3(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, data_frame_header_length, offset, NO_FIN)); @@ -924,9 +928,9 @@ TEST_P(QuicSimpleServerSessionServerPushTest, // Resetting an open stream will close the stream and give space for extra // stream to be opened. QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(3); - EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); EXPECT_CALL(*connection_, SendControlFrame(_)); if (!VersionHasIetfQuicFrames(transport_version())) { + EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); // For version 99, this is covered in InjectStopSending() EXPECT_CALL(*connection_, OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); @@ -936,8 +940,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest, EXPECT_CALL(*connection_, SendStreamData(stream_to_open, 1, offset, NO_FIN)); offset++; - } - if (VersionUsesHttp3(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_to_open, kHeadersFrameHeaderLength, offset, NO_FIN)); @@ -946,8 +948,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest, SendStreamData(stream_to_open, kHeadersFramePayloadLength, offset, NO_FIN)); offset += kHeadersFramePayloadLength; - } - if (VersionUsesHttp3(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_to_open, data_frame_header_length, offset, NO_FIN)); @@ -968,8 +968,9 @@ TEST_P(QuicSimpleServerSessionServerPushTest, // available as it closes/etc them. session_->OnMaxStreamsFrame( QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true)); + } else { + session_->OnRstStream(rst); } - visitor_->OnRstStream(rst); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes // a one-way close. diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc index 783dba0c55c..50ca84fd188 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc @@ -8,6 +8,7 @@ #include #include +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" @@ -192,7 +193,6 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam { header_list_.OnHeader(":authority", "www.google.com"); header_list_.OnHeader(":path", "/"); header_list_.OnHeader(":method", "POST"); - header_list_.OnHeader(":version", "HTTP/1.1"); header_list_.OnHeader("content-length", "11"); header_list_.OnHeaderBlockEnd(128, 128); @@ -248,7 +248,6 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam { std::unique_ptr quic_response_; std::string body_; QuicHeaderList header_list_; - HttpEncoder encoder_; }; INSTANTIATE_TEST_SUITE_P(Tests, @@ -262,7 +261,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFraming) { stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body_.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = UsesHttp3() ? header + body_ : body_; stream_->OnStreamFrame( @@ -280,7 +279,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) { stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body_.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = UsesHttp3() ? header + body_ : body_; stream_->OnStreamFrame( @@ -321,7 +320,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) { stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body_.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); std::string header = std::string(buffer.get(), header_length); std::string data = UsesHttp3() ? header + body_ : body_; @@ -330,7 +329,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) { // Content length is still 11. This will register as an error and we won't // accept the bytes. header_length = - encoder_.SerializeDataFrameHeader(large_body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(large_body.length(), &buffer); header = std::string(buffer.get(), header_length); std::string data2 = UsesHttp3() ? header + large_body : large_body; stream_->OnStreamFrame( @@ -345,17 +344,15 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus) { spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers(); (*request_headers)[":path"] = "/bar"; (*request_headers)[":authority"] = "www.google.com"; - (*request_headers)[":version"] = "HTTP/1.1"; (*request_headers)[":method"] = "GET"; - response_headers_[":version"] = "HTTP/1.1"; // HTTP/2 only supports integer responsecode, so "200 OK" is illegal. response_headers_[":status"] = "200 OK"; response_headers_["content-length"] = "5"; std::string body = "Yummm"; std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); memory_cache_backend_.AddResponse("www.google.com", "/bar", std::move(response_headers_), body); @@ -379,10 +376,8 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus2) { spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers(); (*request_headers)[":path"] = "/bar"; (*request_headers)[":authority"] = "www.google.com"; - (*request_headers)[":version"] = "HTTP/1.1"; (*request_headers)[":method"] = "GET"; - response_headers_[":version"] = "HTTP/1.1"; // HTTP/2 only supports 3-digit-integer, so "+200" is illegal. response_headers_[":status"] = "+200"; response_headers_["content-length"] = "5"; @@ -390,7 +385,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus2) { std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); memory_cache_backend_.AddResponse("www.google.com", "/bar", std::move(response_headers_), body); @@ -422,10 +417,8 @@ TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) { spdy::SpdyHeaderBlock* request_headers = promised_stream->mutable_headers(); (*request_headers)[":path"] = "/bar"; (*request_headers)[":authority"] = "www.google.com"; - (*request_headers)[":version"] = "HTTP/1.1"; (*request_headers)[":method"] = "GET"; - response_headers_[":version"] = "HTTP/1.1"; response_headers_[":status"] = "404"; response_headers_["content-length"] = "8"; std::string body = "NotFound"; @@ -445,17 +438,15 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) { spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers(); (*request_headers)[":path"] = "/bar"; (*request_headers)[":authority"] = "www.google.com"; - (*request_headers)[":version"] = "HTTP/1.1"; (*request_headers)[":method"] = "GET"; - response_headers_[":version"] = "HTTP/1.1"; response_headers_[":status"] = "200"; response_headers_["content-length"] = "5"; std::string body = "Yummm"; std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); memory_cache_backend_.AddResponse("www.google.com", "/bar", std::move(response_headers_), body); @@ -483,7 +474,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) { std::string body = "Yummm"; std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); QuicBackendResponse::ServerPushInfo push_info( QuicUrl(host, "/bar"), spdy::SpdyHeaderBlock(), QuicStream::kDefaultPriority, "Push body"); @@ -495,7 +486,6 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) { spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers(); (*request_headers)[":path"] = request_path; (*request_headers)[":authority"] = host; - (*request_headers)[":version"] = "HTTP/1.1"; (*request_headers)[":method"] = "GET"; stream_->set_fin_received(true); @@ -546,16 +536,14 @@ TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) { spdy::SpdyHeaderBlock headers; headers[":path"] = kPath; headers[":authority"] = kHost; - headers[":version"] = "HTTP/1.1"; headers[":method"] = "GET"; - response_headers_[":version"] = "HTTP/1.1"; response_headers_[":status"] = "200"; response_headers_["content-length"] = "5"; const std::string kBody = "Hello"; std::unique_ptr buffer; QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(kBody.length(), &buffer); + HttpEncoder::SerializeDataFrameHeader(kBody.length(), &buffer); memory_cache_backend_.AddResponse(kHost, kPath, std::move(response_headers_), kBody); @@ -645,6 +633,16 @@ TEST_P(QuicSimpleServerStreamTest, EXPECT_FALSE(stream_->reading_stopped()); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); + if (VersionUsesHttp3(connection_->transport_version())) { + // Unidirectional stream type and then a Stream Cancellation instruction is + // sent on the QPACK decoder stream. Ignore these writes without any + // assumption on their number or size. + auto* qpack_decoder_stream = + QuicSpdySessionPeer::GetQpackDecoderSendStream(&session_); + EXPECT_CALL(session_, WritevData(qpack_decoder_stream, + qpack_decoder_stream->id(), _, _, _)) + .Times(AnyNumber()); + } EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1); QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 1234); 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 3cd4cbdf4cf..6b4cc8d042f 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 @@ -37,14 +37,16 @@ QuicSpdyClientBase::QuicSpdyClientBase( QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, std::unique_ptr network_helper, - std::unique_ptr proof_verifier) + std::unique_ptr proof_verifier, + std::unique_ptr session_cache) : QuicClientBase(server_id, supported_versions, config, helper, alarm_factory, std::move(network_helper), - std::move(proof_verifier)), + std::move(proof_verifier), + std::move(session_cache)), store_response_(false), latest_response_code_(-1), max_allowed_push_id_(0), 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 2a1267fa8be..d95303855c4 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 @@ -23,6 +23,7 @@ namespace quic { class ProofVerifier; class QuicServerId; +class SessionCache; class QuicSpdyClientBase : public QuicClientBase, public QuicClientPushPromiseIndex::Delegate, @@ -69,7 +70,8 @@ class QuicSpdyClientBase : public QuicClientBase, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, std::unique_ptr network_helper, - std::unique_ptr proof_verifier); + std::unique_ptr proof_verifier, + std::unique_ptr session_cache); QuicSpdyClientBase(const QuicSpdyClientBase&) = delete; QuicSpdyClientBase& operator=(const QuicSpdyClientBase&) = delete; 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 eee4e6132d7..41597359280 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 @@ -63,7 +63,6 @@ namespace { -using quic::QuicSocketAddress; using quic::QuicStringPiece; using quic::QuicTextUtils; using quic::QuicUrl; @@ -237,10 +236,6 @@ int QuicToyClient::SendRequestsAndPrintResponses( std::cerr << "Failed to initialize client." << std::endl; return 1; } - client->client_session()->set_qpack_maximum_dynamic_table_capacity( - kDefaultQpackMaxDynamicTableCapacity); - client->client_session()->set_qpack_maximum_blocked_streams( - kDefaultMaximumBlockedStreams); if (!client->Connect()) { quic::QuicErrorCode error = client->session()->error(); if (error == quic::QUIC_INVALID_VERSION) { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc index fdb1bb6ce78..390dcf6aa0c 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc @@ -62,12 +62,13 @@ int QuicToyServer::Start() { ParsedQuicVersionVector supported_versions; if (GetQuicFlag(FLAGS_quic_ietf_draft)) { QuicVersionInitializeSupportForIetfDraft(); - ParsedQuicVersion version(PROTOCOL_TLS1_3, QUIC_VERSION_99); - QuicEnableVersion(version); - supported_versions = {version}; + supported_versions = {ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99)}; } else { supported_versions = AllSupportedVersions(); } + for (const auto& version : supported_versions) { + QuicEnableVersion(version); + } auto proof_source = quic::CreateDefaultProofSource(); auto backend = backend_factory_->CreateBackend(); auto server = server_factory_->CreateServer( diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc new file mode 100644 index 00000000000..9b1ea04cfe6 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h" + +#include + +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h" + +namespace quic { + +QuicTransportSimpleServerDispatcher::QuicTransportSimpleServerDispatcher( + const QuicConfig* config, + const QuicCryptoServerConfig* crypto_config, + QuicVersionManager* version_manager, + std::unique_ptr helper, + std::unique_ptr session_helper, + std::unique_ptr alarm_factory, + uint8_t expected_server_connection_id_length, + QuicTransportSimpleServerSession::Mode mode, + std::vector accepted_origins) + : QuicDispatcher(config, + crypto_config, + version_manager, + std::move(helper), + std::move(session_helper), + std::move(alarm_factory), + expected_server_connection_id_length), + mode_(mode), + accepted_origins_(accepted_origins) {} + +QuicSession* QuicTransportSimpleServerDispatcher::CreateQuicSession( + QuicConnectionId server_connection_id, + const QuicSocketAddress& peer_address, + QuicStringPiece /*alpn*/, + const ParsedQuicVersion& version) { + auto connection = std::make_unique( + server_connection_id, peer_address, helper(), alarm_factory(), writer(), + /*owns_writer=*/false, Perspective::IS_SERVER, + ParsedQuicVersionVector{version}); + QuicTransportSimpleServerSession* session = + new QuicTransportSimpleServerSession( + connection.release(), /*owns_connection=*/true, this, config(), + GetSupportedVersions(), crypto_config(), compressed_certs_cache(), + mode_, accepted_origins_); + session->Initialize(); + return session; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h new file mode 100644 index 00000000000..ea4eb8bf8ef --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h @@ -0,0 +1,41 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_DISPATCHER_H_ +#define QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_DISPATCHER_H_ + +#include "url/origin.h" +#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h" +#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h" + +namespace quic { + +// Dispatcher that creates a QuicTransportSimpleServerSession for every incoming +// connection. +class QuicTransportSimpleServerDispatcher : public QuicDispatcher { + public: + QuicTransportSimpleServerDispatcher( + const QuicConfig* config, + const QuicCryptoServerConfig* crypto_config, + QuicVersionManager* version_manager, + std::unique_ptr helper, + std::unique_ptr session_helper, + std::unique_ptr alarm_factory, + uint8_t expected_server_connection_id_length, + QuicTransportSimpleServerSession::Mode mode, + std::vector accepted_origins); + + protected: + QuicSession* CreateQuicSession(QuicConnectionId server_connection_id, + const QuicSocketAddress& peer_address, + QuicStringPiece alpn, + const ParsedQuicVersion& version) override; + + QuicTransportSimpleServerSession::Mode mode_; + std::vector accepted_origins_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_DISPATCHER_H_ 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 new file mode 100644 index 00000000000..6e86ccab78d --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc @@ -0,0 +1,226 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h" + +#include + +#include "url/gurl.h" +#include "url/origin.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.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/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" + +namespace quic { + +namespace { + +// Discards any incoming data. +class DiscardVisitor : public QuicTransportStream::Visitor { + public: + DiscardVisitor(QuicTransportStream* stream) : stream_(stream) {} + + void OnCanRead() override { + std::string buffer; + size_t bytes_read = stream_->Read(&buffer); + QUIC_DVLOG(2) << "Read " << bytes_read << " bytes from stream " + << stream_->id(); + } + + void OnFinRead() override {} + void OnCanWrite() override {} + + private: + QuicTransportStream* stream_; +}; + +// Echoes any incoming data back on the same stream. +class BidirectionalEchoVisitor : public QuicTransportStream::Visitor { + public: + BidirectionalEchoVisitor(QuicTransportStream* stream) : stream_(stream) {} + + void OnCanRead() override { + stream_->Read(&buffer_); + OnCanWrite(); + } + + void OnFinRead() override { + bool success = stream_->SendFin(); + DCHECK(success); + } + + void OnCanWrite() override { + if (buffer_.empty()) { + return; + } + + bool success = stream_->Write(buffer_); + if (success) { + buffer_ = ""; + } + } + + private: + QuicTransportStream* stream_; + std::string buffer_; +}; + +// Buffers all of the data and calls EchoStreamBack() on the parent session. +class UnidirectionalEchoReadVisitor : public QuicTransportStream::Visitor { + public: + UnidirectionalEchoReadVisitor(QuicTransportSimpleServerSession* session, + QuicTransportStream* stream) + : session_(session), stream_(stream) {} + + void OnCanRead() override { + bool success = stream_->Read(&buffer_); + DCHECK(success); + } + + void OnFinRead() override { + QUIC_DVLOG(1) << "Finished receiving data on stream " << stream_->id() + << ", queueing up the echo"; + session_->EchoStreamBack(buffer_); + } + + void OnCanWrite() override { QUIC_NOTREACHED(); } + + private: + QuicTransportSimpleServerSession* session_; + QuicTransportStream* stream_; + std::string buffer_; +}; + +// Sends supplied data. +class UnidirectionalEchoWriteVisitor : public QuicTransportStream::Visitor { + public: + UnidirectionalEchoWriteVisitor(QuicTransportStream* stream, + const std::string& data) + : stream_(stream), data_(data) {} + + void OnCanRead() override { QUIC_NOTREACHED(); } + void OnFinRead() override { QUIC_NOTREACHED(); } + void OnCanWrite() override { + if (data_.empty()) { + return; + } + if (!stream_->Write(data_)) { + return; + } + data_ = ""; + bool fin_sent = stream_->SendFin(); + DCHECK(fin_sent); + } + + private: + QuicTransportStream* stream_; + std::string data_; +}; + +} // namespace + +QuicTransportSimpleServerSession::QuicTransportSimpleServerSession( + QuicConnection* connection, + bool owns_connection, + Visitor* owner, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + Mode mode, + std::vector accepted_origins) + : QuicTransportServerSession(connection, + owner, + config, + supported_versions, + crypto_config, + compressed_certs_cache, + this), + connection_(connection), + owns_connection_(owns_connection), + mode_(mode), + accepted_origins_(accepted_origins) {} + +QuicTransportSimpleServerSession::~QuicTransportSimpleServerSession() { + if (owns_connection_) { + delete connection_; + } +} + +void QuicTransportSimpleServerSession::OnIncomingDataStream( + QuicTransportStream* stream) { + switch (mode_) { + case DISCARD: + stream->set_visitor(std::make_unique(stream)); + break; + + case ECHO: + switch (stream->type()) { + case BIDIRECTIONAL: + QUIC_DVLOG(1) << "Opening bidirectional echo stream " << stream->id(); + stream->set_visitor( + std::make_unique(stream)); + break; + case READ_UNIDIRECTIONAL: + QUIC_DVLOG(1) + << "Started receiving data on unidirectional echo stream " + << stream->id(); + stream->set_visitor( + std::make_unique(this, stream)); + break; + default: + QUIC_NOTREACHED(); + break; + } + break; + } +} + +void QuicTransportSimpleServerSession::OnCanCreateNewOutgoingStream( + bool unidirectional) { + if (mode_ == ECHO && unidirectional) { + MaybeEchoStreamsBack(); + } +} + +bool QuicTransportSimpleServerSession::CheckOrigin(url::Origin origin) { + if (accepted_origins_.empty()) { + return true; + } + + for (const url::Origin& accepted_origin : accepted_origins_) { + if (origin.IsSameOriginWith(accepted_origin)) { + return true; + } + } + return false; +} + +void QuicTransportSimpleServerSession::MaybeEchoStreamsBack() { + while (!streams_to_echo_back_.empty() && + CanOpenNextOutgoingUnidirectionalStream()) { + // Remove the stream from the queue first, in order to avoid accidentally + // entering an infinite loop in case any of the following code calls + // OnCanCreateNewOutgoingStream(). + std::string data = std::move(streams_to_echo_back_.front()); + streams_to_echo_back_.pop_front(); + + auto stream_owned = std::make_unique( + GetNextOutgoingUnidirectionalStreamId(), this, this); + QuicTransportStream* stream = stream_owned.get(); + ActivateStream(std::move(stream_owned)); + QUIC_DVLOG(1) << "Opened echo response stream " << stream->id(); + + stream->set_visitor( + std::make_unique(stream, data)); + stream->visitor()->OnCanWrite(); + } +} + +} // 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 new file mode 100644 index 00000000000..11f82f2d272 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h @@ -0,0 +1,72 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_SESSION_H_ +#define QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_SESSION_H_ + +#include +#include + +#include "url/origin.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h" +#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" + +namespace quic { + +// QuicTransport simple server is a non-production server that can be used for +// testing QuicTransport. It has two modes that can be changed using the +// command line flags, "echo" and "discard". +class QuicTransportSimpleServerSession + : public QuicTransportServerSession, + QuicTransportServerSession::ServerVisitor { + public: + enum Mode { + // In DISCARD mode, any data on incoming streams is discarded and no + // outgoing streams are initiated. + DISCARD, + // In ECHO mode, any data sent on a bidirectional stream is echoed back. + // Any data sent on a unidirectional stream is buffered, and echoed back on + // a server-initiated unidirectional stream that is sent as soon as a FIN is + // received on the incoming stream. + ECHO, + }; + + QuicTransportSimpleServerSession( + QuicConnection* connection, + bool owns_connection, + Visitor* owner, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + Mode mode, + std::vector accepted_origins); + ~QuicTransportSimpleServerSession(); + + void OnIncomingDataStream(QuicTransportStream* stream) override; + void OnCanCreateNewOutgoingStream(bool unidirectional) override; + bool CheckOrigin(url::Origin origin) override; + + void EchoStreamBack(const std::string& data) { + streams_to_echo_back_.push_back(data); + MaybeEchoStreamsBack(); + } + + private: + void MaybeEchoStreamsBack(); + + QuicConnection* connection_; + const bool owns_connection_; + Mode mode_; + std::vector accepted_origins_; + QuicDeque streams_to_echo_back_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_QUIC_TRANSPORT_SIMPLE_SERVER_SESSION_H_ -- cgit v1.2.1